From 82b666e2ee0e5c9ae4bd8aca37f2ae5fda35a236 Mon Sep 17 00:00:00 2001 From: Matthew Shun-Shin Date: Fri, 28 Jul 2017 11:30:19 +0100 Subject: [PATCH 01/15] Fix GL Views being half size on hidpi monitors --- pyqtgraph/opengl/GLViewWidget.py | 4 ++-- pyqtgraph/widgets/RawImageWidget.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py index e0fee046..40a7d858 100644 --- a/pyqtgraph/opengl/GLViewWidget.py +++ b/pyqtgraph/opengl/GLViewWidget.py @@ -80,7 +80,7 @@ class GLViewWidget(QtOpenGL.QGLWidget): def getViewport(self): vp = self.opts['viewport'] if vp is None: - return (0, 0, self.width(), self.height()) + return (0, 0, self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio()) else: return vp @@ -99,7 +99,7 @@ class GLViewWidget(QtOpenGL.QGLWidget): def projectionMatrix(self, region=None): # Xw = (Xnd + 1) * width/2 + X if region is None: - region = (0, 0, self.width(), self.height()) + region = (0, 0, self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio()) x0, y0, w, h = self.getViewport() dist = self.opts['distance'] diff --git a/pyqtgraph/widgets/RawImageWidget.py b/pyqtgraph/widgets/RawImageWidget.py index 657701f9..ef1d7a38 100644 --- a/pyqtgraph/widgets/RawImageWidget.py +++ b/pyqtgraph/widgets/RawImageWidget.py @@ -122,7 +122,7 @@ if HAVE_OPENGL: if not self.uploaded: self.uploadTexture() - glViewport(0, 0, self.width(), self.height()) + glViewport(0, 0, self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio()) glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, self.texture) glColor4f(1,1,1,1) From f77d7409ba368edaf63bc9e41e47c1683b94c6e5 Mon Sep 17 00:00:00 2001 From: HashSplat Date: Tue, 12 Sep 2017 17:15:26 -0400 Subject: [PATCH 02/15] Fixed legend size after remove item When the legend removed an item with a large label name the legend would not shrink in width. This fix uses the sample and label minimum width to allow the legend to shrink when an item is removed. --- pyqtgraph/graphicsItems/LegendItem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyqtgraph/graphicsItems/LegendItem.py b/pyqtgraph/graphicsItems/LegendItem.py index 20d6416e..527b814a 100644 --- a/pyqtgraph/graphicsItems/LegendItem.py +++ b/pyqtgraph/graphicsItems/LegendItem.py @@ -110,7 +110,8 @@ class LegendItem(GraphicsWidget, GraphicsWidgetAnchor): #print("-------") for sample, label in self.items: height += max(sample.height(), label.height()) + 3 - width = max(width, sample.width()+label.width()) + width = max(width, (sample.sizeHint(QtCore.Qt.MinimumSize, sample.size()).width() + + label.sizeHint(QtCore.Qt.MinimumSize, label.size()).width())) #print(width, height) #print width, height self.setGeometry(0, 0, width+25, height) From 8a956bfddb3d31cadc80ab392995ddf6de22d507 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Fri, 2 Feb 2018 22:40:06 +0800 Subject: [PATCH 03/15] Add main window title for the examples --- examples/__main__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/__main__.py b/examples/__main__.py index 03c41119..6b8a07f9 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -26,6 +26,7 @@ class ExampleLoader(QtGui.QMainWindow): self.cw = QtGui.QWidget() self.setCentralWidget(self.cw) self.ui.setupUi(self.cw) + self.setWindowTitle("Examples") self.codeBtn = QtGui.QPushButton('Run Edited Code') self.codeLayout = QtGui.QGridLayout() From 81562b02528072e4bac98152bbbc07704ae9e431 Mon Sep 17 00:00:00 2001 From: Billy Su Date: Sat, 3 Feb 2018 10:16:09 +0800 Subject: [PATCH 04/15] Refactor MultiPlotSpeedTest.py * Change variable to meaningful name, * Remove the outdated commented out code. --- examples/MultiPlotSpeedTest.py | 40 ++++++++++++++-------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/examples/MultiPlotSpeedTest.py b/examples/MultiPlotSpeedTest.py index 0d0d701b..f4295687 100644 --- a/examples/MultiPlotSpeedTest.py +++ b/examples/MultiPlotSpeedTest.py @@ -12,32 +12,27 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time -#QtGui.QApplication.setGraphicsSystem('raster') app = QtGui.QApplication([]) -#mw = QtGui.QMainWindow() -#mw.resize(800,800) -p = pg.plot() -p.setWindowTitle('pyqtgraph example: MultiPlotSpeedTest') -#p.setRange(QtCore.QRectF(0, -10, 5000, 20)) -p.setLabel('bottom', 'Index', units='B') +plot = pg.plot() +plot.setWindowTitle('pyqtgraph example: MultiPlotSpeedTest') +plot.setLabel('bottom', 'Index', units='B') nPlots = 100 nSamples = 500 -#curves = [p.plot(pen=(i,nPlots*1.3)) for i in range(nPlots)] curves = [] -for i in range(nPlots): - c = pg.PlotCurveItem(pen=(i,nPlots*1.3)) - p.addItem(c) - c.setPos(0,i*6) - curves.append(c) +for idx in range(nPlots): + curve = pg.PlotCurveItem(pen=(idx,nPlots*1.3)) + plot.addItem(curve) + curve.setPos(0,idx*6) + curves.append(curve) -p.setYRange(0, nPlots*6) -p.setXRange(0, nSamples) -p.resize(600,900) +plot.setYRange(0, nPlots*6) +plot.setXRange(0, nSamples) +plot.resize(600,900) rgn = pg.LinearRegionItem([nSamples/5.,nSamples/3.]) -p.addItem(rgn) +plot.addItem(rgn) data = np.random.normal(size=(nPlots*23,nSamples)) @@ -46,13 +41,12 @@ lastTime = time() fps = None count = 0 def update(): - global curve, data, ptr, p, lastTime, fps, nPlots, count + global curve, data, ptr, plot, lastTime, fps, nPlots, count count += 1 - #print "---------", count + for i in range(nPlots): curves[i].setData(data[(ptr+i)%data.shape[0]]) - - #print " setData done." + ptr += nPlots now = time() dt = now - lastTime @@ -62,13 +56,11 @@ def update(): else: s = np.clip(dt*3., 0, 1) fps = fps * (1-s) + (1.0/dt) * s - p.setTitle('%0.2f fps' % fps) + plot.setTitle('%0.2f fps' % fps) #app.processEvents() ## force complete redraw for every plot timer = QtCore.QTimer() timer.timeout.connect(update) timer.start(0) - - ## Start Qt event loop unless running in interactive mode. if __name__ == '__main__': From f3d5273f81ba804871b581e1584175201facae6f Mon Sep 17 00:00:00 2001 From: Fekete Imre Date: Wed, 7 Feb 2018 14:25:15 +0100 Subject: [PATCH 05/15] Cylinder now generates the correct amount of sides Before the first and the last vertex was overlapping. --- pyqtgraph/opengl/MeshData.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqtgraph/opengl/MeshData.py b/pyqtgraph/opengl/MeshData.py index f83fcdf6..5bab4626 100644 --- a/pyqtgraph/opengl/MeshData.py +++ b/pyqtgraph/opengl/MeshData.py @@ -485,7 +485,7 @@ class MeshData(object): if isinstance(radius, int): radius = [radius, radius] # convert to list ## compute vertexes - th = np.linspace(2 * np.pi, 0, cols).reshape(1, cols) + th = np.linspace(2 * np.pi, (2 * np.pi)/cols, cols).reshape(1, cols) r = np.linspace(radius[0],radius[1],num=rows+1, endpoint=True).reshape(rows+1, 1) # radius as a function of z verts[...,2] = np.linspace(0, length, num=rows+1, endpoint=True).reshape(rows+1, 1) # z if offset: From b25196067add5989b530cfd0d9a978deb97465a2 Mon Sep 17 00:00:00 2001 From: Tanuj Date: Sun, 25 Feb 2018 10:54:12 +0000 Subject: [PATCH 06/15] Fix grame typo --- pyqtgraph/opengl/items/GLGridItem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqtgraph/opengl/items/GLGridItem.py b/pyqtgraph/opengl/items/GLGridItem.py index 4d6bc9d6..63a558ea 100644 --- a/pyqtgraph/opengl/items/GLGridItem.py +++ b/pyqtgraph/opengl/items/GLGridItem.py @@ -10,7 +10,7 @@ class GLGridItem(GLGraphicsItem): """ **Bases:** :class:`GLGraphicsItem ` - Displays a wire-grame grid. + Displays a wire-frame grid. """ def __init__(self, size=None, color=None, antialias=True, glOptions='translucent'): From d09fe6bd478770862dffc3157f25e2dfcfa2a4ed Mon Sep 17 00:00:00 2001 From: Marko Toplak Date: Thu, 1 Mar 2018 15:34:15 +0100 Subject: [PATCH 07/15] SVGExporter: logicalDpiX instead of physicalDpiX Fixes problems with non-aligning axes on Qt5 svg exports. In the output svg, the axes were (individually) scaled for physical/logical ration. --- pyqtgraph/exporters/SVGExporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index fdc65080..700b63da 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -169,7 +169,7 @@ def _generateItemSvg(item, nodes=None, root=None): buf = QtCore.QBuffer(arr) svg = QtSvg.QSvgGenerator() svg.setOutputDevice(buf) - dpi = QtGui.QDesktopWidget().physicalDpiX() + dpi = QtGui.QDesktopWidget().logicalDpiX() svg.setResolution(dpi) p = QtGui.QPainter() From c7a32d83111dfa6b57fc37d9387e02e747e00bd5 Mon Sep 17 00:00:00 2001 From: Marko Toplak Date: Wed, 28 Feb 2018 11:04:50 +0100 Subject: [PATCH 08/15] SVG export: handle Qt.NoPen on Qt5 --- pyqtgraph/exporters/SVGExporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index fdc65080..97975fcf 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -372,7 +372,7 @@ def correctCoordinates(node, defs, item): 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': + if removeTransform and ch.getAttribute('vector-effect') != 'non-scaling-stroke' and grp.getAttribute('stroke-width'): w = float(grp.getAttribute('stroke-width')) s = fn.transformCoordinates(tr, np.array([[w,0], [0,0]]), transpose=True) w = ((s[0]-s[1])**2).sum()**0.5 From 27f37d0fd1ae56039936a9af96d8b0688078ee97 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 19 Mar 2018 12:09:49 +0100 Subject: [PATCH 09/15] fix color ignored in GLGridItem. Issue #283 solved --- pyqtgraph/opengl/items/GLGridItem.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyqtgraph/opengl/items/GLGridItem.py b/pyqtgraph/opengl/items/GLGridItem.py index 4d6bc9d6..dece73a5 100644 --- a/pyqtgraph/opengl/items/GLGridItem.py +++ b/pyqtgraph/opengl/items/GLGridItem.py @@ -13,7 +13,7 @@ class GLGridItem(GLGraphicsItem): Displays a wire-grame grid. """ - def __init__(self, size=None, color=None, antialias=True, glOptions='translucent'): + def __init__(self, size=None, color=(1, 1, 1, .3), antialias=True, glOptions='translucent'): GLGraphicsItem.__init__(self) self.setGLOptions(glOptions) self.antialias = antialias @@ -21,6 +21,7 @@ class GLGridItem(GLGraphicsItem): size = QtGui.QVector3D(20,20,1) self.setSize(size=size) self.setSpacing(1, 1, 1) + self.color = color def setSize(self, x=None, y=None, z=None, size=None): """ @@ -66,8 +67,8 @@ class GLGridItem(GLGraphicsItem): x,y,z = self.size() xs,ys,zs = self.spacing() xvals = np.arange(-x/2., x/2. + xs*0.001, xs) - yvals = np.arange(-y/2., y/2. + ys*0.001, ys) - glColor4f(1, 1, 1, .3) + yvals = np.arange(-y/2., y/2. + ys*0.001, ys) + glColor4f(*self.color) for x in xvals: glVertex3f(x, yvals[0], 0) glVertex3f(x, yvals[-1], 0) From b3a579fd004f9a841038b6adf6d4ec14dbe8748a Mon Sep 17 00:00:00 2001 From: Ales Erjavec Date: Thu, 29 Mar 2018 12:03:57 +0200 Subject: [PATCH 10/15] ScatterPlotItem: Fix a GC memory leak due to numpy issue 6581 --- pyqtgraph/graphicsItems/ScatterPlotItem.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index 443cc220..30e6cf89 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -857,11 +857,18 @@ class SpotItem(object): def __init__(self, data, plot): #GraphicsItem.__init__(self, register=False) self._data = data - self._plot = plot + # SpotItems are kept in plot.data["items"] numpy object array which + # does not support cyclic garbage collection (numpy issue 6581). + # Keeping a strong ref to plot here would leak the cycle + self.__plot_ref = weakref.ref(plot) #self.setParentItem(plot) #self.setPos(QtCore.QPointF(data['x'], data['y'])) #self.updateItem() + @property + def _plot(self): + return self.__plot_ref() + def data(self): """Return the user data associated with this spot.""" return self._data['data'] From 358b1539eee6d45f75169bf4471604d540c8e8d5 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 29 Mar 2018 08:49:42 -0700 Subject: [PATCH 11/15] add reduce import to fractal demo --- examples/fractal.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/fractal.py b/examples/fractal.py index eeb1bdb0..d91133a5 100644 --- a/examples/fractal.py +++ b/examples/fractal.py @@ -4,6 +4,7 @@ Displays an interactive Koch fractal """ import initExample ## Add path to library (just for examples; you do not need this) +from functools import reduce import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np @@ -111,12 +112,4 @@ if __name__ == '__main__': import sys if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): QtGui.QApplication.instance().exec_() - - - - - - - - \ No newline at end of file From f79bd8d4fb6d4b13c4dfdd377d07644968964b37 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 29 Mar 2018 09:06:20 -0700 Subject: [PATCH 12/15] svg export fix: more explicit check --- pyqtgraph/exporters/SVGExporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index 97975fcf..0ab9a736 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -372,7 +372,7 @@ def correctCoordinates(node, defs, item): 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' and grp.getAttribute('stroke-width'): + if removeTransform and ch.getAttribute('vector-effect') != 'non-scaling-stroke' and grp.getAttribute('stroke-width') != '': w = float(grp.getAttribute('stroke-width')) s = fn.transformCoordinates(tr, np.array([[w,0], [0,0]]), transpose=True) w = ((s[0]-s[1])**2).sum()**0.5 From 043a3b4d6d7faf84faa563853e55f319884ebd70 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 29 Mar 2018 18:30:46 -0700 Subject: [PATCH 13/15] Better title --- examples/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/__main__.py b/examples/__main__.py index 6b8a07f9..084fe2c3 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -26,7 +26,7 @@ class ExampleLoader(QtGui.QMainWindow): self.cw = QtGui.QWidget() self.setCentralWidget(self.cw) self.ui.setupUi(self.cw) - self.setWindowTitle("Examples") + self.setWindowTitle("PyQtGraph Examples") self.codeBtn = QtGui.QPushButton('Run Edited Code') self.codeLayout = QtGui.QGridLayout() From 063e9c91a999853a47675a2befcdfef4c0e30d53 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Tue, 24 Apr 2018 08:59:33 -0700 Subject: [PATCH 14/15] Make high-dpi handling conditional on Qt version --- pyqtgraph/opengl/GLViewWidget.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py index c6d0c1fa..540fce7d 100644 --- a/pyqtgraph/opengl/GLViewWidget.py +++ b/pyqtgraph/opengl/GLViewWidget.py @@ -16,9 +16,13 @@ class GLViewWidget(QtOpenGL.QGLWidget): - Axis/grid display - Export options + + High-DPI displays: Qt5 should automatically detect the correct resolution. + For Qt4, specify the ``devicePixelRatio`` argument when initializing the + widget (usually this value is 1-2). """ - def __init__(self, parent=None): + def __init__(self, parent=None, devicePixelRatio=None): global ShareWidget if ShareWidget is None: @@ -37,6 +41,7 @@ class GLViewWidget(QtOpenGL.QGLWidget): 'azimuth': 45, ## camera's azimuthal angle in degrees ## (rotation around z-axis 0 points along x-axis) 'viewport': None, ## glViewport params; None == whole widget + 'devicePixelRatio': devicePixelRatio, } self.setBackgroundColor('k') self.items = [] @@ -79,10 +84,21 @@ class GLViewWidget(QtOpenGL.QGLWidget): def getViewport(self): vp = self.opts['viewport'] + dpr = self.devicePixelRatio() if vp is None: - return (0, 0, self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio()) + return (0, 0, int(self.width() * dpr), int(self.height() * dpr)) else: - return vp + return tuple([int(x * dpr) for x in vp]) + + def devicePixelRatio(self): + dpr = self.opts['devicePixelRatio'] + if dpr is not None: + return dpr + + if hasattr(QtOpenGL.QGLWidget, 'devicePixelRatio'): + return QtOpenGL.QGLWidget.devicePixelRatio(self) + else: + return 1.0 def resizeGL(self, w, h): pass @@ -99,7 +115,8 @@ class GLViewWidget(QtOpenGL.QGLWidget): def projectionMatrix(self, region=None): # Xw = (Xnd + 1) * width/2 + X if region is None: - region = (0, 0, self.width() * self.devicePixelRatio(), self.height() * self.devicePixelRatio()) + dpr = self.devicePixelRatio() + region = (0, 0, self.width() * dpr, self.height() * dpr) x0, y0, w, h = self.getViewport() dist = self.opts['distance'] From 80ff4ebfe6196c59c3e5e834cb769f39a8ae93b8 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Wed, 25 Apr 2018 08:50:37 -0700 Subject: [PATCH 15/15] Remove prints from console --- pyqtgraph/console/Console.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyqtgraph/console/Console.py b/pyqtgraph/console/Console.py index 634aab4a..02f00c44 100644 --- a/pyqtgraph/console/Console.py +++ b/pyqtgraph/console/Console.py @@ -359,7 +359,6 @@ class ConsoleWidget(QtGui.QWidget): for index, line in enumerate(traceback.extract_stack(frame)): # extract_stack return value changed in python 3.5 if 'FrameSummary' in str(type(line)): - print(dir(line)) line = (line.filename, line.lineno, line.name, line._line) self.ui.exceptionStackList.addItem('File "%s", line %s, in %s()\n %s' % line) @@ -380,7 +379,6 @@ class ConsoleWidget(QtGui.QWidget): for index, line in enumerate(traceback.extract_tb(tb)): # extract_stack return value changed in python 3.5 if 'FrameSummary' in str(type(line)): - print(dir(line)) line = (line.filename, line.lineno, line.name, line._line) self.ui.exceptionStackList.addItem('File "%s", line %s, in %s()\n %s' % line)