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()