From 23779f004eb85ee448de11d9b431b55a009f2410 Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 23 Jan 2014 10:34:26 -0500 Subject: [PATCH] - Fixed FillBetweenItem to force PlotCurveItem to generate path - Added FillBetweenItem.setCurves() - Added FillBetweenItem example --- CHANGELOG | 2 + examples/__main__.py | 1 + pyqtgraph/graphicsItems/FillBetweenItem.py | 64 +++++++++++++++++++--- pyqtgraph/graphicsItems/PlotDataItem.py | 2 +- 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3db12cb9..4888d8d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,7 @@ pyqtgraph-0.9.9 [unreleased] - Get, set current value - Added Flowchart.sigChartChanged - ImageItem.getHistogram is more clever about constructing histograms + - Added FillBetweenItem.setCurves() Bugfixes: - PlotCurveItem now has correct clicking behavior--clicks within a few px @@ -42,6 +43,7 @@ pyqtgraph-0.9.9 [unreleased] - Prevent divide-by-zero in AxisItem - Major speedup when using ScatterPlotItem in pxMode - PlotCurveItem ignores clip-to-view when auto range is enabled + - FillBetweenItem now forces PlotCurveItem to generate path pyqtgraph-0.9.8 2013-11-24 diff --git a/examples/__main__.py b/examples/__main__.py index 7d75e36a..e7dbe5eb 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -37,6 +37,7 @@ examples = OrderedDict([ ('IsocurveItem', 'isocurve.py'), ('GraphItem', 'GraphItem.py'), ('ErrorBarItem', 'ErrorBarItem.py'), + ('FillBetweenItem', 'FillBetweenItem.py'), ('ImageItem - video', 'ImageItem.py'), ('ImageItem - draw', 'Draw.py'), ('Region-of-Interest', 'ROIExamples.py'), diff --git a/pyqtgraph/graphicsItems/FillBetweenItem.py b/pyqtgraph/graphicsItems/FillBetweenItem.py index 13e5fa6b..3cf33acd 100644 --- a/pyqtgraph/graphicsItems/FillBetweenItem.py +++ b/pyqtgraph/graphicsItems/FillBetweenItem.py @@ -1,24 +1,70 @@ from ..Qt import QtGui from .. import functions as fn +from .PlotDataItem import PlotDataItem +from .PlotCurveItem import PlotCurveItem class FillBetweenItem(QtGui.QGraphicsPathItem): """ GraphicsItem filling the space between two PlotDataItems. """ - def __init__(self, p1, p2, brush=None): + def __init__(self, curve1=None, curve2=None, brush=None): QtGui.QGraphicsPathItem.__init__(self) - self.p1 = p1 - self.p2 = p2 - p1.sigPlotChanged.connect(self.updatePath) - p2.sigPlotChanged.connect(self.updatePath) + self.curves = None + if curve1 is not None and curve2 is not None: + self.setCurves(curve1, curve2) + elif curve1 is not None or curve2 is not None: + raise Exception("Must specify two curves to fill between.") + if brush is not None: self.setBrush(fn.mkBrush(brush)) - self.setZValue(min(p1.zValue(), p2.zValue())-1) + self.updatePath() + + def setCurves(self, curve1, curve2): + """Set the curves to fill between. + + Arguments must be instances of PlotDataItem or PlotCurveItem.""" + + if self.curves is not None: + for c in self.curves: + try: + c.sigPlotChanged.disconnect(self.curveChanged) + except TypeError: + pass + + curves = [curve1, curve2] + for c in curves: + if not isinstance(c, PlotDataItem) and not isinstance(c, PlotCurveItem): + raise TypeError("Curves must be PlotDataItem or PlotCurveItem.") + self.curves = curves + curve1.sigPlotChanged.connect(self.curveChanged) + curve2.sigPlotChanged.connect(self.curveChanged) + self.setZValue(min(curve1.zValue(), curve2.zValue())-1) + self.curveChanged() + + def setBrush(self, *args, **kwds): + """Change the fill brush. Acceps the same arguments as pg.mkBrush()""" + QtGui.QGraphicsPathItem.setBrush(self, fn.mkBrush(*args, **kwds)) + + def curveChanged(self): self.updatePath() def updatePath(self): - p1 = self.p1.curve.path - p2 = self.p2.curve.path + if self.curves is None: + self.setPath(QtGui.QPainterPath()) + return + paths = [] + for c in self.curves: + if isinstance(c, PlotDataItem): + paths.append(c.curve.getPath()) + elif isinstance(c, PlotCurveItem): + paths.append(c.getPath()) + path = QtGui.QPainterPath() - path.addPolygon(p1.toSubpathPolygons()[0] + p2.toReversed().toSubpathPolygons()[0]) + p1 = paths[0].toSubpathPolygons() + p2 = paths[1].toReversed().toSubpathPolygons() + if len(p1) == 0 or len(p2) == 0: + self.setPath(QtGui.QPainterPath()) + return + + path.addPolygon(p1[0] + p2[0]) self.setPath(path) diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py index c1f9fd6a..8baab719 100644 --- a/pyqtgraph/graphicsItems/PlotDataItem.py +++ b/pyqtgraph/graphicsItems/PlotDataItem.py @@ -15,7 +15,7 @@ class PlotDataItem(GraphicsObject): GraphicsItem for displaying plot curves, scatter plots, or both. While it is possible to use :class:`PlotCurveItem ` or :class:`ScatterPlotItem ` individually, this class - provides a unified interface to both. Inspances of :class:`PlotDataItem` are + provides a unified interface to both. Instances of :class:`PlotDataItem` are usually created by plot() methods such as :func:`pyqtgraph.plot` and :func:`PlotItem.plot() `.