From d531a808e1e81e128dc26fa5f577f53bda38cde7 Mon Sep 17 00:00:00 2001 From: Martin Chase Date: Tue, 20 Apr 2021 19:57:15 -0700 Subject: [PATCH] allow gradient position to be configured on a histogram (#1729) * NEW features for HistgramLUTItem * gradientPosition=('left', 'right') * only paint if item is visible (is faster) * link hisogram to other histograms * fixes to be able to merge * drop linkHistogram (rgba needs to be better integrated) * make sure defaults to same as current behavior * draw connecting lines correctly on each side * add example use --- examples/HistogramLUT.py | 36 ++++++++++++--------- pyqtgraph/graphicsItems/HistogramLUTItem.py | 23 +++++++++---- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/examples/HistogramLUT.py b/examples/HistogramLUT.py index 159b321f..826dcc6b 100644 --- a/examples/HistogramLUT.py +++ b/examples/HistogramLUT.py @@ -3,45 +3,49 @@ Use a HistogramLUTWidget to control the contrast / coloration of an image. """ -## Add path to library (just for examples; you do not need this) +# Add path to library (just for examples; you do not need this) import initExample import numpy as np -from pyqtgraph.Qt import QtGui, QtCore -import pyqtgraph as pg +import pyqtgraph as pg +from pyqtgraph.Qt import QtGui app = pg.mkQApp("Histogram Lookup Table Example") win = QtGui.QMainWindow() -win.resize(800,600) +win.resize(880, 600) win.show() win.setWindowTitle('pyqtgraph example: Histogram LUT') cw = QtGui.QWidget() win.setCentralWidget(cw) -l = QtGui.QGridLayout() -cw.setLayout(l) -l.setSpacing(0) +layout = QtGui.QGridLayout() +cw.setLayout(layout) +layout.setSpacing(0) -v = pg.GraphicsView() +view = pg.GraphicsView() vb = pg.ViewBox() vb.setAspectLocked() -v.setCentralItem(vb) -l.addWidget(v, 0, 0, 3, 1) +view.setCentralItem(vb) +layout.addWidget(view, 0, 1, 3, 1) + +hist = pg.HistogramLUTWidget(gradientPosition="left") +layout.addWidget(hist, 0, 2) -w = pg.HistogramLUTWidget() -l.addWidget(w, 0, 1) monoRadio = QtGui.QRadioButton('mono') rgbaRadio = QtGui.QRadioButton('rgba') -l.addWidget(monoRadio, 1, 1) -l.addWidget(rgbaRadio, 2, 1) +layout.addWidget(monoRadio, 1, 2) +layout.addWidget(rgbaRadio, 2, 2) monoRadio.setChecked(True) + def setLevelMode(): mode = 'mono' if monoRadio.isChecked() else 'rgba' - w.setLevelMode(mode) + hist.setLevelMode(mode) + + monoRadio.toggled.connect(setLevelMode) data = pg.gaussianFilter(np.random.normal(size=(256, 256, 3)), (20, 20, 0)) @@ -52,7 +56,7 @@ img = pg.ImageItem(data) vb.addItem(img) vb.autoRange() -w.setImageItem(img) +hist.setImageItem(img) if __name__ == '__main__': pg.mkQApp().exec_() diff --git a/pyqtgraph/graphicsItems/HistogramLUTItem.py b/pyqtgraph/graphicsItems/HistogramLUTItem.py index 89c45568..20ed2d6f 100644 --- a/pyqtgraph/graphicsItems/HistogramLUTItem.py +++ b/pyqtgraph/graphicsItems/HistogramLUTItem.py @@ -46,6 +46,8 @@ class HistogramLUTItem(GraphicsWidget): black/white level lines is drawn, and the levels apply to all channels in the image. If 'rgba', then one set of levels is drawn for each channel. + gradientPosition 'right' (default) OR 'left'. Which side of the histogram to + put the LUT gradient. ================ =========================================================== """ @@ -53,12 +55,13 @@ class HistogramLUTItem(GraphicsWidget): sigLevelsChanged = QtCore.Signal(object) sigLevelChangeFinished = QtCore.Signal(object) - def __init__(self, image=None, fillHistogram=True, rgbHistogram=False, levelMode='mono'): + def __init__(self, image=None, fillHistogram=True, rgbHistogram=False, levelMode='mono', gradientPosition='right'): GraphicsWidget.__init__(self) self.lut = None self.imageItem = lambda: None # fake a dead weakref self.levelMode = levelMode self.rgbHistogram = rgbHistogram + self.gradientPosition = gradientPosition self.layout = QtGui.QGraphicsGridLayout() self.setLayout(self.layout) @@ -69,7 +72,7 @@ class HistogramLUTItem(GraphicsWidget): self.vb.setMinimumWidth(45) self.vb.setMouseEnabled(x=False, y=True) self.gradient = GradientEditorItem() - self.gradient.setOrientation('right') + self.gradient.setOrientation(gradientPosition) self.gradient.loadPreset('grey') self.regions = [ LinearRegionItem([0, 1], 'horizontal', swapMode='block'), @@ -94,7 +97,9 @@ class HistogramLUTItem(GraphicsWidget): self.axis = AxisItem('left', linkView=self.vb, maxTickLength=-10, parent=self) self.layout.addItem(self.axis, 0, 0) self.layout.addItem(self.vb, 0, 1) - self.layout.addItem(self.gradient, 0, 2) + pos = (0, 2) if gradientPosition == 'right' else (2, 0) + self.layout.addItem(self.axis, 0, pos[0]) + self.layout.addItem(self.gradient, 0, pos[1]) self.range = None self.gradient.setFlag(self.gradient.ItemStacksBehindParent) self.vb.setFlag(self.gradient.ItemStacksBehindParent) @@ -134,7 +139,7 @@ class HistogramLUTItem(GraphicsWidget): plot.setFillLevel(None) def paint(self, p, *args): - if self.levelMode != 'mono': + if self.levelMode != 'mono' or not self.region.isVisible(): return pen = self.region.lines[0].pen @@ -145,11 +150,15 @@ class HistogramLUTItem(GraphicsWidget): p.setRenderHint(QtGui.QPainter.Antialiasing) for pen in [fn.mkPen((0, 0, 0, 100), width=3), pen]: p.setPen(pen) - p.drawLine(p1 + Point(0, 5), gradRect.bottomLeft()) - p.drawLine(p2 - Point(0, 5), gradRect.topLeft()) + if self.gradientPosition == 'right': + p.drawLine(p1 + Point(0, 5), gradRect.bottomLeft()) + p.drawLine(p2 - Point(0, 5), gradRect.topLeft()) + else: + p.drawLine(p1 + Point(0, 5), gradRect.bottomRight()) + p.drawLine(p2 - Point(0, 5), gradRect.topRight()) p.drawLine(gradRect.topLeft(), gradRect.topRight()) p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight()) - + def setHistogramRange(self, mn, mx, padding=0.1): """Set the Y range on the histogram plot. This disables auto-scaling.""" self.vb.enableAutoRange(self.vb.YAxis, False)