Source code for lavuelib.histogramWidget

# Copyright (C) 2017  DESY, Notkestr. 85, D-22607 Hamburg
#
# lavue is an image viewing program for photon science imaging detectors.
# Its usual application is as a live viewer using hidra as data source.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation in  version 2
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA  02110-1301, USA.
#
# Authors:
#     Jan Kotanski <jan.kotanski@desy.de>
#     Christoph Rosemann <christoph.rosemann@desy.de>
#

""" Horizontal HistogramWidget """


import pyqtgraph as _pg
from pyqtgraph import QtCore
import numpy as np
import logging
import warnings

try:
    from pyqtgraph import QtWidgets
except Exception:
    from pyqtgraph import QtGui as QtWidgets


from .external.pyqtgraph_0_12 import (
    histogram__init__, histogram_paint, histogram_setHistogramRange,
    # histogram_setLevels, histogram_fillHistogram
)


#: ( (:obj:`str`,:obj:`str`,:obj:`str`) )
#:         pg major version, pg minor verion, pg patch version
_VMAJOR, _VMINOR, _VPATCH = _pg.__version__.split(".")[:3] \
    if _pg.__version__ else ("0", "9", "0")
try:
    _NPATCH = int(_VPATCH)
except Exception:
    _NPATCH = 0
_PQGVER = int(_VMAJOR) * 1000 + int(_VMINOR) * 100 + _NPATCH


_pg.graphicsItems.GradientEditorItem.Gradients['reversegrey'] = {
    'ticks': [(0.0, (255, 255, 255, 255)),
              (1.0, (0, 0, 0, 255)), ], 'mode': 'rgb'}
_pg.graphicsItems.GradientEditorItem.Gradients['highcontrast'] = {
    'ticks': [(0.0, (0, 0, 0, 255)),
              (1.0, (255, 255, 0, 255)), ], 'mode': 'rgb'}
_pg.graphicsItems.GradientEditorItem.Gradients['spectrum'] = {
    'ticks': [(0.0, (255, 0, 255, 255)),
              (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}
_pg.graphicsItems.GradientEditorItem.Gradients['spectrumclip'] = {
    'ticks': [(0.0, (255, 0, 255, 255)),
              (.99, (255, 0, 0, 255)),
              (1.0, (255, 255, 255, 255))], 'mode': 'hsv'}
# define two new gradients of choice
_pg.graphicsItems.GradientEditorItem.Gradients['inverted'] = {
    'ticks': [(0.0, (255, 255, 255, 255)),
              (1.0, (0, 0, 0, 255)), ], 'mode': 'rgb'}
_pg.graphicsItems.GradientEditorItem.Gradients['highcontrastclip'] = {
    'ticks': [(0.0, (255, 255, 255, 255)),
              (0.15, (0, 0, 0, 255)),
              (0.4, (255, 0, 0, 255)),
              (0.7, (255, 255, 0, 255)),
              (0.99, (255, 255, 255, 255)),
              (1.0, (0, 0, 255, 255)), ], 'mode': 'rgb'}


__all__ = ['HistogramHLUTWidget']


logger = logging.getLogger("lavue")


[docs]class HistogramHLUTWidget(_pg.widgets.GraphicsView.GraphicsView): """ Horizontal HistogramWidget """ def __init__(self, parent=None, bins=None, step=None, *args, **kargs): """ constructor :param parent: parent object :type parent: :class:`pyqtgraph.QtCore.QObject` :param bins: bins edges algorithm for histogram, default: 'auto' :type bins: :obj:`str` :param step: data step for calculation of histogram levels, default: 'auto' :type step: :obj:`str` or :obj:`int` :param args: HistogramHLUTItem parameters list :type args: :obj:`list` < :obj:`any`> :param kargs: HistogramHLUTItem parameter dictionary :type kargs: :obj:`dict` < :obj:`str`, :obj:`any`> """ background = kargs.pop('background', 'default') _pg.widgets.GraphicsView.GraphicsView.__init__( self, parent, useOpenGL=False, background=background) #: (:class:`HistogramHLUTItem`) histogram item self.item = HistogramHLUTItem(bins, step, *args, **kargs) self.setCentralItem(self.item) self.setSizePolicy( QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) self.setMinimumWidth(95) self.setMinimumHeight(95)
[docs] def sizeHint(self): """ sets size hint """ return QtCore.QSize(115, 200)
def __getattr__(self, attr): """ gets attribute of HistogramHLUTItem :param attr: attribute name :type attr: :obj:`str` :returns: attribute value :rtype: :obj:`any` """ return getattr(self.item, attr)
[docs] def setAutoFactor(self, factor): """ sets auto level factor :param factor: auto level factor of maximal peak :type factor: :obj:`float` """ self.item.autolevelfactor = factor
[docs] def setBins(self, bins): """ sets bins edges algorithm for histogram :param channel: bins edges algorithm for histogram :type channel: :obj:`str` """ self.item.setBins(bins)
[docs] def setStep(self, step): """ sets image step data for algorithm of histogram :param channel: image step data for algorithm of histogram :type channel: :obj:`int` """ self.item.setStep(step)
class GradientEditorItemWS( _pg.graphicsItems.GradientEditorItem.GradientEditorItem): """ gradient editor item with a signal on loadPreset """ #: (:class:`pyqtgraph.QtCore.pyqtSignal`) minimum level changed signal sigNameChanged = QtCore.pyqtSignal(str) def __init__(self, *args, **kargs): """ constructor :param args: GradientEditorItem parameters list :type args: :obj:`list` < :obj:`any`> :param kargs: GradientEditorItem parameter dictionary :type kargs: :obj:`dict` < :obj:`str`, :obj:`any`> """ self.__skipupdate = True _pg.graphicsItems.GradientEditorItem.GradientEditorItem.__init__( self, *args, **kargs) self.__skipupdate = False #: (:obj:`str`) color gradient name self.name = "highcontrast" #: (:class:`pyqtgrath.QtWidgets.QAction`) save gradient action self.saveAction = QtWidgets.QAction('Save ...', self) #: (:obj:`pyqtgrath.QtWidgets.QAction`) remove gradient action self.removeAction = QtWidgets.QAction('Remove', self) def addMenuActions(self): """ add save/remove actions """ self.menu.addAction(self.saveAction) self.menu.addAction(self.removeAction) def removeTick(self, tick, finish=True): """ removes ticks with hook :param tick: ticks to remove :type tick: :obj:`list` < :obj:`any`> :param finish: finish remove flag :type finish: :obj:`bool` """ if not self.__skipupdate: _pg.graphicsItems.GradientEditorItem.GradientEditorItem.\ removeTick( self, tick=tick, finish=finish) else: _pg.graphicsItems.GradientEditorItem.TickSliderItem.\ removeTick(self, tick) if finish: # hook for a pyqtgraph bug # self.updateGradient() self.sigGradientChangeFinished.emit(self) def getCurrentGradient(self): """ provides dictionary with the current gradient :returns: gradient dictionary with: {"mode": <colorMode>, "ticks": [ (<pos>, (<r>, <g>, <b>, <a>)), (<pos>, (<r>, <g>, <b>, <a>)), ... (<pos>, (<r>, <g>, <b>, <a>)), ] } :rtype: :obj:`dict` < :obj:`str`:, :obj:`str`: or :obj:`list`:> """ tlist = self.listTicks() tdct = {} tdct['ticks'] = [] tdct['mode'] = self.colorMode for tck, pos in tlist: clr = tck.color tdct['ticks'].append( (pos, (clr.red(), clr.green(), clr.blue(), clr.alpha())) ) return tdct def loadPreset(self, name): """ loads a predefined gradient and emits sigNameChanged :param name: gradient name :type name: :obj:`str` """ _pg.graphicsItems.GradientEditorItem.GradientEditorItem.loadPreset( self, name) self.name = name self.sigNameChanged.emit(name) class HistogramHLUTItem(_pg.HistogramLUTItem): #: (:class:`pyqtgraph.QtCore.pyqtSignal`) automatic levels changed signal autoLevelsChanged = QtCore.pyqtSignal(int) # bool does not work... #: (:class:`pyqtgraph.QtCore.pyqtSignal`) minimum level changed signal sigNameChanged = QtCore.pyqtSignal(str) #: (:class:`pyqtgraph.QtCore.pyqtSignal`) save gradient requested saveGradientRequested = QtCore.pyqtSignal() #: (:class:`pyqtgraph.QtCore.pyqtSignal`) remove gradient requested removeGradientRequested = QtCore.pyqtSignal() """ Horizontal HistogramItem """ def __init__(self, bins=None, step=None, image=None, fillHistogram=True, expertmode=False): """ constructor :param bins: bins edges algorithm for histogram, default: 'auto' :type bins: :obj:`str` :param step: data step for calculation of histogram levels, default: 'auto' :type step: :obj:`str` or :obj:`int` :param image: 2d image :type image: :class:`pyqtgraph.ImageItem` :param fillHistogram: histogram will be filled in :type fillHistogram: :obj:`bool` :param expertmode: expert mode flag :type expertmode: :obj:`bool` """ if _PQGVER >= 1100: self.__init_1100(bins, step, image, fillHistogram, expertmode) else: self.__init_old(bins, step, image, fillHistogram, expertmode) self.vb.enableAutoRange(self.vb.YAxis, 0.99) def __init_1100(self, bins=None, step=None, image=None, fillHistogram=True, expertmode=False): """ constructor for old pyqtgraph :param bins: bins edges algorithm for histogram, default: 'auto' :type bins: :obj:`str` :param step: data step for calculation of histogram levels, default: 'auto' :type step: :obj:`str` or :obj:`int` :param image: 2d image :type image: :class:`pyqtgraph.ImageItem` :param fillHistogram: histogram will be filled in :type fillHistogram: :obj:`bool` :param expertmode: expert mode flag :type expertmode: :obj:`bool` """ if _PQGVER >= 1202: _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.__init__( self, image, fillHistogram, levelMode='mono', gradientPosition='bottom', orientation='horizontal') else: histogram__init__( self, image, fillHistogram, levelMode='mono', gradientPosition='bottom', orientation='horizontal') #: (:obj:`bool`) expert mode self.__expertmode = expertmode #: (:obj: `bool`) rgb flag self.__rgb = False # self.vb.setMaximumHeight(15200) #: (:obj:`list`) buffer for removed gradients self.__oldgradient = [] self.resetGradient(False) self.autolevelfactor = None self.__step = step or 'auto' self.__bins = bins or 'auto' def __init_old(self, bins=None, step=None, image=None, fillHistogram=True, expertmode=False): """ constructor for old pyqtgraph :param bins: bins edges algorithm for histogram, default: 'auto' :type bins: :obj:`str` :param step: data step for calculation of histogram levels, default: 'auto' :type step: :obj:`str` or :obj:`int` :param image: 2d image :type image: :class:`pyqtgraph.ImageItem` :param fillHistogram: histogram will be filled in :type fillHistogram: :obj:`bool` :param expertmode: expert mode flag :type expertmode: :obj:`bool` """ _pg.graphicsItems.GraphicsWidget.GraphicsWidget.__init__(self) #: (:obj:`bool`) expert mode self.__expertmode = expertmode #: (:class:`numpy.ndarray`) look up table self.lut = None if _VMAJOR == '0' and int(_VMINOR) < 10 and int(_VPATCH) < 9: #: (:class:`weakref.ref` or :class:`pyqtgraph.ImageItem`) #: weakref to image item or image item itself (for < 0.9.8) self.imageItem = None else: self.imageItem = lambda: None #: (:obj: `bool`) rgb flag self.__rgb = False #: (:class:`PyQt5.QtWidgets.QGraphicsGridLayout`) grid layout self.layout = QtWidgets.QGraphicsGridLayout() self.setLayout(self.layout) self.layout.setContentsMargins(1, 1, 1, 1) self.layout.setSpacing(0) #: (:class:`pyqtgraph.graphicsItems.ViewBox.ViewBox`) view box self.vb = _pg.graphicsItems.ViewBox.ViewBox(parent=self) # self.vb.setMaximumHeight(152) self.vb.setMinimumHeight(45) self.vb.setMouseEnabled(x=True, y=False) # self.vb.setMouseEnabled(x=False, y=True) #: (:class:`GradientEditorItemWS`) gradient editor item with a signal self.gradient = GradientEditorItemWS() if self.__expertmode: self.gradient.addMenuActions() self.gradient.setOrientation('bottom') self.gradient.loadPreset('grey') #: (:obj:`list`) buffer for removed gradients self.__oldgradient = [] #: (:class:`pyqtgraph.graphicsItems.LinearRegionItem.LinearRegionItem`) #: linear region item self.region = _pg.graphicsItems.LinearRegionItem.LinearRegionItem( [0, 1], _pg.graphicsItems.LinearRegionItem.LinearRegionItem.Vertical) self.region.setZValue(1000) self.vb.addItem(self.region) #: (:class:`pyqtgraph.graphicsItems.AxisItem.AxisItem`) axis item self.axis = _pg.graphicsItems.AxisItem.AxisItem( 'top', linkView=self.vb, maxTickLength=-10, showValues=False, parent=self) self.layout.addItem(self.axis, 0, 0) self.layout.addItem(self.vb, 1, 0) self.layout.addItem(self.gradient, 2, 0) # self.range = None self.autolevelfactor = None self.__step = step or 'auto' self.__bins = bins or 'auto' self.gradient.setFlag(self.gradient.ItemStacksBehindParent) self.vb.setFlag(self.gradient.ItemStacksBehindParent) self.gradient.sigGradientChanged.connect(self.gradientChanged) self.gradient.sigNameChanged.connect(self._emitSigNameChanged) self.gradient.saveAction.triggered.connect( self._emitSaveGradientRequested) self.gradient.removeAction.triggered.connect( self._emitRemoveGradientRequested) self.region.sigRegionChanged.connect(self.regionChanging) self.region.sigRegionChangeFinished.connect(self.regionChanged) self.vb.sigRangeChanged.connect(self.viewRangeChanged) self.plot = _pg.graphicsItems.PlotDataItem.PlotDataItem() self.plots = [self.plot] # self.plot.dataBounds(1, 0.9) # self.plot.dataBounds(0, 0.9) self.levelMode = 'mono' self.fillHistogram(fillHistogram) self.vb.addItem(self.plot) self.autoHistogramRange() if image is not None: self.setImageItem(image) # self.background = None def setRGB(self, rgb): """ sets rgb flag :param rgb: rgb lag :type rgb: :obj:`bool` """ self.__rgb = rgb def gradientChanged(self): """ gradient changed with rgb """ if self.__rgb: self.lut = None self.sigLookupTableChanged.emit(self) else: _pg.HistogramLUTItem.gradientChanged(self) def resetGradient(self, signal=True): """ resets gradient widget """ self.gradient.sigGradientChanged.disconnect(self.gradientChanged) if signal: self.gradient.sigNameChanged.disconnect(self._emitSigNameChanged) self.gradient.saveAction.triggered.disconnect( self._emitSaveGradientRequested) self.gradient.removeAction.triggered.disconnect( self._emitRemoveGradientRequested) self.gradient.hide() if hasattr(self.gradient, "prepareGeometryChange"): self.gradient.prepareGeometryChange() self.layout.removeItem(self.gradient) self.gradient.close() self.__oldgradient.append(self.gradient) self.gradient = GradientEditorItemWS() if self.__expertmode: self.gradient.addMenuActions() self.gradient.setOrientation('bottom') self.gradient.loadPreset('grey') self.layout.addItem(self.gradient, 2, 0) self.gradient.sigGradientChanged.connect(self.gradientChanged) self.gradient.sigNameChanged.connect(self._emitSigNameChanged) self.gradient.saveAction.triggered.connect( self._emitSaveGradientRequested) self.gradient.removeAction.triggered.connect( self._emitRemoveGradientRequested) @QtCore.pyqtSlot(str) def _emitSigNameChanged(self, name): """ emits SigNameChanged :param name: gradient name :type name: :obj:`str` """ self.sigNameChanged.emit(name) @QtCore.pyqtSlot() def _emitSaveGradientRequested(self): """ emits saveGradientRequested """ self.saveGradientRequested.emit() @QtCore.pyqtSlot() def _emitRemoveGradientRequested(self): """ emits removeGradientRequested """ self.removeGradientRequested.emit() def setBins(self, bins): """ sets bins edges algorithm for histogram :param channel: bins edges algorithm for histogram :type channel: :obj:`str` """ self.__bins = bins def setStep(self, step): """ sets image step data for algorithm of histogram :param channel: image step data for algorithm of histogram :type channel: :obj:`int` """ try: if self.__step: self.__step = int(step) else: self.__step = "auto" except Exception: self.__step = "auto" def setGradientByName(self, name): """ sets gradient by name :param name: gradient name :type name: :obj:`str` """ try: self.gradient.loadPreset(str(name)) except Exception: self.gradient.loadPreset("highcontrast") def paint(self, p, *args): """ paints the histogram item :param p: QPainter painter :type p: :class:`PyQt5.QtGui.QPainter` :param args: paint argument :type args: :obj:`list` < :obj:`any`> """ if _PQGVER >= 1202: self.__paint_1202(p, *args) elif _PQGVER >= 1100: histogram_paint(self, p, *args) else: self.__paint_old(p, *args) def __paint_1202(self, p, *args): _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.paint( self, p, *args) def __paint_old(self, p, *args): """ paints the histogram item :param p: QPainter painter :type p: :class:`PyQt5.QtGui.QPainter` :param args: paint argument :type args: :obj:`list` < :obj:`any`> """ pen = self.region.lines[0].pen rgn = self.getLevels() p1 = self.vb.mapFromViewToItem( self, _pg.Point(rgn[0], self.vb.viewRect().center().y())) p2 = self.vb.mapFromViewToItem( self, _pg.Point(rgn[1], self.vb.viewRect().center().y())) gradRect = self.gradient.mapRectToParent( self.gradient.gradRect.rect()) for pen in [_pg.functions.mkPen('k', width=3), pen]: p.setPen(pen) p.drawLine(p1, gradRect.topLeft()) p.drawLine(p2, gradRect.topRight()) p.drawLine(gradRect.topLeft(), gradRect.bottomLeft()) p.drawLine(gradRect.topRight(), gradRect.bottomRight()) def setHistogramRange(self, mn, mx, padding=0.1): """sets the Y range on the histogram plot. This disables auto-scaling. :param mn: minimum range level :type mn: :obj:`float` :param mx: maximum range level :type mx: :obj:`float` :param padding: histogram padding :type padding: :obj:`float` """ if _PQGVER >= 1202: self.__setHistogramRange_1202(self, mn, mx, padding) if _PQGVER >= 1100: histogram_setHistogramRange(self, mn, mx, padding) else: self.__setHistogramRange_old(self, mn, mx, padding) def __setHistogramRange_old(self, mn, mx, padding=0.1): """sets the Y range on the histogram plot. This disables auto-scaling. :param mn: minimum range level :type mn: :obj:`float` :param mx: maximum range level :type mx: :obj:`float` :param padding: histogram padding :type padding: :obj:`float` """ self.vb.enableAutoRange(self.vb.XAxis, False) self.vb.setYRange(mn, mx, padding) def __setHistogramRange_1202(self, mn, mx, padding=0.1): """sets the Y range on the histogram plot. This disables auto-scaling. :param mn: minimum range level :type mn: :obj:`float` :param mx: maximum range level :type mx: :obj:`float` :param padding: histogram padding :type padding: :obj:`float` """ _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.setHistogramRange( self, mn, mx, padding) def __imageItem(self): """ provides imageItem independent of the pyqtgraph version :returns: image item :rtype: :class:`pyqtgraph.ImageItem` """ if _VMAJOR == '0' and int(_VMINOR) < 10 and int(_VPATCH) < 9: #: (:class:`weakref.ref` or :class:`pyqtgraph.ImageItem`) #: weakref to image item or image item itself (for < 0.9.8) return self.imageItem else: return self.imageItem() def getFactorRegion(self): """ provides mono auto levels calculated from autofactor :returns: minlevel, maxlevel :rtype: (float, float) """ hx = None hy = None if self.autolevelfactor is not None: try: with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', r'All-NaN slice encountered') hx, hy = self.__imageItem().getHistogram( step=self.__step, bins=self.__bins) except Exception as e: logger.warning(str(e)) # print(str(e)) if hy is not None and hx is not None and hx.any() and hy.any(): if abs(hx[0]) < 1.e-3 or abs(hx[0]+2.) < 1.e-3: hx = hx[1:] hy = hy[1:] if hx.any() and hy.any(): hmax = max(hy) hmin = self.autolevelfactor*hmax/100. # mn, mx = self.__imageItem().levels[:2] indexes = np.where(hy >= hmin) ind1 = indexes[0][0] ind2 = indexes[-1][-1] return hx[ind1], hx[ind2] return None, None def getChannelFactorRegion(self, ch=None): """ provides mono auto levels calculated from autofactor :param ch: histogram channels :type ch: :obj: :returns: minlevel, maxlevel for channels :rtype: :obj:`list` < (float, float) > """ channels = [] if ch is None: with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', r'All-NaN slice encountered') channels = self.__imageItem().getHistogram(perChannel=True) if ch[0] is None: return autofactor = False if self.autolevelfactor is not None: for i in range(1, 5): chs = None if len(ch) >= i: h = ch[i-1] hx = h[0] hy = h[1] if hy is not None and hx is not None and \ hx.any() and hy.any(): if abs(hx[0]) < 1.e-3 or abs(hx[0]+2.) < 1.e-3: hhx = hx[1:] hhy = hy[1:] else: hhx = hx hhy = hy if hhx.any() and hhy.any(): hmax = max(hhy) hmin = self.autolevelfactor * hmax / 100. # mn, mx = self.__imageItem().levels[:2] indexes = np.where(hhy >= hmin) ind1 = indexes[0][0] ind2 = indexes[-1][-1] chs = (hhx[ind1], hhx[ind2]) autofactor = True channels.append(chs) if autofactor: return channels def imageChanged(self, autoLevel=False, autoRange=False): """ overload imageChange method :param autoLevel: auto level flag :type autoLevel: :obj:`bool` :param autoRange: auto range flag :type autoRange: :obj:`bool` """ if self.levelMode == 'mono': for plt in self.plots[1:]: plt.setVisible(False) self.plots[0].setVisible(True) hx1, hx2 = self.getFactorRegion() if hx1 is not None: self.region.setRegion([hx1, hx2]) _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.\ imageChanged( self, autoLevel=False, autoRange=autoRange) return try: # _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.\ # imageChanged( # self, autoLevel=autoLevel, autoRange=autoRange) with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', r'All-NaN slice encountered') h = self.__imageItem().getHistogram( step=self.__step, bins=self.__bins) if h[0] is None: return self.plot.setData(*h) if autoLevel: mn = h[0][0] mx = h[0][-1] self.region.setRegion([mn, mx]) except Exception as e: logger.warning(str(e)) # print(str(e)) else: # plot one histogram for each channel self.plots[0].setVisible(False) with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', r'All-NaN slice encountered') ch = self.__imageItem().getHistogram(perChannel=True) if ch[0] is None: return for i in range(1, 5): if len(ch) >= i: h = ch[i-1] self.plots[i].setVisible(True) self.plots[i].setData(*h) else: # hide channels not present in image data self.plots[i].setVisible(False) autofactor = False channels = self.getChannelFactorRegion(ch) if channels is not None: for i, hxx in enumerate(channels): if hxx is not None: self.regions[i + 1].setRegion([hxx[0], hxx[1]]) autofactor = True if not autofactor and autoLevel: for i in range(1, 5): if len(ch) >= i: h = ch[i-1] mn = h[0][0] mx = h[0][-1] self.regions[i].setRegion([mn, mx]) if autofactor: _pg.graphicsItems.HistogramLUTItem.HistogramLUTItem.\ imageChanged( self, autoLevel=False, autoRange=autoRange) # make sure we are displaying the correct number of channels self._showRegions() def switchLevelMode(self, mode): """ switch rgba mode :param mode: rgba mode i.e. 'mono' or 'rgba' :type mode: :obj:`str` """ if mode == self.levelMode or mode not in {'mono', 'rgba'}: return self.levelMode = mode self._showRegions() if mode == 'mono': levels = self.region.getRegion() self.setLevels(*levels) else: if hasattr(self, "regions"): levels = [self.regions[i].getRegion() for i in range(1, 5)] else: oldLevels = self.region.getRegion() levels = [oldLevels] * 4 self.setLevels(rgba=levels) self.__imageItem().setLevels(self.getLevels()) self.imageChanged() self.update()