Added imageAxisOrder config option
Added global config documentation ROIs don't exactly work yet..
This commit is contained in:
parent
e46be6ddec
commit
bee5878915
@ -6,6 +6,7 @@ Contents:
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
config_options
|
||||
functions
|
||||
graphicsItems/index
|
||||
widgets/index
|
||||
|
40
doc/source/config_options.rst
Normal file
40
doc/source/config_options.rst
Normal file
@ -0,0 +1,40 @@
|
||||
.. currentmodule:: pyqtgraph
|
||||
|
||||
.. _apiref_config:
|
||||
|
||||
Global Configuration Options
|
||||
============================
|
||||
|
||||
PyQtGraph has several global configuration options that allow you to change its
|
||||
default behavior. These can be accessed using the :func:`setConfigOptions` and
|
||||
:func:`getConfigOption` functions:
|
||||
|
||||
================== =================== ================== ================================================================================
|
||||
**Option** **Type** **Default**
|
||||
leftButtonPan bool True If True, dragging the left mouse button over a ViewBox
|
||||
causes the view to be panned. If False, then dragging
|
||||
the left mouse button draws a rectangle that the
|
||||
ViewBox will zoom to.
|
||||
foreground See :func:`mkColor` 'd' Default foreground color for text, lines, axes, etc.
|
||||
background See :func:`mkColor` 'k' Default background for :class:`GraphicsView`.
|
||||
antialias bool False Enabling antialiasing causes lines to be drawn with
|
||||
smooth edges at the cost of reduced performance.
|
||||
imageAxisOrder str 'legacy' For 'normal', image data is expected in the standard row-major (row, col) order.
|
||||
For 'legacy', image data is expected in reversed column-major (col, row) order.
|
||||
The default is 'legacy' for backward compatibility, but this may
|
||||
change in the future.
|
||||
editorCommand str or None None Command used to invoke code editor from ConsoleWidget.
|
||||
exitCleanup bool True Attempt to work around some exit crash bugs in PyQt and PySide.
|
||||
useWeave bool False Use weave to speed up some operations, if it is available.
|
||||
weaveDebug bool False Print full error message if weave compile fails.
|
||||
useOpenGL bool False Enable OpenGL in GraphicsView. This can have unpredictable effects on stability
|
||||
and performance.
|
||||
enableExperimental bool False Enable experimental features (the curious can search for this key in the code).
|
||||
crashWarning bool False If True, print warnings about situations that may result in a crash.
|
||||
================== =================== ================== ================================================================================
|
||||
|
||||
|
||||
.. autofunction:: pyqtgraph.setConfigOptions
|
||||
|
||||
.. autofunction:: pyqtgraph.getConfigOption
|
||||
|
@ -17,6 +17,8 @@ import numpy as np
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
import pyqtgraph as pg
|
||||
|
||||
pg.setConfigOptions(imageAxisOrder='normal')
|
||||
|
||||
app = QtGui.QApplication([])
|
||||
|
||||
## Create window with ImageView widget
|
||||
@ -42,7 +44,7 @@ sig[40:] += np.exp(-np.linspace(1,10, 60))
|
||||
sig[70:] += np.exp(-np.linspace(1,10, 30))
|
||||
|
||||
sig = sig[:,np.newaxis,np.newaxis] * 3
|
||||
data[:,50:60,50:60] += sig
|
||||
data[:,50:60,30:40] += sig
|
||||
|
||||
|
||||
## Display the data and assign each frame a time value from 1.0 to 3.0
|
||||
|
@ -8,23 +8,15 @@ from pyqtgraph.Qt import QtCore, QtGui
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
|
||||
pg.setConfigOptions(imageAxisOrder='normal')
|
||||
|
||||
## create GUI
|
||||
app = QtGui.QApplication([])
|
||||
|
||||
w = pg.GraphicsWindow(size=(800,800), border=True)
|
||||
|
||||
v = w.addViewBox(colspan=2)
|
||||
|
||||
#w = QtGui.QMainWindow()
|
||||
#w.resize(800,800)
|
||||
#v = pg.GraphicsView()
|
||||
v.invertY(True) ## Images usually have their Y-axis pointing downward
|
||||
v.setAspectLocked(True)
|
||||
#v.enableMouse(True)
|
||||
#v.autoPixelScale = False
|
||||
#w.setCentralWidget(v)
|
||||
#s = v.scene()
|
||||
#v.setRange(QtCore.QRectF(-2, -2, 220, 220))
|
||||
|
||||
|
||||
## Create image to display
|
||||
@ -37,6 +29,11 @@ arr[:, 75] = 5
|
||||
arr[50, :] = 10
|
||||
arr[:, 50] = 10
|
||||
|
||||
# add an arrow for asymmetry
|
||||
arr[10, :50] = 10
|
||||
arr[9:12, 44:48] = 10
|
||||
arr[8:13, 44:46] = 10
|
||||
|
||||
## Create image items, add to scene and set position
|
||||
im1 = pg.ImageItem(arr)
|
||||
im2 = pg.ImageItem(arr)
|
||||
@ -44,6 +41,7 @@ v.addItem(im1)
|
||||
v.addItem(im2)
|
||||
im2.moveBy(110, 20)
|
||||
v.setRange(QtCore.QRectF(0, 0, 200, 120))
|
||||
im1.scale(0.8, 0.5)
|
||||
|
||||
im3 = pg.ImageItem()
|
||||
v2 = w.addViewBox(1,0)
|
||||
|
@ -103,6 +103,9 @@ def mkData():
|
||||
if dtype[0] != 'float':
|
||||
data = np.clip(data, 0, mx)
|
||||
data = data.astype(dt)
|
||||
data[:, 10, 10:50] = mx
|
||||
data[:, 9:12, 48] = mx
|
||||
data[:, 8:13, 47] = mx
|
||||
cache = {dtype: data} # clear to save memory (but keep one to prevent unnecessary regeneration)
|
||||
|
||||
data = cache[dtype]
|
||||
|
@ -12,6 +12,7 @@ import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
import numpy as np
|
||||
|
||||
pg.setConfigOptions(imageAxisOrder='normal')
|
||||
pg.mkQApp()
|
||||
|
||||
win = pg.GraphicsLayoutWidget()
|
||||
|
@ -59,6 +59,10 @@ CONFIG_OPTIONS = {
|
||||
'exitCleanup': True, ## Attempt to work around some exit crash bugs in PyQt and PySide
|
||||
'enableExperimental': False, ## Enable experimental features (the curious can search for this key in the code)
|
||||
'crashWarning': False, # If True, print warnings about situations that may result in a crash
|
||||
'imageAxisOrder': 'legacy', # For 'normal', image data is expected in the standard (row, col) order.
|
||||
# For 'legacy', image data is expected in reversed (col, row) order.
|
||||
# The default is 'legacy' for backward compatibility, but this will
|
||||
# change in the future.
|
||||
}
|
||||
|
||||
|
||||
@ -66,9 +70,15 @@ def setConfigOption(opt, value):
|
||||
CONFIG_OPTIONS[opt] = value
|
||||
|
||||
def setConfigOptions(**opts):
|
||||
"""Set global configuration options.
|
||||
|
||||
Each keyword argument sets one global option.
|
||||
"""
|
||||
CONFIG_OPTIONS.update(opts)
|
||||
|
||||
def getConfigOption(opt):
|
||||
"""Return the value of a single global configuration option.
|
||||
"""
|
||||
return CONFIG_OPTIONS[opt]
|
||||
|
||||
|
||||
|
@ -7,6 +7,8 @@ from .. import functions as fn
|
||||
from .. import debug as debug
|
||||
from .GraphicsObject import GraphicsObject
|
||||
from ..Point import Point
|
||||
from .. import getConfigOption
|
||||
|
||||
|
||||
__all__ = ['ImageItem']
|
||||
|
||||
@ -28,7 +30,6 @@ class ImageItem(GraphicsObject):
|
||||
for controlling the levels and lookup table used to display the image.
|
||||
"""
|
||||
|
||||
|
||||
sigImageChanged = QtCore.Signal()
|
||||
sigRemoveRequested = QtCore.Signal(object) # self; emitted when 'remove' is selected from context menu
|
||||
|
||||
@ -86,12 +87,14 @@ class ImageItem(GraphicsObject):
|
||||
def width(self):
|
||||
if self.image is None:
|
||||
return None
|
||||
return self.image.shape[0]
|
||||
axis = 0 if getConfigOption('imageAxisOrder') == 'legacy' else 1
|
||||
return self.image.shape[axis]
|
||||
|
||||
def height(self):
|
||||
if self.image is None:
|
||||
return None
|
||||
return self.image.shape[1]
|
||||
axis = 1 if getConfigOption('imageAxisOrder') == 'legacy' else 0
|
||||
return self.image.shape[axis]
|
||||
|
||||
def boundingRect(self):
|
||||
if self.image is None:
|
||||
@ -190,7 +193,7 @@ class ImageItem(GraphicsObject):
|
||||
image (numpy array) Specifies the image data. May be 2D (width, height) or
|
||||
3D (width, height, RGBa). The array dtype must be integer or floating
|
||||
point of any bit depth. For 3D arrays, the third dimension must
|
||||
be of length 3 (RGB) or 4 (RGBA).
|
||||
be of length 3 (RGB) or 4 (RGBA). See *notes* below.
|
||||
autoLevels (bool) If True, this forces the image to automatically select
|
||||
levels based on the maximum and minimum values in the data.
|
||||
By default, this argument is true unless the levels argument is
|
||||
@ -201,12 +204,26 @@ class ImageItem(GraphicsObject):
|
||||
data. By default, this will be set to the minimum and maximum values
|
||||
in the image. If the image array has dtype uint8, no rescaling is necessary.
|
||||
opacity (float 0.0-1.0)
|
||||
compositionMode see :func:`setCompositionMode <pyqtgraph.ImageItem.setCompositionMode>`
|
||||
compositionMode See :func:`setCompositionMode <pyqtgraph.ImageItem.setCompositionMode>`
|
||||
border Sets the pen used when drawing the image border. Default is None.
|
||||
autoDownsample (bool) If True, the image is automatically downsampled to match the
|
||||
screen resolution. This improves performance for large images and
|
||||
reduces aliasing.
|
||||
================= =========================================================================
|
||||
|
||||
|
||||
**Notes:**
|
||||
|
||||
For backward compatibility, image data is assumed to be in column-major order (column, row).
|
||||
However, most image data is stored in row-major order (row, column) and will need to be
|
||||
transposed before calling setImage()::
|
||||
|
||||
imageitem.setImage(imagedata.T)
|
||||
|
||||
This requirement can be changed by the ``imageAxisOrder``
|
||||
:ref:`global configuration option <apiref_config>`.
|
||||
|
||||
|
||||
"""
|
||||
profile = debug.Profiler()
|
||||
|
||||
@ -331,7 +348,13 @@ class ImageItem(GraphicsObject):
|
||||
lut = self._effectiveLut
|
||||
levels = None
|
||||
|
||||
argb, alpha = fn.makeARGB(image.transpose((1, 0, 2)[:image.ndim]), lut=lut, levels=levels)
|
||||
# Assume images are in column-major order for backward compatibility
|
||||
# (most images are in row-major order)
|
||||
|
||||
if getConfigOption('imageAxisOrder') == 'legacy':
|
||||
image = image.transpose((1, 0, 2)[:image.ndim])
|
||||
|
||||
argb, alpha = fn.makeARGB(image, lut=lut, levels=levels)
|
||||
self.qimage = fn.makeQImage(argb, alpha, transpose=False)
|
||||
|
||||
def paint(self, p, *args):
|
||||
@ -347,7 +370,8 @@ class ImageItem(GraphicsObject):
|
||||
p.setCompositionMode(self.paintMode)
|
||||
profile('set comp mode')
|
||||
|
||||
p.drawImage(QtCore.QRectF(0,0,self.image.shape[0],self.image.shape[1]), self.qimage)
|
||||
shape = self.image.shape[:2] if getConfigOption('imageAxisOrder') == 'legacy' else self.image.shape[:2][::-1]
|
||||
p.drawImage(QtCore.QRectF(0,0,*shape), self.qimage)
|
||||
profile('p.drawImage')
|
||||
if self.border is not None:
|
||||
p.setPen(self.border)
|
||||
|
@ -21,6 +21,7 @@ from math import cos, sin
|
||||
from .. import functions as fn
|
||||
from .GraphicsObject import GraphicsObject
|
||||
from .UIGraphicsItem import UIGraphicsItem
|
||||
from .. import getConfigOption
|
||||
|
||||
__all__ = [
|
||||
'ROI',
|
||||
@ -1074,7 +1075,11 @@ class ROI(GraphicsObject):
|
||||
Used to determine the relationship between the
|
||||
ROI and the boundaries of *data*.
|
||||
axes (length-2 tuple) Specifies the axes in *data* that
|
||||
correspond to the x and y axes of *img*.
|
||||
correspond to the (x, y) axes of *img*. If the
|
||||
global configuration variable
|
||||
:ref:`imageAxisOrder <apiref_config>` is set to
|
||||
'normal', then the axes are instead specified in
|
||||
(y, x) order.
|
||||
returnMappedCoords (bool) If True, the array slice is returned along
|
||||
with a corresponding array of coordinates that were
|
||||
used to extract data from the original array.
|
||||
@ -1143,6 +1148,12 @@ class ROI(GraphicsObject):
|
||||
origin = (origin.x(), origin.y())
|
||||
|
||||
shape = [abs(shape[0]/sx), abs(shape[1]/sy)]
|
||||
origin = (origin.x(), origin.y())
|
||||
|
||||
if getConfigOption('imageAxisOrder') == 'normal':
|
||||
vectors = [vectors[1][::-1], vectors[0][::-1]]
|
||||
shape = shape[::-1]
|
||||
origin = origin[::-1]
|
||||
|
||||
return shape, vectors, origin
|
||||
|
||||
|
@ -30,6 +30,7 @@ from ..graphicsItems.GradientEditorItem import addGradientListToDocstring
|
||||
from .. import ptime as ptime
|
||||
from .. import debug as debug
|
||||
from ..SignalProxy import SignalProxy
|
||||
from .. import getConfigOption
|
||||
|
||||
try:
|
||||
from bottleneck import nanmin, nanmax
|
||||
@ -203,9 +204,10 @@ class ImageView(QtGui.QWidget):
|
||||
"""
|
||||
Set the image to be displayed in the widget.
|
||||
|
||||
================== =======================================================================
|
||||
================== ===========================================================================
|
||||
**Arguments:**
|
||||
img (numpy array) the image to be displayed.
|
||||
img (numpy array) the image to be displayed. See :func:`ImageItem.setImage` and
|
||||
*notes* below.
|
||||
xvals (numpy array) 1D array of z-axis values corresponding to the third axis
|
||||
in a 3D image. For video, this array should contain the time of each frame.
|
||||
autoRange (bool) whether to scale/pan the view to fit the image.
|
||||
@ -222,7 +224,19 @@ class ImageView(QtGui.QWidget):
|
||||
and *scale*.
|
||||
autoHistogramRange If True, the histogram y-range is automatically scaled to fit the
|
||||
image data.
|
||||
================== =======================================================================
|
||||
================== ===========================================================================
|
||||
|
||||
**Notes:**
|
||||
|
||||
For backward compatibility, image data is assumed to be in column-major order (column, row).
|
||||
However, most image data is stored in row-major order (row, column) and will need to be
|
||||
transposed before calling setImage()::
|
||||
|
||||
imageview.setImage(imagedata.T)
|
||||
|
||||
This requirement can be changed by the ``imageAxisOrder``
|
||||
:ref:`global configuration option <apiref_config>`.
|
||||
|
||||
"""
|
||||
profiler = debug.Profiler()
|
||||
|
||||
@ -252,15 +266,17 @@ class ImageView(QtGui.QWidget):
|
||||
profiler()
|
||||
|
||||
if axes is None:
|
||||
xy = (0, 1) if getConfigOption('imageAxisOrder') == 'legacy' else (1, 0)
|
||||
|
||||
if img.ndim == 2:
|
||||
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': None}
|
||||
self.axes = {'t': None, 'x': xy[0], 'y': xy[1], 'c': None}
|
||||
elif img.ndim == 3:
|
||||
if img.shape[2] <= 4:
|
||||
self.axes = {'t': None, 'x': 0, 'y': 1, 'c': 2}
|
||||
self.axes = {'t': None, 'x': xy[0], 'y': xy[1], 'c': 2}
|
||||
else:
|
||||
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': None}
|
||||
self.axes = {'t': 0, 'x': xy[0]+1, 'y': xy[1]+1, 'c': None}
|
||||
elif img.ndim == 4:
|
||||
self.axes = {'t': 0, 'x': 1, 'y': 2, 'c': 3}
|
||||
self.axes = {'t': 0, 'x': xy[0]+1, 'y': xy[1]+1, 'c': 3}
|
||||
else:
|
||||
raise Exception("Can not interpret image with dimensions %s" % (str(img.shape)))
|
||||
elif isinstance(axes, dict):
|
||||
@ -542,6 +558,7 @@ class ImageView(QtGui.QWidget):
|
||||
axes = (1, 2)
|
||||
else:
|
||||
return
|
||||
|
||||
data, coords = self.roi.getArrayRegion(image.view(np.ndarray), self.imageItem, axes, returnMappedCoords=True)
|
||||
if data is not None:
|
||||
while data.ndim > 1:
|
||||
|
@ -63,7 +63,7 @@ class GraphicsView(QtGui.QGraphicsView):
|
||||
:func:`mkColor <pyqtgraph.mkColor>`. By
|
||||
default, the background color is determined using the
|
||||
'backgroundColor' configuration option (see
|
||||
:func:`setConfigOption <pyqtgraph.setConfigOption>`.
|
||||
:func:`setConfigOptions <pyqtgraph.setConfigOptions>`).
|
||||
============== ============================================================
|
||||
"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user