From 8899e8d858d0e4740f9a339a40647ca6808202c1 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Wed, 26 Dec 2012 16:29:29 -0500 Subject: [PATCH 01/11] Updated image, SVG, and print exporters. Image export works well; SVG and print still need work. Added ability to run examples with a specific Qt graphics system --- examples/__main__.py | 15 +++-- examples/exampleLoaderTemplate.ui | 30 +++++++++ examples/exampleLoaderTemplate_pyqt.py | 18 ++++- examples/exampleLoaderTemplate_pyside.py | 20 +++++- examples/initExample.py | 12 +++- exporters/ImageExporter.py | 18 +++-- exporters/PrintExporter.py | 16 +++-- exporters/SVGExporter.py | 2 +- graphicsItems/ArrowItem.py | 5 ++ graphicsItems/GraphicsItem.py | 20 +++++- graphicsItems/PlotCurveItem.py | 12 +--- graphicsItems/ScatterPlotItem.py | 43 ++++++------ graphicsItems/TextItem.py | 83 +++++++++++------------- 13 files changed, 194 insertions(+), 100 deletions(-) diff --git a/examples/__main__.py b/examples/__main__.py index 6f4bf138..1dbe7b9a 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -126,6 +126,9 @@ class ExampleLoader(QtGui.QMainWindow): extra.append('pyqt') elif self.ui.pysideCheck.isChecked(): extra.append('pyside') + + if self.ui.forceGraphicsCheck.isChecked(): + extra.append(str(self.ui.forceGraphicsCombo.currentText())) if fn is None: return @@ -163,22 +166,26 @@ def buildFileList(examples, files=None): buildFileList(val, files) return files -def testFile(name, f, exe, lib): +def testFile(name, f, exe, lib, graphicsSystem): global path fn = os.path.join(path,f) #print "starting process: ", fn - + os.chdir(path) sys.stdout.write(name) sys.stdout.flush() + import1 = "import %s" % lib if lib != '' else '' + import2 = os.path.splitext(os.path.split(fn)[1])[0] + graphicsSystem = '' if graphicsSystem is None else "pg.QtGui.QApplication.setGraphicsSystem('%s')" % graphicsSystem code = """ try: + %s + import pyqtgraph as pg %s import %s import sys print("test complete") sys.stdout.flush() - import pyqtgraph as pg import time while True: ## run a little event loop pg.QtGui.QApplication.processEvents() @@ -187,7 +194,7 @@ except: print("test failed") raise -""" % ("import %s" % lib if lib != '' else "", os.path.splitext(os.path.split(fn)[1])[0]) +""" % (import1, import2, graphicsSystem) #print code process = subprocess.Popen(['exec %s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) process.stdin.write(code.encode('UTF-8')) diff --git a/examples/exampleLoaderTemplate.ui b/examples/exampleLoaderTemplate.ui index 1453240c..cd5ce921 100644 --- a/examples/exampleLoaderTemplate.ui +++ b/examples/exampleLoaderTemplate.ui @@ -57,6 +57,36 @@ + + + + + + Force Graphics System: + + + + + + + + native + + + + + raster + + + + + opengl + + + + + + diff --git a/examples/exampleLoaderTemplate_pyqt.py b/examples/exampleLoaderTemplate_pyqt.py index 26e55a44..f359cc32 100644 --- a/examples/exampleLoaderTemplate_pyqt.py +++ b/examples/exampleLoaderTemplate_pyqt.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' # -# Created: Fri Oct 26 07:53:55 2012 +# Created: Mon Dec 24 00:33:38 2012 # by: PyQt4 UI code generator 4.9.1 # # WARNING! All changes made in this file will be lost! @@ -44,6 +44,18 @@ class Ui_Form(object): self.pysideCheck.setObjectName(_fromUtf8("pysideCheck")) self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck.setObjectName(_fromUtf8("forceGraphicsCheck")) + self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) + self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo.setObjectName(_fromUtf8("forceGraphicsCombo")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.forceGraphicsCombo.addItem(_fromUtf8("")) + self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) + self.verticalLayout.addLayout(self.horizontalLayout_2) self.loadBtn = QtGui.QPushButton(self.layoutWidget) self.loadBtn.setObjectName(_fromUtf8("loadBtn")) self.verticalLayout.addWidget(self.loadBtn) @@ -62,5 +74,9 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) self.pyqtCheck.setText(QtGui.QApplication.translate("Form", "Force PyQt", None, QtGui.QApplication.UnicodeUTF8)) self.pysideCheck.setText(QtGui.QApplication.translate("Form", "Force PySide", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCheck.setText(QtGui.QApplication.translate("Form", "Force Graphics System:", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/exampleLoaderTemplate_pyside.py b/examples/exampleLoaderTemplate_pyside.py index a81f7299..113c1654 100644 --- a/examples/exampleLoaderTemplate_pyside.py +++ b/examples/exampleLoaderTemplate_pyside.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' # -# Created: Fri Oct 26 07:53:57 2012 -# by: pyside-uic 0.2.13 running on PySide 1.1.0 +# Created: Mon Dec 24 00:33:39 2012 +# by: pyside-uic 0.2.13 running on PySide 1.1.2 # # WARNING! All changes made in this file will be lost! @@ -39,6 +39,18 @@ class Ui_Form(object): self.pysideCheck.setObjectName("pysideCheck") self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck.setObjectName("forceGraphicsCheck") + self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) + self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo.setObjectName("forceGraphicsCombo") + self.forceGraphicsCombo.addItem("") + self.forceGraphicsCombo.addItem("") + self.forceGraphicsCombo.addItem("") + self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) + self.verticalLayout.addLayout(self.horizontalLayout_2) self.loadBtn = QtGui.QPushButton(self.layoutWidget) self.loadBtn.setObjectName("loadBtn") self.verticalLayout.addWidget(self.loadBtn) @@ -57,5 +69,9 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) self.pyqtCheck.setText(QtGui.QApplication.translate("Form", "Force PyQt", None, QtGui.QApplication.UnicodeUTF8)) self.pysideCheck.setText(QtGui.QApplication.translate("Form", "Force PySide", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCheck.setText(QtGui.QApplication.translate("Form", "Force Graphics System:", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) + self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/initExample.py b/examples/initExample.py index 1b38363b..908f5fb0 100644 --- a/examples/initExample.py +++ b/examples/initExample.py @@ -3,6 +3,14 @@ import sys, os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) if 'pyside' in sys.argv: ## should force example to use PySide instead of PyQt - import PySide + from PySide import QtGui elif 'pyqt' in sys.argv: - import PyQt4 + from PyQt4 import QtGui +else: + from pyqtgraph.Qt import QtGui + +for gs in ['raster', 'native', 'opengl']: + if gs in sys.argv: + QtGui.QApplication.setGraphicsSystem(gs) + break + diff --git a/exporters/ImageExporter.py b/exporters/ImageExporter.py index 763b615d..cb6cf396 100644 --- a/exporters/ImageExporter.py +++ b/exporters/ImageExporter.py @@ -27,12 +27,12 @@ class ImageExporter(Exporter): def widthChanged(self): sr = self.getSourceRect() - ar = sr.height() / sr.width() + ar = float(sr.height()) / sr.width() self.params.param('height').setValue(self.params['width'] * ar, blockSignal=self.heightChanged) def heightChanged(self): sr = self.getSourceRect() - ar = sr.width() / sr.height() + ar = float(sr.width()) / sr.height() self.params.param('width').setValue(self.params['height'] * ar, blockSignal=self.widthChanged) def parameters(self): @@ -51,6 +51,8 @@ class ImageExporter(Exporter): targetRect = QtCore.QRect(0, 0, self.params['width'], self.params['height']) sourceRect = self.getSourceRect() + + #self.png = QtGui.QImage(targetRect.size(), QtGui.QImage.Format_ARGB32) #self.png.fill(pyqtgraph.mkColor(self.params['background'])) bg = np.empty((self.params['width'], self.params['height'], 4), dtype=np.ubyte) @@ -60,11 +62,19 @@ class ImageExporter(Exporter): bg[:,:,2] = color.red() bg[:,:,3] = color.alpha() self.png = pg.makeQImage(bg, alpha=True) + + ## set resolution of image: + origTargetRect = self.getTargetRect() + resolutionScale = targetRect.width() / origTargetRect.width() + #self.png.setDotsPerMeterX(self.png.dotsPerMeterX() * resolutionScale) + #self.png.setDotsPerMeterY(self.png.dotsPerMeterY() * resolutionScale) + painter = QtGui.QPainter(self.png) + #dtr = painter.deviceTransform() try: - self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background']}) + self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background'], 'painter': painter, 'resolutionScale': resolutionScale}) painter.setRenderHint(QtGui.QPainter.Antialiasing, self.params['antialias']) - self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect) + self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect)) finally: self.setExportMode(False) painter.end() diff --git a/exporters/PrintExporter.py b/exporters/PrintExporter.py index 4a47af2e..5b31b45d 100644 --- a/exporters/PrintExporter.py +++ b/exporters/PrintExporter.py @@ -3,8 +3,8 @@ from pyqtgraph.parametertree import Parameter from pyqtgraph.Qt import QtGui, QtCore, QtSvg import re -#__all__ = ['PrintExporter'] -__all__ = [] ## Printer is disabled for now--does not work very well. +__all__ = ['PrintExporter'] +#__all__ = [] ## Printer is disabled for now--does not work very well. class PrintExporter(Exporter): Name = "Printer" @@ -38,9 +38,15 @@ class PrintExporter(Exporter): if dialog.exec_() != QtGui.QDialog.Accepted: return; + #dpi = QtGui.QDesktopWidget().physicalDpiX() + #self.svg.setSize(QtCore.QSize(100,100)) #self.svg.setResolution(600) - res = printer.resolution() + #res = printer.resolution() + sr = self.getSourceRect() + #res = sr.width() * .4 / (self.params['width'] * 100 / 2.54) + res = QtGui.QDesktopWidget().physicalDpiX() + printer.setResolution(res) rect = printer.pageRect() center = rect.center() h = self.params['height'] * res * 100. / 2.54 @@ -52,8 +58,8 @@ class PrintExporter(Exporter): sourceRect = self.getSourceRect() painter = QtGui.QPainter(printer) try: - self.setExportMode(True) - self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect) + self.setExportMode(True, {'painter': painter}) + self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect)) finally: self.setExportMode(False) painter.end() diff --git a/exporters/SVGExporter.py b/exporters/SVGExporter.py index 2d040282..134330d4 100644 --- a/exporters/SVGExporter.py +++ b/exporters/SVGExporter.py @@ -46,7 +46,7 @@ class SVGExporter(Exporter): painter = QtGui.QPainter(self.svg) try: - self.setExportMode(True) + self.setExportMode(True, {'painter': painter,}) self.render(painter, QtCore.QRectF(targetRect), sourceRect) finally: self.setExportMode(False) diff --git a/graphicsItems/ArrowItem.py b/graphicsItems/ArrowItem.py index 153ea712..22d0065b 100644 --- a/graphicsItems/ArrowItem.py +++ b/graphicsItems/ArrowItem.py @@ -54,3 +54,8 @@ class ArrowItem(QtGui.QGraphicsPathItem): def paint(self, p, *args): p.setRenderHint(QtGui.QPainter.Antialiasing) QtGui.QGraphicsPathItem.paint(self, p, *args) + + def shape(self): + #if not self.opts['pxMode']: + #return QtGui.QGraphicsPathItem.shape(self) + return self.path \ No newline at end of file diff --git a/graphicsItems/GraphicsItem.py b/graphicsItems/GraphicsItem.py index 43b8148c..d3021b75 100644 --- a/graphicsItems/GraphicsItem.py +++ b/graphicsItems/GraphicsItem.py @@ -28,10 +28,13 @@ class GraphicsItem(object): self._viewWidget = None self._viewBox = None self._connectedView = None + self._exportOpts = False ## If False, not currently exporting. Otherwise, contains dict of export options. if register: GraphicsScene.registerObject(self) ## workaround for pyqt bug in graphicsscene.items() - + + + def getViewWidget(self): """ Return the view widget for this item. If the scene has multiple views, only the first view is returned. @@ -82,6 +85,9 @@ class GraphicsItem(object): Return the transform that converts local item coordinates to device coordinates (usually pixels). Extends deviceTransform to automatically determine the viewportTransform. """ + if self._exportOpts is not False and 'painter' in self._exportOpts: ## currently exporting; device transform may be different. + return self._exportOpts['painter'].deviceTransform() + if viewportTransform is None: view = self.getViewWidget() if view is None: @@ -476,4 +482,16 @@ class GraphicsItem(object): return tree + def setExportMode(self, export, opts): + """ + This method is called by exporters to inform items that they are being drawn for export + with a specific set of options. Items access these via self._exportOptions. + When exporting is complete, _exportOptions is set to False. + """ + if export: + self._exportOpts = opts + #if 'antialias' not in opts: + #self._exportOpts['antialias'] = True + else: + self._exportOpts = False \ No newline at end of file diff --git a/graphicsItems/PlotCurveItem.py b/graphicsItems/PlotCurveItem.py index c49ce30b..dbbeb077 100644 --- a/graphicsItems/PlotCurveItem.py +++ b/graphicsItems/PlotCurveItem.py @@ -52,7 +52,6 @@ class PlotCurveItem(GraphicsObject): self.clear() self.path = None self.fillPath = None - self.exportOpts = False ## this is disastrous for performance. @@ -404,8 +403,8 @@ class PlotCurveItem(GraphicsObject): path = self.path prof.mark('generate path') - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] + if self._exportOpts is not False: + aa = self._exportOpts.get('antialias', True) else: aa = self.opts['antialias'] @@ -487,13 +486,6 @@ class PlotCurveItem(GraphicsObject): ev.accept() self.sigClicked.emit(self) - def setExportMode(self, export, opts): - if export: - self.exportOpts = opts - if 'antialias' not in opts: - self.exportOpts['antialias'] = True - else: - self.exportOpts = False class ROIPlotItem(PlotCurveItem): """Plot curve that monitors an ROI and image for changes to automatically replot.""" diff --git a/graphicsItems/ScatterPlotItem.py b/graphicsItems/ScatterPlotItem.py index 2528d35b..2e41cb7c 100644 --- a/graphicsItems/ScatterPlotItem.py +++ b/graphicsItems/ScatterPlotItem.py @@ -239,7 +239,6 @@ class ScatterPlotItem(GraphicsObject): 'useCache': True, ## If useCache is False, symbols are re-drawn on every paint. 'antialias': pg.getConfigOption('antialias'), } - self.exportOpts = False self.setPen(200,200,200, update=False) self.setBrush(100,100,150, update=False) @@ -546,7 +545,7 @@ class ScatterPlotItem(GraphicsObject): if invalidate: self.invalidate() - def getSpotOpts(self, recs): + def getSpotOpts(self, recs, scale=1.0): if recs.ndim == 0: rec = recs symbol = rec['symbol'] @@ -561,11 +560,12 @@ class ScatterPlotItem(GraphicsObject): brush = rec['brush'] if brush is None: brush = self.opts['brush'] - return (symbol, size, fn.mkPen(pen), fn.mkBrush(brush)) + return (symbol, size*scale, fn.mkPen(pen), fn.mkBrush(brush)) else: recs = recs.copy() recs['symbol'][np.equal(recs['symbol'], None)] = self.opts['symbol'] recs['size'][np.equal(recs['size'], -1)] = self.opts['size'] + recs['size'] *= scale recs['pen'][np.equal(recs['pen'], None)] = fn.mkPen(self.opts['pen']) recs['brush'][np.equal(recs['brush'], None)] = fn.mkBrush(self.opts['brush']) return recs @@ -675,18 +675,20 @@ class ScatterPlotItem(GraphicsObject): rect = QtCore.QRectF(y, x, h, w) self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect)) - def setExportMode(self, export, opts): - if export: - self.exportOpts = opts - if 'antialias' not in opts: - self.exportOpts['antialias'] = True - else: - self.exportOpts = False - + def setExportMode(self, *args, **kwds): + GraphicsObject.setExportMode(self, *args, **kwds) + self.invalidate() def paint(self, p, *args): #p.setPen(fn.mkPen('r')) #p.drawRect(self.boundingRect()) + if self._exportOpts is not False: + aa = self._exportOpts.get('antialias', True) + scale = self._exportOpts.get('resolutionScale', 1.0) ## exporting to image; pixel resolution may have changed + else: + aa = self.opts['antialias'] + scale = 1.0 + if self.opts['pxMode'] is True: atlas = self.fragmentAtlas.getAtlas() #arr = fn.imageToArray(atlas.toImage(), copy=True) @@ -701,13 +703,9 @@ class ScatterPlotItem(GraphicsObject): p.resetTransform() - if not USE_PYSIDE and self.opts['useCache'] and self.exportOpts is False: + if not USE_PYSIDE and self.opts['useCache'] and self._exportOpts is False: p.drawPixmapFragments(self.fragments, atlas) else: - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] - else: - aa = self.opts['antialias'] p.setRenderHint(p.Antialiasing, aa) for i in range(len(self.data)): @@ -715,23 +713,20 @@ class ScatterPlotItem(GraphicsObject): frag = self.fragments[i] p.resetTransform() p.translate(frag.x, frag.y) - drawSymbol(p, *self.getSpotOpts(rec)) + drawSymbol(p, *self.getSpotOpts(rec, scale)) else: if self.picture is None: self.picture = QtGui.QPicture() p2 = QtGui.QPainter(self.picture) for rec in self.data: - + if scale != 1.0: + rec = rec.copy() + rec['size'] *= scale p2.resetTransform() p2.translate(rec['x'], rec['y']) - drawSymbol(p2, *self.getSpotOpts(rec)) + drawSymbol(p2, *self.getSpotOpts(rec, scale)) p2.end() - if self.exportOpts is not False: - aa = self.exportOpts['antialias'] - else: - aa = self.opts['antialias'] - p.setRenderHint(p.Antialiasing, aa) self.picture.play(p) diff --git a/graphicsItems/TextItem.py b/graphicsItems/TextItem.py index a85e919d..b5666f6e 100644 --- a/graphicsItems/TextItem.py +++ b/graphicsItems/TextItem.py @@ -27,25 +27,27 @@ class TextItem(UIGraphicsItem): #*angle* Angle in degrees to rotate text (note that the rotation assigned in this item's #transformation will be ignored) - + self.anchor = pg.Point(anchor) + #self.angle = 0 UIGraphicsItem.__init__(self) self.textItem = QtGui.QGraphicsTextItem() + self.textItem.setParentItem(self) self.lastTransform = None self._bounds = QtCore.QRectF() if html is None: self.setText(text, color) else: self.setHtml(html) - self.anchor = pg.Point(anchor) self.fill = pg.mkBrush(fill) self.border = pg.mkPen(border) - self.angle = angle - #self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport + self.rotate(angle) + self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport def setText(self, text, color=(200,200,200)): color = pg.mkColor(color) self.textItem.setDefaultTextColor(color) self.textItem.setPlainText(text) + self.updateText() #html = '%s' % (color, text) #self.setHtml(html) @@ -70,38 +72,41 @@ class TextItem(UIGraphicsItem): self.textItem.setFont(*args) self.updateText() - def updateText(self): - self.viewRangeChanged() - - #def getImage(self): - #if self.img is None: - #br = self.textItem.boundingRect() - #img = QtGui.QImage(int(br.width()), int(br.height()), QtGui.QImage.Format_ARGB32) - #p = QtGui.QPainter(img) - #self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) - #p.end() - #self.img = img - #return self.img + #def setAngle(self, angle): + #self.angle = angle + #self.updateText() - def textBoundingRect(self): - ## return the bounds of the text box in device coordinates - pos = self.mapToDevice(QtCore.QPointF(0,0)) - if pos is None: - return None - tbr = self.textItem.boundingRect() - return QtCore.QRectF(pos.x() - tbr.width()*self.anchor.x(), pos.y() - tbr.height()*self.anchor.y(), tbr.width(), tbr.height()) + + def updateText(self): + + ## Needed to maintain font size when rendering to image with increased resolution + self.textItem.resetTransform() + #self.textItem.rotate(self.angle) + if self._exportOpts is not False and 'resolutionScale' in self._exportOpts: + s = self._exportOpts['resolutionScale'] + self.textItem.scale(s, s) + + #br = self.textItem.mapRectToParent(self.textItem.boundingRect()) + self.textItem.setPos(0,0) + br = self.textItem.boundingRect() + apos = self.textItem.mapToParent(pg.Point(br.width()*self.anchor.x(), br.height()*self.anchor.y())) + #print br, apos + self.textItem.setPos(-apos.x(), -apos.y()) + + #def textBoundingRect(self): + ### return the bounds of the text box in device coordinates + #pos = self.mapToDevice(QtCore.QPointF(0,0)) + #if pos is None: + #return None + #tbr = self.textItem.boundingRect() + #return QtCore.QRectF(pos.x() - tbr.width()*self.anchor.x(), pos.y() - tbr.height()*self.anchor.y(), tbr.width(), tbr.height()) def viewRangeChanged(self): - br = self.textBoundingRect() - if br is None: - return - self.prepareGeometryChange() - self._bounds = fn.invertQTransform(self.deviceTransform()).mapRect(br) - #print self._bounds + self.updateText() def boundingRect(self): - return self._bounds + return self.textItem.mapToParent(self.textItem.boundingRect()).boundingRect() def paint(self, p, *args): tr = p.transform() @@ -110,23 +115,9 @@ class TextItem(UIGraphicsItem): self.viewRangeChanged() self.lastTransform = tr - - tbr = self.textBoundingRect() - - #p.setPen(pg.mkPen('r')) - #p.drawRect(self.boundingRect()) - p.setPen(self.border) p.setBrush(self.fill) + p.setRenderHint(p.Antialiasing, True) + p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) - - #p.fillRect(tbr) - p.resetTransform() - #p.drawRect(tbr) - - - p.translate(tbr.left(), tbr.top()) - p.rotate(self.angle) - p.drawRect(QtCore.QRectF(0, 0, tbr.width(), tbr.height())) - self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None) \ No newline at end of file From 6931eacffd2809abc74d30e4fae59151ce5088f6 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Wed, 26 Dec 2012 21:02:36 -0500 Subject: [PATCH 02/11] Fixed doc build to work with new package structure. --- doc/source/conf.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 2fd718e4..97d4b35c 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,8 +17,7 @@ import sys, os # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. path = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(path, '..', '..', '..')) -print sys.path +sys.path.insert(0, os.path.join(path, '..', '..')) # -- General configuration ----------------------------------------------------- From 19d7bc56054a3c29c1a18f281e41e83896721ab8 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 27 Dec 2012 04:35:23 +0000 Subject: [PATCH 03/11] bugfixes for new package structure --- examples/initExample.py | 6 +++--- setup.py | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/initExample.py b/examples/initExample.py index f95a0cb0..38dd3edc 100644 --- a/examples/initExample.py +++ b/examples/initExample.py @@ -2,10 +2,10 @@ import sys, os path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) path.rstrip(os.path.sep) -if path.endswith('pyqtgraph'): - sys.path.insert(0, os.path.join(path, '..')) ## examples installed inside pyqtgraph package -elif 'pyqtgraph' in os.listdir(path): +if 'pyqtgraph' in os.listdir(path): sys.path.insert(0, path) ## examples adjacent to pyqtgraph (as in source) +elif path.endswith('pyqtgraph'): + sys.path.insert(0, os.path.abspath(os.path.join(path, '..'))) ## examples installed inside pyqtgraph package ## should force example to use PySide instead of PyQt if 'pyside' in sys.argv: diff --git a/setup.py b/setup.py index e4dc07cf..64d22ba2 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,19 @@ from distutils.core import setup +import distutils.dir_util import os ## generate list of all sub-packages -subdirs = [i[0].split(os.path.sep)[1:] for i in os.walk('./pyqtgraph') if '__init__.py' in i[2]] -subdirs = filter(lambda p: len(p) == 1 or p[1] != 'build', subdirs) +path = os.path.abspath(os.path.dirname(__file__)) +n = len(path.split(os.path.sep)) +subdirs = [i[0].split(os.path.sep)[n:] for i in os.walk(os.path.join(path, 'pyqtgraph')) if '__init__.py' in i[2]] all_packages = ['.'.join(p) for p in subdirs] + ['pyqtgraph.examples'] + +## Make sure build directory is clean before installing +buildPath = os.path.join(path, 'build') +if os.path.isdir(buildPath): + distutils.dir_util.remove_tree(buildPath) + setup(name='pyqtgraph', version='', description='Scientific Graphics and GUI Library for Python', @@ -23,6 +31,9 @@ It is intended for use in mathematics / scientific / engineering applications. D #package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']}, classifiers = [ "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Development Status :: 4 - Beta", "Environment :: Other Environment", From 7f51813c2c0a101f1783a4af4acadb587b95e556 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Thu, 27 Dec 2012 01:52:32 -0500 Subject: [PATCH 04/11] Added MANIFEST.in for generating cleaner source distributions updated versioning system --- MANIFEST.in | 7 +++++++ pyqtgraph/__init__.py | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..fb08e7e5 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +recursive-include pyqtgraph *.py *.ui *.m README *.txt +recursive-include tests *.py *.ui +recursive-include examples *.py *.ui +recursive-include doc *.rst *.py *.svg *.png *.jpg +recursive-include doc/build/html * +include doc/Makefile doc/make.bat + diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 6e950770..93d9f7b8 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -1,5 +1,10 @@ # -*- coding: utf-8 -*- -REVISION = None +""" +PyQtGraph - Scientific Graphics and GUI Library for Python +www.pyqtgraph.org +""" + +__version__ = None ### import all the goodies and add some helper functions for easy CLI use @@ -63,19 +68,21 @@ def systemInfo(): from .Qt import VERSION_INFO print("qt bindings: %s" % VERSION_INFO) - global REVISION - if REVISION is None: ## this code was probably checked out from bzr; look up the last-revision file - lastRevFile = os.path.join(os.path.dirname(__file__), '.bzr', 'branch', 'last-revision') + global __version__ + rev = None + if __version__ is None: ## this code was probably checked out from bzr; look up the last-revision file + lastRevFile = os.path.join(os.path.dirname(__file__), '..', '.bzr', 'branch', 'last-revision') if os.path.exists(lastRevFile): - REVISION = open(lastRevFile, 'r').read().strip() + rev = open(lastRevFile, 'r').read().strip() - print("pyqtgraph: %s" % REVISION) + print("pyqtgraph: %s; %s" % (__version__, rev)) print("config:") import pprint pprint.pprint(CONFIG_OPTIONS) ## Rename orphaned .pyc files. This is *probably* safe :) - +## We only do this if __version__ is None, indicating the code was probably pulled +## from the repository. def renamePyc(startDir): ### Used to rename orphaned .pyc files ### When a python file changes its location in the repository, usually the .pyc file @@ -108,9 +115,8 @@ def renamePyc(startDir): print(" " + name2) os.rename(fileName, name2) -import os path = os.path.split(__file__)[0] -if not hasattr(sys, 'frozen'): ## If we are frozen, there's a good chance we don't have the original .py files anymore. +if __version__ is None and not hasattr(sys, 'frozen') and sys.version_info[0] == 2: ## If we are frozen, there's a good chance we don't have the original .py files anymore. renamePyc(path) From 000354ac2189078bf3dff3f3dfc01e8fd6fda975 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Thu, 27 Dec 2012 02:21:34 -0500 Subject: [PATCH 05/11] Fixed documentation version numbers --- doc/source/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 97d4b35c..236cb807 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -49,9 +49,9 @@ copyright = '2011, Luke Campagnola' # built documents. # # The short X.Y version. -version = '1.8' +version = '' # The full version, including alpha/beta/rc tags. -release = '1.8' +release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From b9822b1d10e2820cb4a62cf47869130b1eeb4def Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Thu, 27 Dec 2012 03:13:35 -0500 Subject: [PATCH 06/11] Fixed doc version (again) Added debian control files --- doc/source/conf.py | 4 ++-- doc/source/index.rst | 4 ++-- pyqtgraph/__init__.py | 2 +- setup.py | 2 +- tools/DEBIAN/control | 13 +++++++++++++ tools/DEBIAN/postrm | 2 ++ 6 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 tools/DEBIAN/control create mode 100755 tools/DEBIAN/postrm diff --git a/doc/source/conf.py b/doc/source/conf.py index 236cb807..4a275cd1 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -49,9 +49,9 @@ copyright = '2011, Luke Campagnola' # built documents. # # The short X.Y version. -version = '' +version = '0.9.0' # The full version, including alpha/beta/rc tags. -release = '' +release = '0.9.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/index.rst b/doc/source/index.rst index 5d606061..cc89f3d8 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,8 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to the documentation for pyqtgraph 1.8 -============================================== +Welcome to the documentation for pyqtgraph +========================================== Contents: diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 93d9f7b8..2998be79 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -4,7 +4,7 @@ PyQtGraph - Scientific Graphics and GUI Library for Python www.pyqtgraph.org """ -__version__ = None +__version__ = '0.9.0' ### import all the goodies and add some helper functions for easy CLI use diff --git a/setup.py b/setup.py index 64d22ba2..5b608eda 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ if os.path.isdir(buildPath): distutils.dir_util.remove_tree(buildPath) setup(name='pyqtgraph', - version='', + version='0.9.0', description='Scientific Graphics and GUI Library for Python', long_description="""\ PyQtGraph is a pure-python graphics and GUI library built on PyQt4/PySide and numpy. diff --git a/tools/DEBIAN/control b/tools/DEBIAN/control new file mode 100644 index 00000000..d7c74bc7 --- /dev/null +++ b/tools/DEBIAN/control @@ -0,0 +1,13 @@ +Package: python-pyqtgraph +Version: 0.9.0 +Section: python +Priority: optional +Architecture: all +Essential: no +Installed-Size: 5048 +Maintainer: Luke Campagnola +Homepage: http://luke.campagnola.me/code/pyqtgraph +Depends: python (>= 2.6), python-qt4 | python-pyside, python-scipy, python-numpy +Suggests: python-opengl, python-qt4-gl +Description: Scientific Graphics and GUI Library for Python + PyQtGraph is a pure-python graphics and GUI library built on PyQt4 and numpy. It is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is very fast due to its heavy leverage of numpy for number crunching and Qt's GraphicsView framework for fast display. diff --git a/tools/DEBIAN/postrm b/tools/DEBIAN/postrm new file mode 100755 index 00000000..35a4685c --- /dev/null +++ b/tools/DEBIAN/postrm @@ -0,0 +1,2 @@ +#!/bin/sh +rm -rf /usr/lib/python2.7/dist-packages/pyqtgraph From 87ea160a2360aac41a48f1218554a163cff25171 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 27 Dec 2012 10:31:08 -0500 Subject: [PATCH 07/11] Correction to setup.py - use install_requires to inform pip of dependencies. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5b608eda..8833b1d8 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ It is intended for use in mathematics / scientific / engineering applications. D "Topic :: Scientific/Engineering :: Visualization", "Topic :: Software Development :: User Interfaces", ], - requires = [ + install_requires = [ 'numpy', 'scipy', ], From 8d5e24c8fdb46e14f496d6d136a8d044eea7ef53 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Thu, 27 Dec 2012 11:53:22 -0500 Subject: [PATCH 08/11] Removed incorrect version numbers --- doc/source/conf.py | 4 ++-- pyqtgraph/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 4a275cd1..236cb807 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -49,9 +49,9 @@ copyright = '2011, Luke Campagnola' # built documents. # # The short X.Y version. -version = '0.9.0' +version = '' # The full version, including alpha/beta/rc tags. -release = '0.9.0' +release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 2998be79..93d9f7b8 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -4,7 +4,7 @@ PyQtGraph - Scientific Graphics and GUI Library for Python www.pyqtgraph.org """ -__version__ = '0.9.0' +__version__ = None ### import all the goodies and add some helper functions for easy CLI use diff --git a/setup.py b/setup.py index 8833b1d8..8128a851 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ if os.path.isdir(buildPath): distutils.dir_util.remove_tree(buildPath) setup(name='pyqtgraph', - version='0.9.0', + version='', description='Scientific Graphics and GUI Library for Python', long_description="""\ PyQtGraph is a pure-python graphics and GUI library built on PyQt4/PySide and numpy. From f32a04a43314af335538930ce565be01bcfea345 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Fri, 28 Dec 2012 16:23:28 -0500 Subject: [PATCH 09/11] SVG export fixes: - unicode support for text objects - always export in scene coordinates with offset from root item --- pyqtgraph/exporters/SVGExporter.py | 37 ++++++++++++++++++++--------- pyqtgraph/graphicsItems/TextItem.py | 9 +++---- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index ce05b82d..321c311f 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -83,7 +83,7 @@ class SVGExporter(Exporter): return bytes(xml) else: with open(fileName, 'w') as fh: - fh.write(xml) + fh.write(xml.encode('UTF-8')) xmlHeader = """\ @@ -171,8 +171,16 @@ def _generateItemSvg(item, nodes=None, root=None): doc = xml.parseString(xmlStr) else: childs = item.childItems() - tr = itemTransform(item, root) + tr = itemTransform(item, item.scene()) + ## offset to corner of root item + if isinstance(root, QtGui.QGraphicsScene): + rootPos = QtCore.QPoint(0,0) + else: + rootPos = root.scenePos() + tr2 = QtGui.QTransform() + tr2.translate(-rootPos.x(), -rootPos.y()) + tr = tr * tr2 #print item, pg.SRTTransform(tr) #tr.translate(item.pos().x(), item.pos().y()) @@ -239,17 +247,23 @@ def _generateItemSvg(item, nodes=None, root=None): nodes[name] = g1 g1.setAttribute('id', name) - ## If this item clips its children, we need to take car of that. + ## If this item clips its children, we need to take care of that. childGroup = g1 ## add children directly to this node unless we are clipping if not isinstance(item, QtGui.QGraphicsScene): ## See if this item clips its children if int(item.flags() & item.ItemClipsChildrenToShape) > 0: ## Generate svg for just the path - if isinstance(root, QtGui.QGraphicsScene): - path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) - else: - path = QtGui.QGraphicsPathItem(root.mapToParent(item.mapToItem(root, item.shape()))) - pathNode = _generateItemSvg(path, root=root).getElementsByTagName('path')[0] + #if isinstance(root, QtGui.QGraphicsScene): + #path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) + #else: + #path = QtGui.QGraphicsPathItem(root.mapToParent(item.mapToItem(root, item.shape()))) + path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) + item.scene().addItem(path) + try: + pathNode = _generateItemSvg(path, root=root).getElementsByTagName('path')[0] + finally: + item.scene().removeItem(path) + ## and for the clipPath element clip = name + '_clip' clipNode = g1.ownerDocument.createElement('clipPath') @@ -294,7 +308,10 @@ def correctCoordinates(node, item): elif ch.tagName == 'path': removeTransform = True newCoords = '' - for c in ch.getAttribute('d').strip().split(' '): + oldCoords = ch.getAttribute('d').strip() + if oldCoords == '': + continue + for c in oldCoords.split(' '): x,y = c.split(',') if x[0].isalpha(): t = x[0] @@ -317,8 +334,6 @@ def correctCoordinates(node, item): #fs = c[1]-c[2] #fs = (fs**2).sum()**0.5 #ch.setAttribute('font-size', str(fs)) - else: - print('warning: export not implemented for SVG tag %s (from item %s)' % (ch.tagName, item)) ## correct line widths if needed if removeTransform and ch.getAttribute('vector-effect') != 'non-scaling-stroke': diff --git a/pyqtgraph/graphicsItems/TextItem.py b/pyqtgraph/graphicsItems/TextItem.py index b5666f6e..911057f4 100644 --- a/pyqtgraph/graphicsItems/TextItem.py +++ b/pyqtgraph/graphicsItems/TextItem.py @@ -115,9 +115,10 @@ class TextItem(UIGraphicsItem): self.viewRangeChanged() self.lastTransform = tr - p.setPen(self.border) - p.setBrush(self.fill) - p.setRenderHint(p.Antialiasing, True) - p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) + if self.border.style() != QtCore.Qt.NoPen or self.fill.style() != QtCore.Qt.NoBrush: + p.setPen(self.border) + p.setBrush(self.fill) + p.setRenderHint(p.Antialiasing, True) + p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) \ No newline at end of file From b0030e1a49ca06509960d40f0bb2b8a7a50cabca Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Sat, 29 Dec 2012 02:35:45 -0500 Subject: [PATCH 10/11] Bugfixes: - Fixed RuntimeError when clearing items from ViewBox - SVG exporter adds generic font-family names to text items --- pyqtgraph/exporters/SVGExporter.py | 15 +++++++++++++++ pyqtgraph/graphicsItems/GraphicsItem.py | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index 321c311f..70f1f632 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -17,6 +17,9 @@ class SVGExporter(Exporter): self.params = Parameter(name='params', type='group', children=[ #{'name': 'width', 'type': 'float', 'value': tr.width(), 'limits': (0, None)}, #{'name': 'height', 'type': 'float', 'value': tr.height(), 'limits': (0, None)}, + #{'name': 'viewbox clipping', 'type': 'bool', 'value': True}, + #{'name': 'normalize coordinates', 'type': 'bool', 'value': True}, + #{'name': 'normalize line width', 'type': 'bool', 'value': True}, ]) #self.params.param('width').sigValueChanged.connect(self.widthChanged) #self.params.param('height').sigValueChanged.connect(self.heightChanged) @@ -335,6 +338,18 @@ def correctCoordinates(node, item): #fs = (fs**2).sum()**0.5 #ch.setAttribute('font-size', str(fs)) + ## Correct some font information + families = ch.getAttribute('font-family').split(',') + if len(families) == 1: + font = QtGui.QFont(families[0].strip('" ')) + if font.style() == font.SansSerif: + families.append('sans-serif') + elif font.style() == font.Serif: + families.append('serif') + elif font.style() == font.Courier: + families.append('monospace') + ch.setAttribute('font-family', ', '.join([f if ' ' not in f else '"%s"'%f for f in families])) + ## correct line widths if needed if removeTransform and ch.getAttribute('vector-effect') != 'non-scaling-stroke': w = float(grp.getAttribute('stroke-width')) diff --git a/pyqtgraph/graphicsItems/GraphicsItem.py b/pyqtgraph/graphicsItems/GraphicsItem.py index 34fd4bd7..2018fb4c 100644 --- a/pyqtgraph/graphicsItems/GraphicsItem.py +++ b/pyqtgraph/graphicsItems/GraphicsItem.py @@ -63,7 +63,10 @@ class GraphicsItem(object): if self._viewBox is None: p = self while True: - p = p.parentItem() + try: + p = p.parentItem() + except RuntimeError: ## sometimes happens as items are being removed from a scene and collected. + return None if p is None: vb = self.getViewWidget() if vb is None: From 927f032f19ed8e24126a2bbca0413c6c81b9cabb Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Sat, 29 Dec 2012 01:40:41 -0500 Subject: [PATCH 11/11] MANIFEST.in includes some missing files: tools, README, LICENSE updated debian control structure for building source packages --- MANIFEST.in | 3 ++- tools/DEBIAN/control | 13 ------------- tools/debian/changelog | 5 +++++ tools/debian/compat | 1 + tools/debian/control | 18 ++++++++++++++++++ tools/debian/copyright | 10 ++++++++++ tools/debian/files | 1 + tools/{DEBIAN => debian}/postrm | 3 ++- tools/debian/rules | 4 ++++ tools/debian/source/format | 1 + 10 files changed, 44 insertions(+), 15 deletions(-) delete mode 100644 tools/DEBIAN/control create mode 100644 tools/debian/changelog create mode 100644 tools/debian/compat create mode 100644 tools/debian/control create mode 100644 tools/debian/copyright create mode 100644 tools/debian/files rename tools/{DEBIAN => debian}/postrm (66%) create mode 100755 tools/debian/rules create mode 100644 tools/debian/source/format diff --git a/MANIFEST.in b/MANIFEST.in index fb08e7e5..02d67f6f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,5 +3,6 @@ recursive-include tests *.py *.ui recursive-include examples *.py *.ui recursive-include doc *.rst *.py *.svg *.png *.jpg recursive-include doc/build/html * -include doc/Makefile doc/make.bat +recursive-include tools * +include doc/Makefile doc/make.bat README.txt LICENSE.txt diff --git a/tools/DEBIAN/control b/tools/DEBIAN/control deleted file mode 100644 index d7c74bc7..00000000 --- a/tools/DEBIAN/control +++ /dev/null @@ -1,13 +0,0 @@ -Package: python-pyqtgraph -Version: 0.9.0 -Section: python -Priority: optional -Architecture: all -Essential: no -Installed-Size: 5048 -Maintainer: Luke Campagnola -Homepage: http://luke.campagnola.me/code/pyqtgraph -Depends: python (>= 2.6), python-qt4 | python-pyside, python-scipy, python-numpy -Suggests: python-opengl, python-qt4-gl -Description: Scientific Graphics and GUI Library for Python - PyQtGraph is a pure-python graphics and GUI library built on PyQt4 and numpy. It is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is very fast due to its heavy leverage of numpy for number crunching and Qt's GraphicsView framework for fast display. diff --git a/tools/debian/changelog b/tools/debian/changelog new file mode 100644 index 00000000..1edf45f3 --- /dev/null +++ b/tools/debian/changelog @@ -0,0 +1,5 @@ +python-pyqtgraph (0.9.1-1) UNRELEASED; urgency=low + + * Initial release. + + -- Luke Sat, 29 Dec 2012 01:07:23 -0500 diff --git a/tools/debian/compat b/tools/debian/compat new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/tools/debian/compat @@ -0,0 +1 @@ +8 diff --git a/tools/debian/control b/tools/debian/control new file mode 100644 index 00000000..7ab6f28a --- /dev/null +++ b/tools/debian/control @@ -0,0 +1,18 @@ +Source: python-pyqtgraph +Maintainer: Luke Campagnola +Section: python +Priority: optional +Standards-Version: 3.9.3 +Build-Depends: debhelper (>= 8) + +Package: python-pyqtgraph +Architecture: all +Homepage: http://luke.campagnola.me/code/pyqtgraph +Depends: python (>= 2.6), python-support (>= 0.90), python-qt4 | python-pyside, python-scipy, python-numpy, ${misc:Depends} +Suggests: python-opengl, python-qt4-gl +Description: Scientific Graphics and GUI Library for Python + PyQtGraph is a pure-python graphics and GUI library built on PyQt4 and numpy. + It is intended for use in mathematics / scientific / engineering applications. + Despite being written entirely in python, the library is very fast due to its + heavy leverage of numpy for number crunching and Qt's GraphicsView framework + for fast display. diff --git a/tools/debian/copyright b/tools/debian/copyright new file mode 100644 index 00000000..22791ae3 --- /dev/null +++ b/tools/debian/copyright @@ -0,0 +1,10 @@ +Copyright (c) 2012 University of North Carolina at Chapel Hill +Luke Campagnola ('luke.campagnola@%s.com' % 'gmail') + +The MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/tools/debian/files b/tools/debian/files new file mode 100644 index 00000000..4af05533 --- /dev/null +++ b/tools/debian/files @@ -0,0 +1 @@ +python-pyqtgraph_0.9.1-1_all.deb python optional diff --git a/tools/DEBIAN/postrm b/tools/debian/postrm similarity index 66% rename from tools/DEBIAN/postrm rename to tools/debian/postrm index 35a4685c..e1eae9f2 100755 --- a/tools/DEBIAN/postrm +++ b/tools/debian/postrm @@ -1,2 +1,3 @@ -#!/bin/sh +#!/bin/sh -e +#DEBHELPER# rm -rf /usr/lib/python2.7/dist-packages/pyqtgraph diff --git a/tools/debian/rules b/tools/debian/rules new file mode 100755 index 00000000..2d33f6ac --- /dev/null +++ b/tools/debian/rules @@ -0,0 +1,4 @@ +#!/usr/bin/make -f + +%: + dh $@ diff --git a/tools/debian/source/format b/tools/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/tools/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt)