Minor edits and bugfixes
- fixed AxisItem sometimes drawing the same tick twice (sometimes with different text) - fixed handling of record arrays in setting ScatterPlotItem point data
This commit is contained in:
parent
a4963f93b7
commit
cc94e15d1e
@ -1,13 +1,10 @@
|
|||||||
#!/usr/bin/python -i
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
## Add path to library (just for examples; you do not need this)
|
import initExample ## Add path to library (just for examples; you do not need this)
|
||||||
import sys, os
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
||||||
|
|
||||||
|
|
||||||
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtCore, QtGui
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
|
||||||
|
|
||||||
## Create image to display
|
## Create image to display
|
||||||
arr = np.ones((100, 100), dtype=float)
|
arr = np.ones((100, 100), dtype=float)
|
||||||
@ -128,100 +125,10 @@ img4.setParentItem(r4)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#v = w.addViewBox(colspan=2)
|
|
||||||
|
|
||||||
#v.invertY(True) ## Images usually have their Y-axis pointing downward
|
|
||||||
#v.setAspectLocked(True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Create image items, add to scene and set position
|
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||||
#im1 = pg.ImageItem(arr)
|
import sys
|
||||||
#im2 = pg.ImageItem(arr)
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
#v.addItem(im1)
|
QtGui.QApplication.instance().exec_()
|
||||||
#v.addItem(im2)
|
|
||||||
#im2.moveBy(110, 20)
|
|
||||||
#v.setRange(QtCore.QRectF(0, 0, 200, 120))
|
|
||||||
|
|
||||||
#im3 = pg.ImageItem()
|
|
||||||
#v2 = w.addViewBox(1,0)
|
|
||||||
#v2.addItem(im3)
|
|
||||||
#v2.setRange(QtCore.QRectF(0, 0, 60, 60))
|
|
||||||
#v2.invertY(True)
|
|
||||||
#v2.setAspectLocked(True)
|
|
||||||
##im3.moveBy(0, 130)
|
|
||||||
#im3.setZValue(10)
|
|
||||||
|
|
||||||
#im4 = pg.ImageItem()
|
|
||||||
#v3 = w.addViewBox(1,1)
|
|
||||||
#v3.addItem(im4)
|
|
||||||
#v3.setRange(QtCore.QRectF(0, 0, 60, 60))
|
|
||||||
#v3.invertY(True)
|
|
||||||
#v3.setAspectLocked(True)
|
|
||||||
##im4.moveBy(110, 130)
|
|
||||||
#im4.setZValue(10)
|
|
||||||
|
|
||||||
### create the plot
|
|
||||||
#pi1 = w.addPlot(2,0, colspan=2)
|
|
||||||
##pi1 = pg.PlotItem()
|
|
||||||
##s.addItem(pi1)
|
|
||||||
##pi1.scale(0.5, 0.5)
|
|
||||||
##pi1.setGeometry(0, 170, 300, 100)
|
|
||||||
|
|
||||||
#lastRoi = None
|
|
||||||
|
|
||||||
#def updateRoi(roi):
|
|
||||||
#global im1, im2, im3, im4, arr, lastRoi
|
|
||||||
#if roi is None:
|
|
||||||
#return
|
|
||||||
#lastRoi = roi
|
|
||||||
#arr1 = roi.getArrayRegion(im1.image, img=im1)
|
|
||||||
#im3.setImage(arr1)
|
|
||||||
#arr2 = roi.getArrayRegion(im2.image, img=im2)
|
|
||||||
#im4.setImage(arr2)
|
|
||||||
#updateRoiPlot(roi, arr1)
|
|
||||||
|
|
||||||
#def updateRoiPlot(roi, data=None):
|
|
||||||
#if data is None:
|
|
||||||
#data = roi.getArrayRegion(im1.image, img=im1)
|
|
||||||
#if data is not None:
|
|
||||||
#roi.curve.setData(data.mean(axis=1))
|
|
||||||
|
|
||||||
|
|
||||||
### Create a variety of different ROI types
|
|
||||||
#rois = []
|
|
||||||
#rois.append(pg.TestROI([0, 0], [20, 20], maxBounds=QtCore.QRectF(-10, -10, 230, 140), pen=(0,9)))
|
|
||||||
#rois.append(pg.LineROI([0, 0], [20, 20], width=5, pen=(1,9)))
|
|
||||||
#rois.append(pg.MultiLineROI([[0, 50], [50, 60], [60, 30]], width=5, pen=(2,9)))
|
|
||||||
#rois.append(pg.EllipseROI([110, 10], [30, 20], pen=(3,9)))
|
|
||||||
#rois.append(pg.CircleROI([110, 50], [20, 20], pen=(4,9)))
|
|
||||||
#rois.append(pg.LineSegmentROI([[110, 50], [20, 20]], pen=(5,9)))
|
|
||||||
#rois.append(pg.PolyLineROI([[110, 60], [20, 30], [50, 10]], pen=(6,9)))
|
|
||||||
##rois.append(pg.PolygonROI([[2,0], [2.1,0], [2,.1]], pen=(5,9)))
|
|
||||||
##rois.append(SpiralROI([20,30], [1,1], pen=mkPen(0)))
|
|
||||||
|
|
||||||
### Add each ROI to the scene and link its data to a plot curve with the same color
|
|
||||||
#for r in rois:
|
|
||||||
#v.addItem(r)
|
|
||||||
#c = pi1.plot(pen=r.pen)
|
|
||||||
#r.curve = c
|
|
||||||
#r.sigRegionChanged.connect(updateRoi)
|
|
||||||
|
|
||||||
#def updateImage():
|
|
||||||
#global im1, arr, lastRoi
|
|
||||||
#r = abs(np.random.normal(loc=0, scale=(arr.max()-arr.min())*0.1, size=arr.shape))
|
|
||||||
#im1.updateImage(arr + r)
|
|
||||||
#updateRoi(lastRoi)
|
|
||||||
#for r in rois:
|
|
||||||
#updateRoiPlot(r)
|
|
||||||
|
|
||||||
### Rapidly update one of the images with random noise
|
|
||||||
#t = QtCore.QTimer()
|
|
||||||
#t.timeout.connect(updateImage)
|
|
||||||
#t.start(50)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Start Qt event loop unless running in interactive mode.
|
|
||||||
if sys.flags.interactive != 1:
|
|
||||||
app.exec_()
|
|
||||||
|
@ -210,7 +210,7 @@ class AxisItem(GraphicsWidget):
|
|||||||
if scale is None:
|
if scale is None:
|
||||||
#if self.drawLabel: ## If there is a label, then we are free to rescale the values
|
#if self.drawLabel: ## If there is a label, then we are free to rescale the values
|
||||||
if self.label.isVisible():
|
if self.label.isVisible():
|
||||||
d = self.range[1] - self.range[0]
|
#d = self.range[1] - self.range[0]
|
||||||
#(scale, prefix) = fn.siScale(d / 2.)
|
#(scale, prefix) = fn.siScale(d / 2.)
|
||||||
(scale, prefix) = fn.siScale(max(abs(self.range[0]), abs(self.range[1])))
|
(scale, prefix) = fn.siScale(max(abs(self.range[0]), abs(self.range[1])))
|
||||||
if self.labelUnits == '' and prefix in ['k', 'm']: ## If we are not showing units, wait until 1e6 before scaling.
|
if self.labelUnits == '' and prefix in ['k', 'm']: ## If we are not showing units, wait until 1e6 before scaling.
|
||||||
@ -230,7 +230,7 @@ class AxisItem(GraphicsWidget):
|
|||||||
def setRange(self, mn, mx):
|
def setRange(self, mn, mx):
|
||||||
"""Set the range of values displayed by the axis.
|
"""Set the range of values displayed by the axis.
|
||||||
Usually this is handled automatically by linking the axis to a ViewBox with :func:`linkToView <pyqtgraph.AxisItem.linkToView>`"""
|
Usually this is handled automatically by linking the axis to a ViewBox with :func:`linkToView <pyqtgraph.AxisItem.linkToView>`"""
|
||||||
if mn in [np.nan, np.inf, -np.inf] or mx in [np.nan, np.inf, -np.inf]:
|
if any(np.isinf((mn, mx))) or any(np.isnan((mn, mx))):
|
||||||
raise Exception("Not setting range to [%s, %s]" % (str(mn), str(mx)))
|
raise Exception("Not setting range to [%s, %s]" % (str(mn), str(mx)))
|
||||||
self.range = [mn, mx]
|
self.range = [mn, mx]
|
||||||
if self.autoScale:
|
if self.autoScale:
|
||||||
@ -259,6 +259,9 @@ class AxisItem(GraphicsWidget):
|
|||||||
view.sigXRangeChanged.connect(self.linkedViewChanged)
|
view.sigXRangeChanged.connect(self.linkedViewChanged)
|
||||||
|
|
||||||
def linkedViewChanged(self, view, newRange):
|
def linkedViewChanged(self, view, newRange):
|
||||||
|
if self.orientation in ['right', 'left'] and view.yInverted():
|
||||||
|
self.setRange(*newRange[::-1])
|
||||||
|
else:
|
||||||
self.setRange(*newRange)
|
self.setRange(*newRange)
|
||||||
|
|
||||||
def boundingRect(self):
|
def boundingRect(self):
|
||||||
@ -365,12 +368,14 @@ class AxisItem(GraphicsWidget):
|
|||||||
By default, this method calls tickSpacing to determine the correct tick locations.
|
By default, this method calls tickSpacing to determine the correct tick locations.
|
||||||
This is a good method to override in subclasses.
|
This is a good method to override in subclasses.
|
||||||
"""
|
"""
|
||||||
|
minVal, maxVal = sorted((minVal, maxVal))
|
||||||
|
|
||||||
if self.logMode:
|
if self.logMode:
|
||||||
return self.logTickValues(minVal, maxVal, size)
|
return self.logTickValues(minVal, maxVal, size)
|
||||||
|
|
||||||
ticks = []
|
ticks = []
|
||||||
tickLevels = self.tickSpacing(minVal, maxVal, size)
|
tickLevels = self.tickSpacing(minVal, maxVal, size)
|
||||||
allValues = []
|
allValues = np.array([])
|
||||||
for i in range(len(tickLevels)):
|
for i in range(len(tickLevels)):
|
||||||
spacing, offset = tickLevels[i]
|
spacing, offset = tickLevels[i]
|
||||||
|
|
||||||
@ -380,8 +385,11 @@ class AxisItem(GraphicsWidget):
|
|||||||
## determine number of ticks
|
## determine number of ticks
|
||||||
num = int((maxVal-start) / spacing) + 1
|
num = int((maxVal-start) / spacing) + 1
|
||||||
values = np.arange(num) * spacing + start
|
values = np.arange(num) * spacing + start
|
||||||
values = filter(lambda x: x not in allValues, values) ## remove any ticks that were present in higher levels
|
## remove any ticks that were present in higher levels
|
||||||
allValues.extend(values)
|
## we assume here that if the difference between a tick value and a previously seen tick value
|
||||||
|
## is less than spacing/100, then they are 'equal' and we can ignore the new tick.
|
||||||
|
values = filter(lambda x: all(np.abs(allValues-x) > spacing*0.01), values)
|
||||||
|
allValues = np.concatenate([allValues, values])
|
||||||
ticks.append((spacing, values))
|
ticks.append((spacing, values))
|
||||||
return ticks
|
return ticks
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
from pyqtgraph.Qt import QtGui, QtCore
|
from pyqtgraph.Qt import QtGui, QtCore
|
||||||
import pyqtgraph.functions as fn
|
import pyqtgraph.functions as fn
|
||||||
from .GraphicsWidget import GraphicsWidget
|
from .GraphicsWidget import GraphicsWidget
|
||||||
|
## Must be imported at the end to avoid cyclic-dependency hell:
|
||||||
|
from .ViewBox import ViewBox
|
||||||
|
from .PlotItem import PlotItem
|
||||||
|
from .LabelItem import LabelItem
|
||||||
|
|
||||||
__all__ = ['GraphicsLayout']
|
__all__ = ['GraphicsLayout']
|
||||||
class GraphicsLayout(GraphicsWidget):
|
class GraphicsLayout(GraphicsWidget):
|
||||||
@ -34,7 +38,7 @@ class GraphicsLayout(GraphicsWidget):
|
|||||||
return self.currentCol-colspan
|
return self.currentCol-colspan
|
||||||
|
|
||||||
def nextCol(self, *args, **kargs):
|
def nextCol(self, *args, **kargs):
|
||||||
"""Advance to next column for automatic item placement"""
|
"""Alias of nextColumn"""
|
||||||
return self.nextColumn(*args, **kargs)
|
return self.nextColumn(*args, **kargs)
|
||||||
|
|
||||||
def addPlot(self, row=None, col=None, rowspan=1, colspan=1, **kargs):
|
def addPlot(self, row=None, col=None, rowspan=1, colspan=1, **kargs):
|
||||||
@ -131,7 +135,3 @@ class GraphicsLayout(GraphicsWidget):
|
|||||||
self.removeItem(i)
|
self.removeItem(i)
|
||||||
|
|
||||||
|
|
||||||
## Must be imported at the end to avoid cyclic-dependency hell:
|
|
||||||
from .ViewBox import ViewBox
|
|
||||||
from .PlotItem import PlotItem
|
|
||||||
from .LabelItem import LabelItem
|
|
@ -371,7 +371,6 @@ class PlotDataItem(GraphicsObject):
|
|||||||
#self.curves.append(curve)
|
#self.curves.append(curve)
|
||||||
|
|
||||||
if scatterArgs['symbol'] is not None:
|
if scatterArgs['symbol'] is not None:
|
||||||
print scatterArgs
|
|
||||||
self.scatter.setData(x=x, y=y, **scatterArgs)
|
self.scatter.setData(x=x, y=y, **scatterArgs)
|
||||||
self.scatter.show()
|
self.scatter.show()
|
||||||
else:
|
else:
|
||||||
|
@ -330,6 +330,13 @@ class ScatterPlotItem(GraphicsObject):
|
|||||||
if isinstance(data, np.ndarray) or isinstance(data, list):
|
if isinstance(data, np.ndarray) or isinstance(data, list):
|
||||||
if len(data) != len(dataSet):
|
if len(data) != len(dataSet):
|
||||||
raise Exception("Length of meta data does not match number of points (%d != %d)" % (len(data), len(dataSet)))
|
raise Exception("Length of meta data does not match number of points (%d != %d)" % (len(data), len(dataSet)))
|
||||||
|
|
||||||
|
## Bug: If data is a numpy record array, then items from that array must be copied to dataSet one at a time.
|
||||||
|
## (otherwise they are converted to tuples and thus lose their field names.
|
||||||
|
if isinstance(data, np.ndarray) and len(data.dtype.fields) > 1:
|
||||||
|
for i, rec in enumerate(data):
|
||||||
|
dataSet['data'][i] = rec
|
||||||
|
else:
|
||||||
dataSet['data'] = data
|
dataSet['data'] = data
|
||||||
|
|
||||||
def setPxMode(self, mode, update=True):
|
def setPxMode(self, mode, update=True):
|
||||||
|
@ -47,9 +47,9 @@ class CheckTable(QtGui.QWidget):
|
|||||||
check.row = name
|
check.row = name
|
||||||
self.layout.addWidget(check, row, col)
|
self.layout.addWidget(check, row, col)
|
||||||
checks.append(check)
|
checks.append(check)
|
||||||
col += 1
|
|
||||||
if name in self.oldRows:
|
if name in self.oldRows:
|
||||||
check.setChecked(self.oldRows[name])
|
check.setChecked(self.oldRows[name][col])
|
||||||
|
col += 1
|
||||||
#QtCore.QObject.connect(check, QtCore.SIGNAL('stateChanged(int)'), self.checkChanged)
|
#QtCore.QObject.connect(check, QtCore.SIGNAL('stateChanged(int)'), self.checkChanged)
|
||||||
check.stateChanged.connect(self.checkChanged)
|
check.stateChanged.connect(self.checkChanged)
|
||||||
self.rowNames.append(name)
|
self.rowNames.append(name)
|
||||||
|
@ -7,6 +7,6 @@ class GraphicsLayoutWidget(GraphicsView):
|
|||||||
def __init__(self, parent=None, **kargs):
|
def __init__(self, parent=None, **kargs):
|
||||||
GraphicsView.__init__(self, parent)
|
GraphicsView.__init__(self, parent)
|
||||||
self.ci = GraphicsLayout(**kargs)
|
self.ci = GraphicsLayout(**kargs)
|
||||||
for n in ['nextRow', 'nextCol', 'nextColumn', 'addPlot', 'addViewBox', 'addItem', 'getItem', 'addLabel', 'addLayout']:
|
for n in ['nextRow', 'nextCol', 'nextColumn', 'addPlot', 'addViewBox', 'addItem', 'getItem', 'addLabel', 'addLayout', 'addLabel', 'addViewBox', 'removeItem', 'itemIndex', 'clear']:
|
||||||
setattr(self, n, getattr(self.ci, n))
|
setattr(self, n, getattr(self.ci, n))
|
||||||
self.setCentralItem(self.ci)
|
self.setCentralItem(self.ci)
|
||||||
|
Loading…
Reference in New Issue
Block a user