From ad7b5f0aad55c5fca68ff6620cf4719de968dd89 Mon Sep 17 00:00:00 2001
From: Luke Campagnola <>
Date: Fri, 29 Jun 2012 14:39:27 -0400
Subject: [PATCH] - Default foreground / background colors can now be set using
pyqtgraph.setConfigOption() - Added pyqtgraph.systemInfo() for bug reporting
- GraphicsLayout does a better job of avoiding occupied cells when using
automatic placement - Fixed sizing issues with LabelItem - Updated
GraphicsLayout example
---
Qt.py | 27 ++++++----
__init__.py | 22 ++++++--
examples/GraphicsLayout.py | 68 +++++++++++++++++-------
graphicsItems/AxisItem.py | 60 +++++++++++++++------
graphicsItems/GradientEditorItem.py | 8 +--
graphicsItems/GraphicsLayout.py | 49 +++++++++++------
graphicsItems/HistogramLUTItem.py | 2 +-
graphicsItems/LabelItem.py | 71 +++++++++++++++++--------
graphicsItems/ViewBox/ViewBox.py | 21 +++++++-
widgets/GradientWidget.py | 4 +-
widgets/GraphicsView.py | 82 +++++++++++++++++++++--------
widgets/HistogramLUTWidget.py | 2 +-
widgets/RemoteGraphicsView.py | 20 +++----
13 files changed, 306 insertions(+), 130 deletions(-)
diff --git a/Qt.py b/Qt.py
index 89bf00d6..349721ab 100644
--- a/Qt.py
+++ b/Qt.py
@@ -1,15 +1,20 @@
## Do all Qt imports from here to allow easier PyQt / PySide compatibility
-#from PySide import QtGui, QtCore, QtOpenGL, QtSvg
-from PyQt4 import QtGui, QtCore
-try:
- from PyQt4 import QtSvg
-except ImportError:
- pass
-try:
- from PyQt4 import QtOpenGL
-except ImportError:
- pass
+USE_PYSIDE = False ## If False, import PyQt4. If True, import PySide
+
+if USE_PYSIDE:
+ from PySide import QtGui, QtCore, QtOpenGL, QtSvg
+ VERSION_INFO = 'PySide ' + PySide.__version__
+else:
+ from PyQt4 import QtGui, QtCore
+ try:
+ from PyQt4 import QtSvg
+ except ImportError:
+ pass
+ try:
+ from PyQt4 import QtOpenGL
+ except ImportError:
+ pass
-if not hasattr(QtCore, 'Signal'):
QtCore.Signal = QtCore.pyqtSignal
+ VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
diff --git a/__init__.py b/__init__.py
index 51a0fe5c..039188c1 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
+REVISION = '621'
+
### import all the goodies and add some helper functions for easy CLI use
## 'Qt' is a local module; it is intended mainly to cover up the differences
## between PyQt4 and PySide.
-from .Qt import QtGui
+from .Qt import QtGui
## not really safe--If we accidentally create another QApplication, the process hangs (and it is very difficult to trace the cause)
#if QtGui.QApplication.instance() is None:
@@ -30,13 +32,15 @@ else:
useOpenGL = False ## on windows there's a more even performance / bugginess tradeoff.
CONFIG_OPTIONS = {
- 'useOpenGL': useOpenGL, ## by default, this is platform-dependent (see widgets/GraphicsView). Set to True or False to explicitly enable/disable opengl.
+ 'useOpenGL': useOpenGL, ## by default, this is platform-dependent (see widgets/GraphicsView). Set to True or False to explicitly enable/disable opengl.
'leftButtonPan': True, ## if false, left button drags a rubber band for zooming in viewbox
- 'foregroundColor': (200,200,200),
- 'backgroundColor': (0,0,0),
+ 'foreground': (150, 150, 150), ## default foreground color for axes, labels, etc.
+ 'background': (0, 0, 0), ## default background for GraphicsWidget
'antialias': False,
+ 'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets
}
+
def setConfigOption(opt, value):
CONFIG_OPTIONS[opt] = value
@@ -44,6 +48,16 @@ def getConfigOption(opt):
return CONFIG_OPTIONS[opt]
+def systemInfo():
+ print "sys.platform:", sys.platform
+ print "sys.version:", sys.version
+ from .Qt import VERSION_INFO
+ print "qt bindings:", VERSION_INFO
+ print "pyqtgraph:", REVISION
+ print "config:"
+ import pprint
+ pprint.pprint(CONFIG_OPTIONS)
+
## Rename orphaned .pyc files. This is *probably* safe :)
def renamePyc(startDir):
diff --git a/examples/GraphicsLayout.py b/examples/GraphicsLayout.py
index 0602dd87..c8b4160f 100644
--- a/examples/GraphicsLayout.py
+++ b/examples/GraphicsLayout.py
@@ -4,41 +4,73 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
-import user
+import numpy as np
app = QtGui.QApplication([])
view = pg.GraphicsView()
-l = pg.GraphicsLayout(border=pg.mkPen(0, 0, 255))
+l = pg.GraphicsLayout(border=(100,100,100))
view.setCentralItem(l)
view.show()
+view.resize(800,600)
+
+## Title at top
+text = """
+This example demonstrates the use of GraphicsLayout to arrange items in a grid.
+The items added to the layout must be subclasses of QGraphicsWidget (this includes
+PlotItem, ViewBox, LabelItem, and GrphicsLayout itself).
+"""
+l.addLabel(text, col=1, colspan=4)
+l.nextRow()
+
+## Put vertical label on left side
+l.addLabel('Long Vertical Label', angle=-90, rowspan=3)
## Add 3 plots into the first row (automatic position)
-p1 = l.addPlot()
-p2 = l.addPlot()
-p3 = l.addPlot()
+p1 = l.addPlot(title="Plot 1")
+p2 = l.addPlot(title="Plot 2")
+vb = l.addViewBox(lockAspect=True)
+img = pg.ImageItem(np.random.normal(size=(100,100)))
+vb.addItem(img)
+vb.autoRange()
-## Add a viewbox into the second row (automatic position)
+
+## Add a sub-layout into the second row (automatic position)
+## The added item should avoid the first column, which is already filled
l.nextRow()
-vb = l.addViewBox(colspan=3)
+l2 = l.addLayout(colspan=3, border=(50,0,0))
+l2.setContentsMargins(10, 10, 10, 10)
+l2.addLabel("Sub-layout: this layout demonstrates the use of shared axes and axis labels", colspan=3)
+l2.nextRow()
+l2.addLabel('Vertical Axis Label', angle=-90, rowspan=2)
+p21 = l2.addPlot()
+p22 = l2.addPlot()
+l2.nextRow()
+p23 = l2.addPlot()
+p24 = l2.addPlot()
+l2.nextRow()
+l2.addLabel("HorizontalAxisLabel", col=1, colspan=2)
+
+## hide axes on some plots
+p21.hideAxis('bottom')
+p22.hideAxis('bottom')
+p22.hideAxis('left')
+p24.hideAxis('left')
+p21.hideButtons()
+p22.hideButtons()
+p23.hideButtons()
+p24.hideButtons()
+
## Add 2 more plots into the third row (manual position)
-p4 = l.addPlot(row=2, col=0)
-p5 = l.addPlot(row=2, col=1, colspan=2)
+p4 = l.addPlot(row=3, col=1)
+p5 = l.addPlot(row=3, col=2, colspan=2)
-
-
-## show some content
+## show some content in the plots
p1.plot([1,3,2,4,3,5])
p2.plot([1,3,2,4,3,5])
-p3.plot([1,3,2,4,3,5])
p4.plot([1,3,2,4,3,5])
p5.plot([1,3,2,4,3,5])
-b = QtGui.QGraphicsRectItem(0, 0, 1, 1)
-b.setPen(pg.mkPen(255,255,0))
-vb.addItem(b)
-vb.setRange(QtCore.QRectF(-1, -1, 3, 3))
-
## Start Qt event loop unless running in interactive mode.
diff --git a/graphicsItems/AxisItem.py b/graphicsItems/AxisItem.py
index ce2cb503..d6615748 100644
--- a/graphicsItems/AxisItem.py
+++ b/graphicsItems/AxisItem.py
@@ -4,6 +4,7 @@ from pyqtgraph.Point import Point
import pyqtgraph.debug as debug
import weakref
import pyqtgraph.functions as fn
+import pyqtgraph as pg
from .GraphicsWidget import GraphicsWidget
__all__ = ['AxisItem']
@@ -65,8 +66,6 @@ class AxisItem(GraphicsWidget):
self.setRange(0, 1)
- if pen is None:
- pen = QtGui.QPen(QtGui.QColor(100, 100, 100))
self.setPen(pen)
self._linkedView = None
@@ -189,8 +188,18 @@ class AxisItem(GraphicsWidget):
self.setMaximumWidth(w)
self.setMinimumWidth(w)
+ def pen(self):
+ if self._pen is None:
+ return fn.mkPen(pg.getConfigOption('foreground'))
+ return self._pen
+
def setPen(self, pen):
- self.pen = pen
+ """
+ Set the pen used for drawing text, axes, ticks, and grid lines.
+ if pen == None, the default will be used (see :func:`setConfigOption
+ `)
+ """
+ self._pen = pen
self.picture = None
self.update()
@@ -370,8 +379,6 @@ class AxisItem(GraphicsWidget):
"""
minVal, maxVal = sorted((minVal, maxVal))
- if self.logMode:
- return self.logTickValues(minVal, maxVal, size)
ticks = []
tickLevels = self.tickSpacing(minVal, maxVal, size)
@@ -391,18 +398,33 @@ class AxisItem(GraphicsWidget):
values = filter(lambda x: all(np.abs(allValues-x) > spacing*0.01), values)
allValues = np.concatenate([allValues, values])
ticks.append((spacing, values))
+
+ if self.logMode:
+ return self.logTickValues(minVal, maxVal, size, ticks)
+
return ticks
- def logTickValues(self, minVal, maxVal, size):
- v1 = int(np.floor(minVal))
- v2 = int(np.ceil(maxVal))
- major = list(range(v1+1, v2))
+ def logTickValues(self, minVal, maxVal, size, stdTicks):
- minor = []
- for v in range(v1, v2):
- minor.extend(v + np.log10(np.arange(1, 10)))
- minor = [x for x in minor if x>minVal and x= 1.0:
+ ticks.append((spacing, t))
+
+ if len(ticks) < 3:
+ v1 = int(np.floor(minVal))
+ v2 = int(np.ceil(maxVal))
+ #major = list(range(v1+1, v2))
+
+ minor = []
+ for v in range(v1, v2):
+ minor.extend(v + np.log10(np.arange(1, 10)))
+ minor = [x for x in minor if x>minVal and x`
Returns the created item.
+
+ To create a vertical label, use *angle*=-90
"""
text = LabelItem(text, **kargs)
self.addItem(text, row, col, rowspan, colspan)
@@ -89,18 +99,24 @@ class GraphicsLayout(GraphicsWidget):
if row is None:
row = self.currentRow
if col is None:
- col = self.nextCol(colspan)
+ col = self.currentCol
- if row not in self.rows:
- self.rows[row] = {}
- self.rows[row][col] = item
- self.items[item] = (row, col)
+ self.items[item] = []
+ for i in range(rowspan):
+ for j in range(colspan):
+ row2 = row + i
+ col2 = col + j
+ if row2 not in self.rows:
+ self.rows[row2] = {}
+ self.rows[row2][col2] = item
+ self.items[item].append((row2, col2))
self.layout.addItem(item, row, col, rowspan, colspan)
+ self.nextColumn()
def getItem(self, row, col):
- """Return the item in (*row*, *col*)"""
- return self.row[row][col]
+ """Return the item in (*row*, *col*). If the cell is empty, return None."""
+ return self.rows.get(row, {}).get(col, None)
def boundingRect(self):
return self.rect()
@@ -124,9 +140,10 @@ class GraphicsLayout(GraphicsWidget):
ind = self.itemIndex(item)
self.layout.removeAt(ind)
self.scene().removeItem(item)
- r,c = self.items[item]
+
+ for r,c in self.items[item]:
+ del self.rows[r][c]
del self.items[item]
- del self.rows[r][c]
self.update()
def clear(self):
diff --git a/graphicsItems/HistogramLUTItem.py b/graphicsItems/HistogramLUTItem.py
index 56730c3e..5a3b63d6 100644
--- a/graphicsItems/HistogramLUTItem.py
+++ b/graphicsItems/HistogramLUTItem.py
@@ -50,7 +50,7 @@ class HistogramLUTItem(GraphicsWidget):
self.layout.setSpacing(0)
self.vb = ViewBox()
self.vb.setMaximumWidth(152)
- self.vb.setMinimumWidth(52)
+ self.vb.setMinimumWidth(45)
self.vb.setMouseEnabled(x=False, y=True)
self.gradient = GradientEditorItem()
self.gradient.setOrientation('right')
diff --git a/graphicsItems/LabelItem.py b/graphicsItems/LabelItem.py
index 5ebbe739..17301fb3 100644
--- a/graphicsItems/LabelItem.py
+++ b/graphicsItems/LabelItem.py
@@ -1,5 +1,6 @@
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph.functions as fn
+import pyqtgraph as pg
from .GraphicsWidget import GraphicsWidget
@@ -18,14 +19,13 @@ class LabelItem(GraphicsWidget):
GraphicsWidget.__init__(self, parent)
self.item = QtGui.QGraphicsTextItem(self)
self.opts = {
- 'color': 'CCC',
+ 'color': None,
'justify': 'center'
}
self.opts.update(args)
- self.sizeHint = {}
+ self._sizeHint = {}
self.setText(text)
self.setAngle(angle)
-
def setAttr(self, attr, value):
"""Set default text properties. See setText() for accepted parameters."""
@@ -44,15 +44,17 @@ class LabelItem(GraphicsWidget):
==================== ==============================
"""
self.text = text
- opts = self.opts.copy()
+ opts = self.opts
for k in args:
opts[k] = args[k]
optlist = []
- if 'color' in opts:
- if isinstance(opts['color'], QtGui.QColor):
- opts['color'] = fn.colorStr(opts['color'])[:6]
- optlist.append('color: #' + opts['color'])
+
+ color = self.opts['color']
+ if color is None:
+ color = pg.getConfigOption('foreground')
+ color = fn.mkColor(color)
+ optlist.append('color: #' + fn.colorStr(color)[:6])
if 'size' in opts:
optlist.append('font-size: ' + opts['size'])
if 'bold' in opts and opts['bold'] in [True, False]:
@@ -64,7 +66,7 @@ class LabelItem(GraphicsWidget):
self.item.setHtml(full)
self.updateMin()
self.resizeEvent(None)
- self.update()
+ self.updateGeometry()
def resizeEvent(self, ev):
#c1 = self.boundingRect().center()
@@ -72,16 +74,35 @@ class LabelItem(GraphicsWidget):
#dif = c1 - c2
#self.item.moveBy(dif.x(), dif.y())
#print c1, c2, dif, self.item.pos()
+ self.item.setPos(0,0)
+ bounds = self.itemRect()
+ left = self.mapFromItem(self.item, QtCore.QPointF(0,0)) - self.mapFromItem(self.item, QtCore.QPointF(1,0))
+ rect = self.rect()
+
if self.opts['justify'] == 'left':
- self.item.setPos(0,0)
+ if left.x() != 0:
+ bounds.moveLeft(rect.left())
+ if left.y() < 0:
+ bounds.moveTop(rect.top())
+ elif left.y() > 0:
+ bounds.moveBottom(rect.bottom())
+
elif self.opts['justify'] == 'center':
- bounds = self.item.mapRectToParent(self.item.boundingRect())
- self.item.setPos(self.width()/2. - bounds.width()/2., 0)
+ bounds.moveCenter(rect.center())
+ #bounds = self.itemRect()
+ #self.item.setPos(self.width()/2. - bounds.width()/2., 0)
elif self.opts['justify'] == 'right':
- bounds = self.item.mapRectToParent(self.item.boundingRect())
- self.item.setPos(self.width() - bounds.width(), 0)
- #if self.width() > 0:
- #self.item.setTextWidth(self.width())
+ if left.x() != 0:
+ bounds.moveRight(rect.right())
+ if left.y() < 0:
+ bounds.moveBottom(rect.bottom())
+ elif left.y() > 0:
+ bounds.moveTop(rect.top())
+ #bounds = self.itemRect()
+ #self.item.setPos(self.width() - bounds.width(), 0)
+
+ self.item.setPos(bounds.topLeft() - self.itemRect().topLeft())
+ self.updateMin()
def setAngle(self, angle):
self.angle = angle
@@ -89,27 +110,31 @@ class LabelItem(GraphicsWidget):
self.item.rotate(angle)
self.updateMin()
+
def updateMin(self):
- bounds = self.item.mapRectToParent(self.item.boundingRect())
+ bounds = self.itemRect()
self.setMinimumWidth(bounds.width())
self.setMinimumHeight(bounds.height())
- self.sizeHint = {
+ self._sizeHint = {
QtCore.Qt.MinimumSize: (bounds.width(), bounds.height()),
QtCore.Qt.PreferredSize: (bounds.width(), bounds.height()),
QtCore.Qt.MaximumSize: (-1, -1), #bounds.width()*2, bounds.height()*2),
QtCore.Qt.MinimumDescent: (0, 0) ##?? what is this?
}
-
- self.update()
+ self.updateGeometry()
def sizeHint(self, hint, constraint):
- if hint not in self.sizeHint:
+ if hint not in self._sizeHint:
return QtCore.QSizeF(0, 0)
- return QtCore.QSizeF(*self.sizeHint[hint])
+ return QtCore.QSizeF(*self._sizeHint[hint])
+
+ def itemRect(self):
+ return self.item.mapRectToParent(self.item.boundingRect())
#def paint(self, p, *args):
#p.setPen(fn.mkPen('r'))
#p.drawRect(self.rect())
- #p.drawRect(self.item.boundingRect())
+ #p.setPen(fn.mkPen('g'))
+ #p.drawRect(self.itemRect())
diff --git a/graphicsItems/ViewBox/ViewBox.py b/graphicsItems/ViewBox/ViewBox.py
index eecc9bdd..45c0fe01 100644
--- a/graphicsItems/ViewBox/ViewBox.py
+++ b/graphicsItems/ViewBox/ViewBox.py
@@ -105,6 +105,8 @@ class ViewBox(GraphicsWidget):
'mouseMode': ViewBox.PanMode if pyqtgraph.getConfigOption('leftButtonPan') else ViewBox.RectMode,
'enableMenu': enableMenu,
'wheelScaleFactor': -1.0 / 8.0,
+
+ 'background': None,
}
@@ -118,11 +120,17 @@ class ViewBox(GraphicsWidget):
self.setFlag(self.ItemIsFocusable, True) ## so we can receive key presses
## childGroup is required so that ViewBox has local coordinates similar to device coordinates.
- ## this is a workaround for a Qt + OpenGL but that causes improper clipping
+ ## this is a workaround for a Qt + OpenGL bug that causes improper clipping
## https://bugreports.qt.nokia.com/browse/QTBUG-23723
self.childGroup = ChildGroup(self)
self.childGroup.sigItemsChanged.connect(self.itemsChanged)
+ self.background = QtGui.QGraphicsRectItem(self.rect())
+ self.background.setParentItem(self)
+ self.background.setZValue(-1e6)
+ self.background.setPen(fn.mkPen(None))
+ self.updateBackground()
+
#self.useLeftButtonPan = pyqtgraph.getConfigOption('leftButtonPan') # normally use left button to pan
# this also enables capture of keyPressEvents.
@@ -286,6 +294,7 @@ class ViewBox(GraphicsWidget):
#self.updateAutoRange()
self.updateMatrix()
self.sigStateChanged.emit(self)
+ self.background.setRect(self.rect())
#self.linkedXChanged()
#self.linkedYChanged()
@@ -1155,6 +1164,16 @@ class ViewBox(GraphicsWidget):
#self.scene().render(p)
#p.end()
+ def updateBackground(self):
+ bg = self.state['background']
+ #print self, bg
+ if bg is None:
+ self.background.hide()
+ else:
+ self.background.show()
+ self.background.setBrush(fn.mkBrush(bg))
+
+
def updateViewLists(self):
def cmpViews(a, b):
wins = 100 * cmp(a.window() is self.window(), b.window() is self.window())
diff --git a/widgets/GradientWidget.py b/widgets/GradientWidget.py
index 287a2635..35c6852d 100644
--- a/widgets/GradientWidget.py
+++ b/widgets/GradientWidget.py
@@ -15,7 +15,7 @@ class GradientWidget(GraphicsView):
def __init__(self, parent=None, orientation='bottom', *args, **kargs):
GraphicsView.__init__(self, parent, useOpenGL=False, background=None)
- self.maxDim = 27
+ self.maxDim = 31
kargs['tickPen'] = 'k'
self.item = GradientEditorItem(*args, **kargs)
self.item.sigGradientChanged.connect(self.sigGradientChanged)
@@ -24,7 +24,7 @@ class GradientWidget(GraphicsView):
self.setCacheMode(self.CacheNone)
self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)
self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain)
- self.setBackgroundRole(QtGui.QPalette.NoRole)
+ #self.setBackgroundRole(QtGui.QPalette.NoRole)
#self.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
#self.setAutoFillBackground(False)
#self.setAttribute(QtCore.Qt.WA_PaintOnScreen, False)
diff --git a/widgets/GraphicsView.py b/widgets/GraphicsView.py
index 83a7f91b..b3d2863f 100644
--- a/widgets/GraphicsView.py
+++ b/widgets/GraphicsView.py
@@ -6,6 +6,7 @@ Distributed under MIT/X11 license. See license.txt for more infomation.
"""
from pyqtgraph.Qt import QtCore, QtGui
+import pyqtgraph as pg
try:
from pyqtgraph.Qt import QtOpenGL
@@ -13,12 +14,8 @@ try:
except ImportError:
HAVE_OPENGL = False
-#from numpy import vstack
-#import time
from pyqtgraph.Point import Point
-#from vector import *
import sys, os
-#import debug
from .FileDialog import FileDialog
from pyqtgraph.GraphicsScene import GraphicsScene
import numpy as np
@@ -29,6 +26,20 @@ import pyqtgraph
__all__ = ['GraphicsView']
class GraphicsView(QtGui.QGraphicsView):
+ """Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the
+ viewed coordinate range. Also automatically creates a GraphicsScene and a central QGraphicsWidget
+ that is automatically scaled to the full view geometry.
+
+ This widget is the basis for :class:`PlotWidget `,
+ :class:`GraphicsLayoutWidget `, and the view widget in
+ :class:`ImageView `.
+
+ By default, the view coordinate system matches the widget's pixel coordinates and
+ automatically updates when the view is resized. This can be overridden by setting
+ autoPixelRange=False. The exact visible range can be set with setRange().
+
+ The view can be panned using the middle mouse button and scaled using the right mouse button if
+ enabled via enableMouse() (but ordinarily, we use ViewBox for this functionality)."""
sigRangeChanged = QtCore.Signal(object, object)
sigMouseReleased = QtCore.Signal(object)
@@ -37,17 +48,25 @@ class GraphicsView(QtGui.QGraphicsView):
sigScaleChanged = QtCore.Signal(object)
lastFileDir = None
- def __init__(self, parent=None, useOpenGL=None, background='k'):
- """Re-implementation of QGraphicsView that removes scrollbars and allows unambiguous control of the
- viewed coordinate range. Also automatically creates a QGraphicsScene and a central QGraphicsWidget
- that is automatically scaled to the full view geometry.
+ def __init__(self, parent=None, useOpenGL=None, background='default'):
+ """
+ ============ ============================================================
+ Arguments:
+ parent Optional parent widget
+ useOpenGL If True, the GraphicsView will use OpenGL to do all of its
+ rendering. This can improve performance on some systems,
+ but may also introduce bugs (the combination of
+ QGraphicsView and QGLWidget is still an 'experimental'
+ feature of Qt)
+ background Set the background color of the GraphicsView. Accepts any
+ single argument accepted by
+ :func:`mkColor `. By
+ default, the background color is determined using the
+ 'backgroundColor' configuration option (see
+ :func:`setConfigOption `.
+ ============ ============================================================
+ """
- By default, the view coordinate system matches the widget's pixel coordinates and
- automatically updates when the view is resized. This can be overridden by setting
- autoPixelRange=False. The exact visible range can be set with setRange().
-
- The view can be panned using the middle mouse button and scaled using the right mouse button if
- enabled via enableMouse() (but ordinarily, we use ViewBox for this functionality)."""
self.closed = False
QtGui.QGraphicsView.__init__(self, parent)
@@ -62,9 +81,7 @@ class GraphicsView(QtGui.QGraphicsView):
## This might help, but it's probably dangerous in the general case..
#self.setOptimizationFlag(self.DontSavePainterState, True)
- if background is not None:
- brush = fn.mkBrush(background)
- self.setBackgroundBrush(brush)
+ self.setBackground(background)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.setFrameShape(QtGui.QFrame.NoFrame)
@@ -98,7 +115,22 @@ class GraphicsView(QtGui.QGraphicsView):
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
self.clickAccepted = False
-
+ def setBackground(self, background):
+ """
+ Set the background color of the GraphicsView.
+ To use the defaults specified py pyqtgraph.setConfigOption, use background='default'.
+ To make the background transparent, use background=None.
+ """
+ self._background = background
+ if background == 'default':
+ background = pyqtgraph.getConfigOption('background')
+ if background is None:
+ self.setBackgroundRole(QtGui.QPalette.NoRole)
+ else:
+ brush = fn.mkBrush(background)
+ self.setBackgroundBrush(brush)
+
+
def close(self):
self.centralWidget = None
self.scene().clear()
@@ -126,7 +158,8 @@ class GraphicsView(QtGui.QGraphicsView):
return self.setCentralWidget(item)
def setCentralWidget(self, item):
- """Sets a QGraphicsWidget to automatically fill the entire view."""
+ """Sets a QGraphicsWidget to automatically fill the entire view (the item will be automatically
+ resize whenever the GraphicsView is resized)."""
if self.centralWidget is not None:
self.scene().removeItem(self.centralWidget)
self.centralWidget = item
@@ -152,15 +185,18 @@ class GraphicsView(QtGui.QGraphicsView):
return
if self.autoPixelRange:
self.range = QtCore.QRectF(0, 0, self.size().width(), self.size().height())
- GraphicsView.setRange(self, self.range, padding=0, disableAutoPixel=False)
+ GraphicsView.setRange(self, self.range, padding=0, disableAutoPixel=False) ## we do this because some subclasses like to redefine setRange in an incompatible way.
self.updateMatrix()
def updateMatrix(self, propagate=True):
self.setSceneRect(self.range)
- if self.aspectLocked:
- self.fitInView(self.range, QtCore.Qt.KeepAspectRatio)
+ if self.autoPixelRange:
+ self.resetTransform()
else:
- self.fitInView(self.range, QtCore.Qt.IgnoreAspectRatio)
+ if self.aspectLocked:
+ self.fitInView(self.range, QtCore.Qt.KeepAspectRatio)
+ else:
+ self.fitInView(self.range, QtCore.Qt.IgnoreAspectRatio)
self.sigRangeChanged.emit(self, self.range)
diff --git a/widgets/HistogramLUTWidget.py b/widgets/HistogramLUTWidget.py
index 5d6f3d44..bc041595 100644
--- a/widgets/HistogramLUTWidget.py
+++ b/widgets/HistogramLUTWidget.py
@@ -18,7 +18,7 @@ class HistogramLUTWidget(GraphicsView):
self.item = HistogramLUTItem(*args, **kargs)
self.setCentralItem(self.item)
self.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
- self.setMinimumWidth(92)
+ self.setMinimumWidth(95)
def sizeHint(self):
diff --git a/widgets/RemoteGraphicsView.py b/widgets/RemoteGraphicsView.py
index eda14025..5a389616 100644
--- a/widgets/RemoteGraphicsView.py
+++ b/widgets/RemoteGraphicsView.py
@@ -1,6 +1,7 @@
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph.multiprocess as mp
import pyqtgraph as pg
+from .GraphicsView import GraphicsView
import numpy as np
import mmap, tempfile, ctypes, atexit
@@ -20,6 +21,7 @@ class RemoteGraphicsView(QtGui.QWidget):
QtGui.QWidget.__init__(self)
self._proc = mp.QtProcess()
self.pg = self._proc._import('pyqtgraph')
+ self.pg.setConfigOptions(self.pg.CONFIG_OPTIONS)
rpgRemote = self._proc._import('pyqtgraph.widgets.RemoteGraphicsView')
self._view = rpgRemote.Renderer(*args, **kwds)
self._view._setProxyOptions(deferGetattr=True)
@@ -82,7 +84,7 @@ class RemoteGraphicsView(QtGui.QWidget):
-class Renderer(pg.GraphicsView):
+class Renderer(GraphicsView):
sceneRendered = QtCore.Signal(object)
@@ -97,7 +99,7 @@ class Renderer(pg.GraphicsView):
self.shm = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
atexit.register(self.close)
- pg.GraphicsView.__init__(self, *args, **kwds)
+ GraphicsView.__init__(self, *args, **kwds)
self.scene().changed.connect(self.update)
self.img = None
self.renderTimer = QtCore.QTimer()
@@ -113,11 +115,11 @@ class Renderer(pg.GraphicsView):
def update(self):
self.img = None
- return pg.GraphicsView.update(self)
+ return GraphicsView.update(self)
def resize(self, size):
oldSize = self.size()
- pg.GraphicsView.resize(self, size)
+ GraphicsView.resize(self, size)
self.resizeEvent(QtGui.QResizeEvent(size, oldSize))
self.update()
@@ -141,29 +143,29 @@ class Renderer(pg.GraphicsView):
typ = QtCore.QEvent.Type(typ)
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods)
- return pg.GraphicsView.mousePressEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
+ return GraphicsView.mousePressEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
def mouseMoveEvent(self, typ, pos, gpos, btn, btns, mods):
typ = QtCore.QEvent.Type(typ)
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods)
- return pg.GraphicsView.mouseMoveEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
+ return GraphicsView.mouseMoveEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
def mouseReleaseEvent(self, typ, pos, gpos, btn, btns, mods):
typ = QtCore.QEvent.Type(typ)
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods)
- return pg.GraphicsView.mouseReleaseEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
+ return GraphicsView.mouseReleaseEvent(self, QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods))
def wheelEvent(self, pos, gpos, d, btns, mods, ori):
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods)
- return pg.GraphicsView.wheelEvent(self, QtGui.QWheelEvent(pos, gpos, d, btns, mods, ori))
+ return GraphicsView.wheelEvent(self, QtGui.QWheelEvent(pos, gpos, d, btns, mods, ori))
def keyEvent(self, typ, mods, text, autorep, count):
typ = QtCore.QEvent.Type(typ)
mods = QtCore.Qt.KeyboardModifiers(mods)
- pg.GraphicsView.keyEvent(self, QtGui.QKeyEvent(typ, mods, text, autorep, count))
+ GraphicsView.keyEvent(self, QtGui.QKeyEvent(typ, mods, text, autorep, count))
return ev.accepted()