- PlotItem can now be constructed with customized ViewBox and AxisItems

- Text spacing fix for AxisItem
This commit is contained in:
Luke Campagnola 2012-07-09 08:38:30 -04:00
parent f178919bee
commit 662b319d7b
8 changed files with 168 additions and 530 deletions

View File

@ -505,18 +505,19 @@ class GraphicsScene(QtGui.QGraphicsScene):
menusToAdd = []
while item is not self:
item = item.parentItem()
if item is None:
item = self
if not hasattr(item, "getContextMenus"):
continue
subMenus = item.getContextMenus(event)
if subMenus is None:
continue
if type(subMenus) is not list: ## so that some items (like FlowchartViewBox) can return multiple menus
subMenus = [subMenus]
for sm in subMenus:
menusToAdd.append(sm)

View File

@ -49,10 +49,10 @@ def getConfigOption(opt):
def systemInfo():
print "sys.platform:", sys.platform
print "sys.version:", sys.version
print("sys.platform: %s" % sys.platform)
print("sys.version: %s" % sys.version)
from .Qt import VERSION_INFO
print "qt bindings:", 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
@ -60,8 +60,8 @@ def systemInfo():
if os.path.exists(lastRevFile):
REVISION = open(lastRevFile, 'r').read().strip()
print "pyqtgraph:", REVISION
print "config:"
print("pyqtgraph: %s" % REVISION)
print("config:")
import pprint
pprint.pprint(CONFIG_OPTIONS)
@ -126,7 +126,7 @@ def importAll(path, excludes=()):
globals()[k] = getattr(mod, k)
importAll('graphicsItems')
importAll('widgets', excludes=['MatplotlibWidget'])
importAll('widgets', excludes=['MatplotlibWidget', 'RemoteGraphicsView'])
from .imageview import *
from .WidgetGroup import *

View File

@ -16,6 +16,7 @@ examples = OrderedDict([
('Video speed test', 'VideoSpeedTest.py'),
('Plot speed test', 'PlotSpeedTest.py'),
('Data Slicing', 'DataSlicing.py'),
('Plot Customization', 'customPlot.py'),
('GraphicsItems', OrderedDict([
('Scatter Plot', 'ScatterPlot.py'),
#('PlotItem', 'PlotItem.py'),
@ -45,7 +46,7 @@ examples = OrderedDict([
#('VerticalLabel', '../widgets/VerticalLabel.py'),
('JoystickButton', 'JoystickButton.py'),
])),
('GraphicsScene', 'GraphicsScene.py'),
('Flowcharts', 'Flowchart.py'),
#('Canvas', '../canvas'),

52
examples/customPlot.py Normal file
View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
##
## This example demonstrates the creation of a plot with a customized
## AxisItem and ViewBox.
##
import initExample ## Add path to library (just for examples; you do not need this)
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import time
class DateAxis(pg.AxisItem):
def tickStrings(self, values, scale, spacing):
return [time.strftime('%b %Y', time.localtime(x)) for x in values]
class CustomViewBox(pg.ViewBox):
def __init__(self, *args, **kwds):
pg.ViewBox.__init__(self, *args, **kwds)
self.setMouseMode(self.RectMode)
## reimplement right-click to zoom out
def mouseClickEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
self.autoRange()
def mouseDragEvent(self, ev):
if ev.button() == QtCore.Qt.RightButton:
ev.ignore()
else:
pg.ViewBox.mouseDragEvent(self, ev)
app = pg.mkQApp()
axis = DateAxis(orientation='bottom')
vb = CustomViewBox()
pw = pg.PlotWidget(viewBox=vb, axisItems={'bottom': axis}, enableMenu=False, title="PlotItem with custom axis and ViewBox<br>Menu disabled, mouse behavior changed: left-drag to zoom, right-click to reset zoom")
dates = np.arange(8) * (3600*24*356)
pw.plot(x=dates, y=[1,6,2,4,3,5,6,8], symbol='o')
pw.show()
r = pg.PolyLineROI([(0,0), (10, 10)])
pw.addItem(r)
## Start Qt event loop unless running in interactive mode or using pyside.
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

View File

@ -363,6 +363,29 @@ class AxisItem(GraphicsWidget):
(intervals[minorIndex], 0)
]
##### This does not work -- switching between 2/5 confuses the automatic text-level-selection
### Determine major/minor tick spacings which flank the optimal spacing.
#intervals = np.array([1., 2., 5., 10., 20., 50., 100.]) * p10unit
#minorIndex = 0
#while intervals[minorIndex+1] <= optimalSpacing:
#minorIndex += 1
### make sure we never see 5 and 2 at the same time
#intIndexes = [
#[0,1,3],
#[0,2,3],
#[2,3,4],
#[3,4,6],
#[3,5,6],
#][minorIndex]
#return [
#(intervals[intIndexes[2]], 0),
#(intervals[intIndexes[1]], 0),
#(intervals[intIndexes[0]], 0)
#]
def tickValues(self, minVal, maxVal, size):
"""
@ -395,7 +418,7 @@ class AxisItem(GraphicsWidget):
## remove any ticks that were present in higher levels
## 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)
values = list(filter(lambda x: all(np.abs(allValues-x) > spacing*0.01), values) )
allValues = np.concatenate([allValues, values])
ticks.append((spacing, values))
@ -601,9 +624,9 @@ class AxisItem(GraphicsWidget):
if tickPositions[i][j] is None:
strings[j] = None
textRects.extend([p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings if s is not None])
if i > 0: ## always draw top level
## measure all text, make sure there's enough room
textRects.extend([p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings if s is not None])
if axis == 0:
textSize = np.sum([r.height() for r in textRects])
else:
@ -613,7 +636,6 @@ class AxisItem(GraphicsWidget):
textFillRatio = float(textSize) / lengthInPixels
if textFillRatio > 0.7:
break
#spacing, values = tickLevels[best]
#strings = self.tickStrings(values, self.scale, spacing)
for j in range(len(strings)):

View File

@ -33,17 +33,12 @@ from .. AxisItem import AxisItem
from .. LabelItem import LabelItem
from .. GraphicsWidget import GraphicsWidget
from .. ButtonItem import ButtonItem
#from .. GraphicsLayout import GraphicsLayout
from pyqtgraph.WidgetGroup import WidgetGroup
import collections
__all__ = ['PlotItem']
#try:
#from WidgetGroup import *
#HAVE_WIDGETGROUP = True
#except:
#HAVE_WIDGETGROUP = False
try:
from metaarray import *
HAVE_METAARRAY = True
@ -99,26 +94,28 @@ class PlotItem(GraphicsWidget):
lastFileDir = None
managers = {}
def __init__(self, parent=None, name=None, labels=None, title=None, **kargs):
def __init__(self, parent=None, name=None, labels=None, title=None, viewBox=None, axisItems=None, enableMenu=True, **kargs):
"""
Create a new PlotItem. All arguments are optional.
Any extra keyword arguments are passed to PlotItem.plot().
============= ==========================================================================================
============== ==========================================================================================
**Arguments**
*title* Title to display at the top of the item. Html is allowed.
*labels* A dictionary specifying the axis labels to display::
*title* Title to display at the top of the item. Html is allowed.
*labels* A dictionary specifying the axis labels to display::
{'left': (args), 'bottom': (args), ...}
{'left': (args), 'bottom': (args), ...}
The name of each axis and the corresponding arguments are passed to
:func:`PlotItem.setLabel() <pyqtgraph.PlotItem.setLabel>`
Optionally, PlotItem my also be initialized with the keyword arguments left,
right, top, or bottom to achieve the same effect.
*name* Registers a name for this view so that others may link to it
============= ==========================================================================================
The name of each axis and the corresponding arguments are passed to
:func:`PlotItem.setLabel() <pyqtgraph.PlotItem.setLabel>`
Optionally, PlotItem my also be initialized with the keyword arguments left,
right, top, or bottom to achieve the same effect.
*name* Registers a name for this view so that others may link to it
*viewBox* If specified, the PlotItem will be constructed with this as its ViewBox.
*axisItems* Optional dictionary instructing the PlotItem to use pre-constructed items
for its axes. The dict keys must be axis names ('left', 'bottom', 'right', 'top')
and the values must be instances of AxisItem (or at least compatible with AxisItem).
============== ==========================================================================================
"""
GraphicsWidget.__init__(self, parent)
@ -127,8 +124,6 @@ class PlotItem(GraphicsWidget):
## Set up control buttons
path = os.path.dirname(__file__)
#self.ctrlBtn = ButtonItem(os.path.join(path, 'ctrl.png'), 14, self)
#self.ctrlBtn.clicked.connect(self.ctrlBtnClicked)
self.autoImageFile = os.path.join(path, 'auto.png')
self.lockImageFile = os.path.join(path, 'lock.png')
self.autoBtn = ButtonItem(self.autoImageFile, 14, self)
@ -141,32 +136,33 @@ class PlotItem(GraphicsWidget):
self.layout.setHorizontalSpacing(0)
self.layout.setVerticalSpacing(0)
self.vb = ViewBox(name=name)
if viewBox is None:
viewBox = ViewBox()
self.vb = viewBox
self.setMenuEnabled(enableMenu, enableMenu) ## en/disable plotitem and viewbox menus
if name is not None:
self.vb.register(name)
self.vb.sigRangeChanged.connect(self.sigRangeChanged)
self.vb.sigXRangeChanged.connect(self.sigXRangeChanged)
self.vb.sigYRangeChanged.connect(self.sigYRangeChanged)
#self.vb.sigRangeChangedManually.connect(self.enableManualScale)
#self.vb.sigRangeChanged.connect(self.viewRangeChanged)
self.layout.addItem(self.vb, 2, 1)
self.alpha = 1.0
self.autoAlpha = True
self.spectrumMode = False
#self.autoScale = [True, True]
## Create and place scale items
self.scales = {
'top': {'item': AxisItem(orientation='top', linkView=self.vb), 'pos': (1, 1)},
'bottom': {'item': AxisItem(orientation='bottom', linkView=self.vb), 'pos': (3, 1)},
'left': {'item': AxisItem(orientation='left', linkView=self.vb), 'pos': (2, 0)},
'right': {'item': AxisItem(orientation='right', linkView=self.vb), 'pos': (2, 2)}
}
for k in self.scales:
item = self.scales[k]['item']
self.layout.addItem(item, *self.scales[k]['pos'])
item.setZValue(-1000)
item.setFlag(item.ItemNegativeZStacksBehindParent)
## Create and place axis items
if axisItems is None:
axisItems = {}
self.axes = {}
for k, pos in (('top', (1,1)), ('bottom', (3,1)), ('left', (2,0)), ('right', (2,2))):
axis = axisItems.get(k, AxisItem(orientation=k))
axis.linkToView(self.vb)
self.axes[k] = {'item': axis, 'pos': pos}
self.layout.addItem(axis, *pos)
axis.setZValue(-1000)
axis.setFlag(axis.ItemNegativeZStacksBehindParent)
self.titleLabel = LabelItem('', size='11pt')
self.layout.addItem(self.titleLabel, 0, 1)
@ -193,7 +189,6 @@ class PlotItem(GraphicsWidget):
'setXRange', 'setYRange', 'setXLink', 'setYLink', 'setAutoPan', 'setAutoVisible',
'setRange', 'autoRange', 'viewRect', 'viewRange', 'setMouseEnabled',
'enableAutoRange', 'disableAutoRange', 'setAspectLocked',
'setMenuEnabled', 'menuEnabled',
'register', 'unregister']: ## NOTE: If you update this list, please update the class docstring as well.
setattr(self, m, getattr(self.vb, m))
@ -233,45 +228,12 @@ class PlotItem(GraphicsWidget):
self.subMenus.append(sm)
self.ctrlMenu.addMenu(sm)
## exporting is handled by GraphicsScene now
#exportOpts = collections.OrderedDict([
#('SVG - Full Plot', self.saveSvgClicked),
#('SVG - Curves Only', self.saveSvgCurvesClicked),
#('Image', self.saveImgClicked),
#('CSV', self.saveCsvClicked),
#])
#self.vb.menu.setExportMethods(exportOpts)
#if HAVE_WIDGETGROUP:
self.stateGroup = WidgetGroup()
for name, w in menuItems:
self.stateGroup.autoAdd(w)
self.fileDialog = None
#self.xLinkPlot = None
#self.yLinkPlot = None
#self.linksBlocked = False
#self.setAcceptHoverEvents(True)
## Connect control widgets
#c.xMinText.editingFinished.connect(self.setManualXScale)
#c.xMaxText.editingFinished.connect(self.setManualXScale)
#c.yMinText.editingFinished.connect(self.setManualYScale)
#c.yMaxText.editingFinished.connect(self.setManualYScale)
#c.xManualRadio.clicked.connect(lambda: self.updateXScale())
#c.yManualRadio.clicked.connect(lambda: self.updateYScale())
#c.xAutoRadio.clicked.connect(self.updateXScale)
#c.yAutoRadio.clicked.connect(self.updateYScale)
#c.xAutoPercentSpin.valueChanged.connect(self.replot)
#c.yAutoPercentSpin.valueChanged.connect(self.replot)
c.alphaGroup.toggled.connect(self.updateAlpha)
c.alphaSlider.valueChanged.connect(self.updateAlpha)
c.autoAlphaCheck.toggled.connect(self.updateAlpha)
@ -283,13 +245,6 @@ class PlotItem(GraphicsWidget):
c.fftCheck.toggled.connect(self.updateSpectrumMode)
c.logXCheck.toggled.connect(self.updateLogMode)
c.logYCheck.toggled.connect(self.updateLogMode)
#c.saveSvgBtn.clicked.connect(self.saveSvgClicked)
#c.saveSvgCurvesBtn.clicked.connect(self.saveSvgCurvesClicked)
#c.saveImgBtn.clicked.connect(self.saveImgClicked)
#c.saveCsvBtn.clicked.connect(self.saveCsvClicked)
#self.ctrl.xLinkCombo.currentIndexChanged.connect(self.xLinkComboChanged)
#self.ctrl.yLinkCombo.currentIndexChanged.connect(self.yLinkComboChanged)
c.downsampleSpin.valueChanged.connect(self.updateDownsampling)
@ -298,24 +253,15 @@ class PlotItem(GraphicsWidget):
self.ctrl.maxTracesCheck.toggled.connect(self.updateDecimation)
self.ctrl.maxTracesSpin.valueChanged.connect(self.updateDecimation)
#c.xMouseCheck.toggled.connect(self.mouseCheckChanged)
#c.yMouseCheck.toggled.connect(self.mouseCheckChanged)
#self.xLinkPlot = None
#self.yLinkPlot = None
#self.linksBlocked = False
self.manager = None
self.hideAxis('right')
self.hideAxis('top')
self.showAxis('left')
self.showAxis('bottom')
#if name is not None:
#self.registerPlot(name)
if labels is None:
labels = {}
for label in list(self.scales.keys()):
for label in list(self.axes.keys()):
if label in kargs:
labels[label] = kargs[label]
del kargs[label]
@ -330,15 +276,16 @@ class PlotItem(GraphicsWidget):
if len(kargs) > 0:
self.plot(**kargs)
#self.enableAutoRange()
def implements(self, interface=None):
return interface in ['ViewBoxWrapper']
def getViewBox(self):
"""Return the ViewBox within."""
"""Return the :class:`ViewBox <pyqtgraph.ViewBox>` contained within."""
return self.vb
def setLogMode(self, x, y):
"""
Set log scaling for x and y axes.
@ -399,11 +346,11 @@ class PlotItem(GraphicsWidget):
#self.autoBtn.setParent(None)
#self.autoBtn = None
for k in self.scales:
i = self.scales[k]['item']
for k in self.axes:
i = self.axes[k]['item']
i.close()
self.scales = None
self.axes = None
self.scene().removeItem(self.vb)
self.vb = None
@ -431,47 +378,6 @@ class PlotItem(GraphicsWidget):
def registerPlot(self, name): ## for backward compatibility
self.vb.register(name)
#self.name = name
#win = str(self.window())
##print "register", name, win
#if win not in PlotItem.managers:
#PlotItem.managers[win] = PlotWidgetManager()
#self.manager = PlotItem.managers[win]
#self.manager.addWidget(self, name)
##QtCore.QObject.connect(self.manager, QtCore.SIGNAL('widgetListChanged'), self.updatePlotList)
#self.manager.sigWidgetListChanged.connect(self.updatePlotList)
#self.updatePlotList()
#def updatePlotList(self):
#"""Update the list of all plotWidgets in the "link" combos"""
##print "update plot list", self
#try:
#for sc in [self.ctrl.xLinkCombo, self.ctrl.yLinkCombo]:
#current = unicode(sc.currentText())
#sc.blockSignals(True)
#try:
#sc.clear()
#sc.addItem("")
#if self.manager is not None:
#for w in self.manager.listWidgets():
##print w
#if w == self.name:
#continue
#sc.addItem(w)
#if w == current:
#sc.setCurrentIndex(sc.count()-1)
#finally:
#sc.blockSignals(False)
#if unicode(sc.currentText()) != current:
#sc.currentItemChanged.emit()
#except:
#import gc
#refs= gc.get_referrers(self)
#print " error during update of", self
#print " Referrers are:", refs
#raise
def updateGrid(self, *args):
alpha = self.ctrl.gridAlphaSlider.value()
@ -492,91 +398,6 @@ class PlotItem(GraphicsWidget):
return wr
#def viewRangeChanged(self, vb, range):
##self.emit(QtCore.SIGNAL('viewChanged'), *args)
#self.sigRangeChanged.emit(self, range)
#def blockLink(self, b):
#self.linksBlocked = b
#def xLinkComboChanged(self):
#self.setXLink(str(self.ctrl.xLinkCombo.currentText()))
#def yLinkComboChanged(self):
#self.setYLink(str(self.ctrl.yLinkCombo.currentText()))
#def setXLink(self, plot=None):
#"""Link this plot's X axis to another plot (pass either the PlotItem/PlotWidget or the registered name of the plot)"""
#if isinstance(plot, basestring):
#if self.manager is None:
#return
#if self.xLinkPlot is not None:
#self.manager.unlinkX(self, self.xLinkPlot)
#plot = self.manager.getWidget(plot)
#if not isinstance(plot, PlotItem) and hasattr(plot, 'getPlotItem'):
#plot = plot.getPlotItem()
#self.xLinkPlot = plot
#if plot is not None:
#self.setManualXScale()
#self.manager.linkX(self, plot)
#def setYLink(self, plot=None):
#"""Link this plot's Y axis to another plot (pass either the PlotItem/PlotWidget or the registered name of the plot)"""
#if isinstance(plot, basestring):
#if self.manager is None:
#return
#if self.yLinkPlot is not None:
#self.manager.unlinkY(self, self.yLinkPlot)
#plot = self.manager.getWidget(plot)
#if not isinstance(plot, PlotItem) and hasattr(plot, 'getPlotItem'):
#plot = plot.getPlotItem()
#self.yLinkPlot = plot
#if plot is not None:
#self.setManualYScale()
#self.manager.linkY(self, plot)
#def linkXChanged(self, plot):
#"""Called when a linked plot has changed its X scale"""
##print "update from", plot
#if self.linksBlocked:
#return
#pr = plot.vb.viewRect()
#pg = plot.viewGeometry()
#if pg is None:
##print " return early"
#return
#sg = self.viewGeometry()
#upp = float(pr.width()) / pg.width()
#x1 = pr.left() + (sg.x()-pg.x()) * upp
#x2 = x1 + sg.width() * upp
#plot.blockLink(True)
#self.setManualXScale()
#self.setXRange(x1, x2, padding=0)
#plot.blockLink(False)
#self.replot()
#def linkYChanged(self, plot):
#"""Called when a linked plot has changed its Y scale"""
#if self.linksBlocked:
#return
#pr = plot.vb.viewRect()
#pg = plot.vb.boundingRect()
#sg = self.vb.boundingRect()
#upp = float(pr.height()) / pg.height()
#y1 = pr.bottom() + (sg.y()-pg.y()) * upp
#y2 = y1 + sg.height() * upp
#plot.blockLink(True)
#self.setManualYScale()
#self.setYRange(y1, y2, padding=0)
#plot.blockLink(False)
#self.replot()
def avgToggled(self, b):
if b:
self.recomputeAverages()
@ -650,50 +471,6 @@ class PlotItem(GraphicsWidget):
else:
plot.setData(x, y)
#def mouseCheckChanged(self):
#state = [self.ctrl.xMouseCheck.isChecked(), self.ctrl.yMouseCheck.isChecked()]
#self.vb.setMouseEnabled(*state)
#def xRangeChanged(self, _, range):
#if any(np.isnan(range)) or any(np.isinf(range)):
#raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
#self.ctrl.xMinText.setText('%0.5g' % range[0])
#self.ctrl.xMaxText.setText('%0.5g' % range[1])
### automatically change unit scale
#maxVal = max(abs(range[0]), abs(range[1]))
#(scale, prefix) = fn.siScale(maxVal)
##for l in ['top', 'bottom']:
##if self.getLabel(l).isVisible():
##self.setLabel(l, unitPrefix=prefix)
##self.getScale(l).setScale(scale)
##else:
##self.setLabel(l, unitPrefix='')
##self.getScale(l).setScale(1.0)
##self.emit(QtCore.SIGNAL('xRangeChanged'), self, range)
#self.sigXRangeChanged.emit(self, range)
#def yRangeChanged(self, _, range):
#if any(np.isnan(range)) or any(np.isinf(range)):
#raise Exception("yRange invalid: %s. Signal came from %s" % (str(range), str(self.sender())))
#self.ctrl.yMinText.setText('%0.5g' % range[0])
#self.ctrl.yMaxText.setText('%0.5g' % range[1])
### automatically change unit scale
#maxVal = max(abs(range[0]), abs(range[1]))
#(scale, prefix) = fn.siScale(maxVal)
##for l in ['left', 'right']:
##if self.getLabel(l).isVisible():
##self.setLabel(l, unitPrefix=prefix)
##self.getScale(l).setScale(scale)
##else:
##self.setLabel(l, unitPrefix='')
##self.getScale(l).setScale(1.0)
##self.emit(QtCore.SIGNAL('yRangeChanged'), self, range)
#self.sigYRangeChanged.emit(self, range)
def autoBtnClicked(self):
if self.autoBtn.mode == 'auto':
self.enableAutoRange()
@ -706,72 +483,6 @@ class PlotItem(GraphicsWidget):
"""
print("Warning: enableAutoScale is deprecated. Use enableAutoRange(axis, enable) instead.")
self.vb.enableAutoRange(self.vb.XYAxes)
#self.ctrl.xAutoRadio.setChecked(True)
#self.ctrl.yAutoRadio.setChecked(True)
#self.autoBtn.setImageFile(self.lockImageFile)
#self.autoBtn.mode = 'lock'
#self.updateXScale()
#self.updateYScale()
#self.replot()
#def updateXScale(self):
#"""Set plot to autoscale or not depending on state of radio buttons"""
#if self.ctrl.xManualRadio.isChecked():
#self.setManualXScale()
#else:
#self.setAutoXScale()
#self.replot()
#def updateYScale(self, b=False):
#"""Set plot to autoscale or not depending on state of radio buttons"""
#if self.ctrl.yManualRadio.isChecked():
#self.setManualYScale()
#else:
#self.setAutoYScale()
#self.replot()
#def enableManualScale(self, v=[True, True]):
#if v[0]:
#self.autoScale[0] = False
#self.ctrl.xManualRadio.setChecked(True)
##self.setManualXScale()
#if v[1]:
#self.autoScale[1] = False
#self.ctrl.yManualRadio.setChecked(True)
##self.setManualYScale()
##self.autoBtn.enable()
#self.autoBtn.setImageFile(self.autoImageFile)
#self.autoBtn.mode = 'auto'
##self.replot()
#def setManualXScale(self):
#self.autoScale[0] = False
#x1 = float(self.ctrl.xMinText.text())
#x2 = float(self.ctrl.xMaxText.text())
#self.ctrl.xManualRadio.setChecked(True)
#self.setXRange(x1, x2, padding=0)
#self.autoBtn.show()
##self.replot()
#def setManualYScale(self):
#self.autoScale[1] = False
#y1 = float(self.ctrl.yMinText.text())
#y2 = float(self.ctrl.yMaxText.text())
#self.ctrl.yManualRadio.setChecked(True)
#self.setYRange(y1, y2, padding=0)
#self.autoBtn.show()
##self.replot()
#def setAutoXScale(self):
#self.autoScale[0] = True
#self.ctrl.xAutoRadio.setChecked(True)
##self.replot()
#def setAutoYScale(self):
#self.autoScale[1] = True
#self.ctrl.yAutoRadio.setChecked(True)
##self.replot()
def addItem(self, item, *args, **kargs):
"""
@ -867,17 +578,6 @@ class PlotItem(GraphicsWidget):
"""
#if y is not None:
#data = y
#if data2 is not None:
#x = data
#data = data2
#if decimate is not None and decimate > 1:
#data = data[::decimate]
#if x is not None:
#x = x[::decimate]
## print 'plot with decimate = %d' % (decimate)
clear = kargs.get('clear', False)
params = kargs.get('params', None)
@ -888,23 +588,7 @@ class PlotItem(GraphicsWidget):
if params is None:
params = {}
#if HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')):
#curve = self._plotMetaArray(data, x=x, **kargs)
#elif isinstance(data, np.ndarray):
#curve = self._plotArray(data, x=x, **kargs)
#elif isinstance(data, list):
#if x is not None:
#x = np.array(x)
#curve = self._plotArray(np.array(data), x=x, **kargs)
#elif data is None:
#curve = PlotCurveItem(**kargs)
#else:
#raise Exception('Not sure how to plot object of type %s' % type(data))
#print data, curve
self.addItem(item, params=params)
#if pen is not None:
#curve.setPen(fn.mkPen(pen))
return item
@ -922,80 +606,34 @@ class PlotItem(GraphicsWidget):
del kargs['size']
return self.plot(*args, **kargs)
#sp = ScatterPlotItem(*args, **kargs)
#self.addItem(sp)
#return sp
#def plotChanged(self, curve=None):
## Recompute auto range if needed
#args = {}
#for ax in [0, 1]:
#print "range", ax
#if self.autoScale[ax]:
#percentScale = [self.ctrl.xAutoPercentSpin.value(), self.ctrl.yAutoPercentSpin.value()][ax] * 0.01
#mn = None
#mx = None
#for c in self.curves + [c[1] for c in self.avgCurves.values()] + self.dataItems:
#if not c.isVisible():
#continue
#cmn, cmx = c.getRange(ax, percentScale)
##print " ", c, cmn, cmx
#if mn is None or cmn < mn:
#mn = cmn
#if mx is None or cmx > mx:
#mx = cmx
#if mn is None or mx is None or any(np.isnan([mn, mx])) or any(np.isinf([mn, mx])):
#continue
#if mn == mx:
#mn -= 1
#mx += 1
#if ax == 0:
#args['xRange'] = [mn, mx]
#else:
#args['yRange'] = [mn, mx]
#if len(args) > 0:
##print args
#self.setRange(**args)
def replot(self):
#self.plotChanged()
self.update()
def updateParamList(self):
self.ctrl.avgParamList.clear()
## Check to see that each parameter for each curve is present in the list
#print "\nUpdate param list", self
#print "paramList:", self.paramList
for c in self.curves:
#print " curve:", c
for p in list(self.itemMeta.get(c, {}).keys()):
#print " param:", p
if type(p) is tuple:
p = '.'.join(p)
## If the parameter is not in the list, add it.
matches = self.ctrl.avgParamList.findItems(p, QtCore.Qt.MatchExactly)
#print " matches:", matches
if len(matches) == 0:
i = QtGui.QListWidgetItem(p)
if p in self.paramList and self.paramList[p] is True:
#print " set checked"
i.setCheckState(QtCore.Qt.Checked)
else:
#print " set unchecked"
i.setCheckState(QtCore.Qt.Unchecked)
self.ctrl.avgParamList.addItem(i)
else:
i = matches[0]
self.paramList[p] = (i.checkState() == QtCore.Qt.Checked)
#print "paramList:", self.paramList
## This is bullshit.
## Qt's SVG-writing capabilities are pretty terrible.
def writeSvgCurves(self, fileName=None):
if fileName is None:
self.fileDialog = FileDialog()
@ -1190,18 +828,12 @@ class PlotItem(GraphicsWidget):
def saveState(self):
#if not HAVE_WIDGETGROUP:
#raise Exception("State save/restore requires WidgetGroup class.")
state = self.stateGroup.state()
state['paramList'] = self.paramList.copy()
state['view'] = self.vb.getState()
#print "\nSAVE %s:\n" % str(self.name), state
#print "Saving state. averageGroup.isChecked(): %s state: %s" % (str(self.ctrl.averageGroup.isChecked()), str(state['averageGroup']))
return state
def restoreState(self, state):
#if not HAVE_WIDGETGROUP:
#raise Exception("State save/restore requires WidgetGroup class.")
if 'paramList' in state:
self.paramList = state['paramList'].copy()
@ -1218,8 +850,6 @@ class PlotItem(GraphicsWidget):
state['yGridCheck'] = state['gridGroup']
self.stateGroup.setState(state)
#self.updateXScale()
#self.updateYScale()
self.updateParamList()
if 'view' not in state:
@ -1232,13 +862,6 @@ class PlotItem(GraphicsWidget):
}
self.vb.setState(state['view'])
#print "\nRESTORE %s:\n" % str(self.name), state
#print "Restoring state. averageGroup.isChecked(): %s state: %s" % (str(self.ctrl.averageGroup.isChecked()), str(state['averageGroup']))
#avg = self.ctrl.averageGroup.isChecked()
#if avg != state['averageGroup']:
#print " WARNING: avgGroup is %s, should be %s" % (str(avg), str(state['averageGroup']))
def widgetGroupInterface(self):
return (None, PlotItem.saveState, PlotItem.restoreState)
@ -1269,8 +892,6 @@ class PlotItem(GraphicsWidget):
for c in self.curves:
c.setDownsampling(ds)
self.recomputeAverages()
#for c in self.avgCurves.values():
#c[1].setDownsampling(ds)
def downsampleMode(self):
@ -1306,8 +927,6 @@ class PlotItem(GraphicsWidget):
(alpha, auto) = self.alphaState()
for c in self.curves:
c.setAlpha(alpha**2, auto)
#self.replot(autoRange=False)
def alphaState(self):
enabled = self.ctrl.alphaGroup.isChecked()
@ -1330,9 +949,6 @@ class PlotItem(GraphicsWidget):
mode = False
return mode
#def wheelEvent(self, ev):
## disables default panning the whole scene by mousewheel
#ev.accept()
def resizeEvent(self, ev):
if self.autoBtn is None: ## already closed down
@ -1340,29 +956,42 @@ class PlotItem(GraphicsWidget):
btnRect = self.mapRectFromItem(self.autoBtn, self.autoBtn.boundingRect())
y = self.size().height() - btnRect.height()
self.autoBtn.setPos(0, y)
#def hoverMoveEvent(self, ev):
#self.mousePos = ev.pos()
#self.mouseScreenPos = ev.screenPos()
#def ctrlBtnClicked(self):
#self.ctrlMenu.popup(self.mouseScreenPos)
def getMenu(self):
return self.ctrlMenu
def getContextMenus(self, event):
## called when another item is displaying its context menu; we get to add extras to the end of the menu.
return self.ctrlMenu
if self.menuEnabled():
return self.ctrlMenu
else:
return None
def setMenuEnabled(self, enableMenu=True, enableViewBoxMenu='same'):
"""
Enable or disable the context menu for this PlotItem.
By default, the ViewBox's context menu will also be affected.
(use enableViewBoxMenu=None to leave the ViewBox unchanged)
"""
self._menuEnabled = enableMenu
if enableViewBoxMenu is None:
return
if enableViewBoxMenu is 'same':
enableViewBoxMenu = enableMenu
self.vb.setMenuEnabled(enableViewBoxMenu)
def menuEnabled(self):
return self._menuEnabled
def getLabel(self, key):
pass
def _checkScaleKey(self, key):
if key not in self.scales:
raise Exception("Scale '%s' not found. Scales are: %s" % (key, str(list(self.scales.keys()))))
if key not in self.axes:
raise Exception("Scale '%s' not found. Scales are: %s" % (key, str(list(self.axes.keys()))))
def getScale(self, key):
return self.getAxis(key)
@ -1371,7 +1000,7 @@ class PlotItem(GraphicsWidget):
"""Return the specified AxisItem.
*name* should be 'left', 'bottom', 'top', or 'right'."""
self._checkScaleKey(name)
return self.scales[name]['item']
return self.axes[name]['item']
def setLabel(self, axis, text=None, units=None, unitPrefix=None, **args):
"""
@ -1417,7 +1046,7 @@ class PlotItem(GraphicsWidget):
axis must be one of 'left', 'bottom', 'right', or 'top'
"""
s = self.getScale(axis)
p = self.scales[axis]['pos']
p = self.axes[axis]['pos']
if show:
s.show()
else:
@ -1454,7 +1083,6 @@ class PlotItem(GraphicsWidget):
## create curve
try:
xv = arr.xvals(0)
#print 'xvals:', xv
except:
if x is None:
xv = np.arange(arr.shape[0])
@ -1474,17 +1102,6 @@ class PlotItem(GraphicsWidget):
return c
#def saveSvgClicked(self):
#self.writeSvg()
#def saveSvgCurvesClicked(self):
#self.writeSvgCurves()
#def saveImgClicked(self):
#self.writeImage()
#def saveCsvClicked(self):
#self.writeCsv()
def setExportMode(self, export, opts):
if export:
@ -1492,63 +1109,3 @@ class PlotItem(GraphicsWidget):
else:
self.autoBtn.show()
#class PlotWidgetManager(QtCore.QObject):
#sigWidgetListChanged = QtCore.Signal(object)
#"""Used for managing communication between PlotWidgets"""
#def __init__(self):
#QtCore.QObject.__init__(self)
#self.widgets = weakref.WeakValueDictionary() # Don't keep PlotWidgets around just because they are listed here
#def addWidget(self, w, name):
#self.widgets[name] = w
##self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
#self.sigWidgetListChanged.emit(self.widgets.keys())
#def removeWidget(self, name):
#if name in self.widgets:
#del self.widgets[name]
##self.emit(QtCore.SIGNAL('widgetListChanged'), self.widgets.keys())
#self.sigWidgetListChanged.emit(self.widgets.keys())
#else:
#print "plot %s not managed" % name
#def listWidgets(self):
#return self.widgets.keys()
#def getWidget(self, name):
#if name not in self.widgets:
#return None
#else:
#return self.widgets[name]
#def linkX(self, p1, p2):
##QtCore.QObject.connect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
#p1.sigXRangeChanged.connect(p2.linkXChanged)
##QtCore.QObject.connect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
#p2.sigXRangeChanged.connect(p1.linkXChanged)
#p1.linkXChanged(p2)
##p2.setManualXScale()
#def unlinkX(self, p1, p2):
##QtCore.QObject.disconnect(p1, QtCore.SIGNAL('xRangeChanged'), p2.linkXChanged)
#p1.sigXRangeChanged.disconnect(p2.linkXChanged)
##QtCore.QObject.disconnect(p2, QtCore.SIGNAL('xRangeChanged'), p1.linkXChanged)
#p2.sigXRangeChanged.disconnect(p1.linkXChanged)
#def linkY(self, p1, p2):
##QtCore.QObject.connect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
#p1.sigYRangeChanged.connect(p2.linkYChanged)
##QtCore.QObject.connect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
#p2.sigYRangeChanged.connect(p1.linkYChanged)
#p1.linkYChanged(p2)
##p2.setManualYScale()
#def unlinkY(self, p1, p2):
##QtCore.QObject.disconnect(p1, QtCore.SIGNAL('yRangeChanged'), p2.linkYChanged)
#p1.sigYRangeChanged.disconnect(p2.linkYChanged)
##QtCore.QObject.disconnect(p2, QtCore.SIGNAL('yRangeChanged'), p1.linkYChanged)
#p2.sigYRangeChanged.disconnect(p1.linkYChanged)

View File

@ -62,7 +62,7 @@ class ViewBox(GraphicsWidget):
NamedViews = weakref.WeakValueDictionary() # name: ViewBox
AllViews = weakref.WeakKeyDictionary() # ViewBox: None
def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, enableMenu = True, name=None):
def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, enableMenu=True, name=None):
"""
============= =============================================================
**Arguments**
@ -136,7 +136,7 @@ class ViewBox(GraphicsWidget):
## Make scale box that is shown when dragging on the view
self.rbScaleBox = QtGui.QGraphicsRectItem(0, 0, 1, 1)
self.rbScaleBox.setPen(fn.mkPen((255,0,0), width=1))
self.rbScaleBox.setPen(fn.mkPen((255,255,100), width=1))
self.rbScaleBox.setBrush(fn.mkBrush(255,255,0,100))
self.rbScaleBox.hide()
self.addItem(self.rbScaleBox)
@ -358,7 +358,7 @@ class ViewBox(GraphicsWidget):
changes[1] = yRange
if len(changes) == 0:
print rect
print(rect)
raise Exception("Must specify at least one of rect, xRange, or yRange. (gave rect=%s)" % str(type(rect)))
changed = [False, False]
@ -863,7 +863,10 @@ class ViewBox(GraphicsWidget):
return self._menuCopy
def getContextMenus(self, event):
return self.menu.subMenus()
if self.menuEnabled():
return self.menu.subMenus()
else:
return None
#return [self.getMenu(event)]

View File

@ -41,6 +41,8 @@ class PlotWidget(GraphicsView):
other methods, use :func:`getPlotItem <pyqtgraph.PlotWidget.getPlotItem>`.
"""
def __init__(self, parent=None, **kargs):
"""When initializing PlotWidget, all keyword arguments except *parent* are passed
to :func:`PlotItem.__init__() <pyqtgraph.PlotItem.__init__>`."""
GraphicsView.__init__(self, parent)
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
self.enableMouse(False)