From 03c01d3b32b420cd888f9acf7f2d36b7a4d47acf Mon Sep 17 00:00:00 2001 From: Luke Campagnola Date: Thu, 19 Dec 2013 12:30:00 -0500 Subject: [PATCH] Fixes related to CSV exporter: - CSV headers include data names, if available - Exporter correctly handles items with no data - pg.plot() avoids creating empty data item - removed call to reduce() from exporter; not available in python 3 - Gave .name() methods to PlotDataItem, PlotCurveItem, and ScatterPlotItem --- examples/Plotting.py | 6 +++--- pyqtgraph/__init__.py | 3 ++- pyqtgraph/exporters/CSVExporter.py | 12 +++++++++--- pyqtgraph/graphicsItems/PlotCurveItem.py | 5 ++++- pyqtgraph/graphicsItems/PlotDataItem.py | 3 +++ pyqtgraph/graphicsItems/PlotItem/PlotItem.py | 4 +++- pyqtgraph/graphicsItems/ScatterPlotItem.py | 6 ++++++ 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/examples/Plotting.py b/examples/Plotting.py index 6578fb2b..8476eae8 100644 --- a/examples/Plotting.py +++ b/examples/Plotting.py @@ -27,9 +27,9 @@ pg.setConfigOptions(antialias=True) p1 = win.addPlot(title="Basic array plotting", y=np.random.normal(size=100)) p2 = win.addPlot(title="Multiple curves") -p2.plot(np.random.normal(size=100), pen=(255,0,0)) -p2.plot(np.random.normal(size=100)+5, pen=(0,255,0)) -p2.plot(np.random.normal(size=100)+10, pen=(0,0,255)) +p2.plot(np.random.normal(size=100), pen=(255,0,0), name="Red curve") +p2.plot(np.random.normal(size=110)+5, pen=(0,255,0), name="Blue curve") +p2.plot(np.random.normal(size=120)+10, pen=(0,0,255), name="Green curve") p3 = win.addPlot(title="Drawing with points") p3.plot(np.random.normal(size=100), pen=(200,200,200), symbolBrush=(255,0,0), symbolPen='w') diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index f46184b4..f25d1c3a 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -292,7 +292,8 @@ def plot(*args, **kargs): dataArgs[k] = kargs[k] w = PlotWindow(**pwArgs) - w.plot(*args, **dataArgs) + if len(args) > 0 or len(dataArgs) > 0: + w.plot(*args, **dataArgs) plots.append(w) w.show() return w diff --git a/pyqtgraph/exporters/CSVExporter.py b/pyqtgraph/exporters/CSVExporter.py index 0439fc35..3ff2af31 100644 --- a/pyqtgraph/exporters/CSVExporter.py +++ b/pyqtgraph/exporters/CSVExporter.py @@ -33,8 +33,14 @@ class CSVExporter(Exporter): data = [] header = [] for c in self.item.curves: - data.append(c.getData()) - header.extend(['x', 'y']) + cd = c.getData() + if cd[0] is None: + continue + data.append(cd) + name = '' + if hasattr(c, 'implements') and c.implements('plotData') and c.name() is not None: + name = c.name().replace('"', '""') + '_' + header.extend(['"'+name+'x"', '"'+name+'y"']) if self.params['separator'] == 'comma': sep = ',' @@ -44,7 +50,7 @@ class CSVExporter(Exporter): fd.write(sep.join(header) + '\n') i = 0 numFormat = '%%0.%dg' % self.params['precision'] - numRows = reduce(max, [len(d[0]) for d in data]) + numRows = max([len(d[0]) for d in data]) for i in range(numRows): for d in data: if i < len(d[0]): diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index d221bf74..93ef195b 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -65,7 +65,7 @@ class PlotCurveItem(GraphicsObject): 'brush': None, 'stepMode': False, 'name': None, - 'antialias': pg.getConfigOption('antialias'),\ + 'antialias': pg.getConfigOption('antialias'), 'connect': 'all', 'mouseWidth': 8, # width of shape responding to mouse click } @@ -78,6 +78,9 @@ class PlotCurveItem(GraphicsObject): return ints return interface in ints + def name(self): + return self.opts.get('name', None) + def setClickable(self, s, width=None): """Sets whether the item responds to mouse clicks. diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py index 2235711c..7d46d65c 100644 --- a/pyqtgraph/graphicsItems/PlotDataItem.py +++ b/pyqtgraph/graphicsItems/PlotDataItem.py @@ -170,6 +170,9 @@ class PlotDataItem(GraphicsObject): return ints return interface in ints + def name(self): + return self.opts.get('name', None) + def boundingRect(self): return QtCore.QRectF() ## let child items handle this diff --git a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py index 7f817f81..b99a3266 100644 --- a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py +++ b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py @@ -514,7 +514,9 @@ class PlotItem(GraphicsWidget): if 'ignoreBounds' in kargs: vbargs['ignoreBounds'] = kargs['ignoreBounds'] self.vb.addItem(item, *args, **vbargs) + name = None if hasattr(item, 'implements') and item.implements('plotData'): + name = item.name() self.dataItems.append(item) #self.plotChanged() @@ -547,7 +549,7 @@ class PlotItem(GraphicsWidget): #c.connect(c, QtCore.SIGNAL('plotChanged'), self.plotChanged) #item.sigPlotChanged.connect(self.plotChanged) #self.plotChanged() - name = kargs.get('name', getattr(item, 'opts', {}).get('name', None)) + #name = kargs.get('name', getattr(item, 'opts', {}).get('name', None)) if name is not None and hasattr(self, 'legend') and self.legend is not None: self.legend.addItem(item, name=name) diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index 15be8be0..498df2cd 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -234,6 +234,7 @@ class ScatterPlotItem(GraphicsObject): 'pxMode': True, 'useCache': True, ## If useCache is False, symbols are re-drawn on every paint. 'antialias': pg.getConfigOption('antialias'), + 'name': None, } self.setPen(200,200,200, update=False) @@ -281,6 +282,8 @@ class ScatterPlotItem(GraphicsObject): *antialias* Whether to draw symbols with antialiasing. Note that if pxMode is True, symbols are always rendered with antialiasing (since the rendered symbols can be cached, this incurs very little performance cost) + *name* The name of this item. Names are used for automatically + generating LegendItem entries and by some exporters. ====================== =============================================================================================== """ oldData = self.data ## this causes cached pixmaps to be preserved while new data is registered. @@ -410,6 +413,9 @@ class ScatterPlotItem(GraphicsObject): return ints return interface in ints + def name(self): + return self.opts.get('name', None) + def setPen(self, *args, **kargs): """Set the pen(s) used to draw the outline around each spot. If a list or array is provided, then the pen for each spot will be set separately.