Skip to content

Allow menu selection of ColorMap(s)#2779

Merged
j9ac9k merged 6 commits intopyqtgraph:masterfrom
pijyoi:histlvl
Nov 11, 2023
Merged

Allow menu selection of ColorMap(s)#2779
j9ac9k merged 6 commits intopyqtgraph:masterfrom
pijyoi:histlvl

Conversation

@pijyoi
Copy link
Copy Markdown
Contributor

@pijyoi pijyoi commented Jul 22, 2023

UPDATE: the scope of this PR has evolved from the original HistogramLevelsItem (analog to HistogramLUTItem) to ColorMapDisplayItem (analog to GradientEditorItem). The contents of this comment should be considered outdated.

HistogramLevelsItem is a simplified version of HistogramLUTItem.
Differences:

  1. supports only mono-channel images
  2. changes only levels, does not change LUT
  3. uses only ColorMap property from ImageItem. Expects that ColorMap has been set.
  4. does not make use of GradientEditorItem. Colormaps are non-editable.

The NonUniformImage example has been modified to use HistogramLevelsItem. It was originally using HistogramLUTItem but had been changed to ColorBarItem to avoid the monkey patch of color presets. Changing it to use HistogramLevelsItem makes the example closer to its original look.

@pijyoi pijyoi force-pushed the histlvl branch 2 times, most recently from bcac0ff to 3129baf Compare July 24, 2023 13:43
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Jul 26, 2023

As there is too much code overlap between HistogramLUTItem and its derivative HistogramLevelsItem, it would make more sense to add an option to HistogramLUTItem instead to disable its GradientEditorItem. (HistogramLevelsItem will be removed from this PR)

When so disabled, the GradientEditorItem is replaced with a DummyGradientWidget that merely displays the colormap that has been pre-set on the ImageItem.

@pijyoi pijyoi force-pushed the histlvl branch 2 times, most recently from a54d444 to 3778211 Compare July 27, 2023 12:59
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Jul 27, 2023

To make the levels-only mode closer in behavior to HistogramLUTItem, the widget will no longer obtain the colormap by ImageItem::getColorMap. Instead, the user will set the colormap by HistogramLUTItem.gradient.setColorMap.

Some warts:

  1. enableGradientEditor could use a better name --> renamed to useColorMaps
  2. no way to use this levels-only mode in ImageView. --> see example in Allow menu selection of ColorMap(s) #2779 (comment)

@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Jul 27, 2023

An example of usage.
It also demonstrates that using 256-entry LUTs have a large speed advantage over larger LUTs (according to PYQTGRAPHPROFILE="ImageItem.paint").
Setting useColorMaps=True will, as an additional side-effect, unconditionally use 256-entry LUTs, whereas useColorMaps=False will use the original behavior of 512-entry LUTs.

import numpy as np
import pyqtgraph as pg
pg.setConfigOption('useNumba', False)

rng = np.random.default_rng()
data = rng.rayleigh(size=(10240, 6144)).astype(np.float32)

pg.mkQApp()
glw = pg.GraphicsLayoutWidget()
glw.show()

imgitem = pg.ImageItem(axisOrder='row-major')
plot = glw.addPlot()
plot.addItem(imgitem)
hist = pg.HistogramLUTItem(image=imgitem, useColorMaps=True)
glw.addItem(hist)

# hist.gradient.setColorMap("viridis")
imgitem.setImage(data)

pg.exec()

print(imgitem.qimage.format())

@pijyoi pijyoi marked this pull request as ready for review July 29, 2023 14:26
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Jul 30, 2023

UPDATE: to reduce the scope of this PR, ColorMapDisplayItem has been removed.

ColorMapDisplayItem is also usable standalone without HistogramLUTItem.

import numpy as np
import pyqtgraph as pg

from pyqtgraph.graphicsItems.ColorMapDisplay import ColorMapDisplayItem

rng = np.random.default_rng()
data = rng.random(size=(256,256), dtype=np.float32)

pg.mkQApp()
glw = pg.GraphicsLayoutWidget()
glw.show()

imgitem = pg.ImageItem(image=data, axisOrder='row-major')
plot = glw.addPlot()
plot.addItem(imgitem)
cmdisp1 = ColorMapDisplayItem(orientation='vertical')
cmdisp2 = ColorMapDisplayItem(orientation='horizontal')
glw.addItem(cmdisp1)
glw.nextRow()
glw.addItem(cmdisp2)

cmdisp1.sigColorMapChanged.connect(imgitem.setColorMap)
cmdisp2.sigColorMapChanged.connect(imgitem.setColorMap)

pg.exec()

@pijyoi pijyoi changed the title HistogramLevelsItem ColorMapDisplayItem Aug 2, 2023
@pijyoi pijyoi force-pushed the histlvl branch 2 times, most recently from f3dd7e7 to e1703dd Compare August 5, 2023 03:20
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Aug 5, 2023

This is how the example in #2779 (comment) looks now
Screenshot 2023-08-05 122945

@pijyoi pijyoi force-pushed the histlvl branch 7 times, most recently from c61b9f5 to a65dc12 Compare August 12, 2023 03:47
@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Aug 13, 2023

An alternative to replacing GradientEditorItem with GradientShimItem is to simply replace GradientEditorItem's gradient selection context menu with ColorMapMenu, as is done in the last commit.

Advantages:

  1. no need to supply extra option useColorMaps=True. Existing users automatically get access to the non-gradient colormaps. option useColorMaps=True has been removed, preferable not to introduce more API

Disadvantages (due to GradientEditorItem):

  1. 256-entry colormaps will have 256 ticks rendered. hide the ticks when using loaded ColorMap
  2. non-uint8 image data will request for 512-entry LUT, which will result in a less efficient QImage format of RGBX8888 instead of Indexed8. change ImageItem to request for 256-entry LUT
  3. Inefficient: the internal native representation of a color stop is a Tick, which is a QGraphicsWidget.

Other differences:

  1. GradientEditorItem renders the colorbar as a QLinearGradient whereas GradientShimItem renders it as a 256-pixel QImage.

@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Aug 15, 2023

As GradientEditorItem is now endowed with the new ColorMapMenu, the original colormap parameter based on GradientWidget also automatically gets that new menu.

The proof of concept new colormap parameter is thus renamed to colormapex.
Both colormap and colormapex can be seen in action in examples/parametertree.py.

A decision should be made whether the old colormap should be left as is or replaced with colormapex.
The old colormap would have been more aptly named gradient.

@pijyoi
Copy link
Copy Markdown
Contributor Author

pijyoi commented Aug 16, 2023

The original ColorMapParameter has been renamed to GradientParameter
while ColorMapExParameter has been renamed to ColorMapParameter.

There is actually an examples/ScatterPlotWidget.py --> widgets.ScatterPlotWidget --> widgets.ColorMapWidget --> parametertree.GradientParameter. (where the arrow signifies "makes use of") (the new name GradientParameter is used to be less confusing)

If this is not a desirable change, it can be reverted.

@pijyoi pijyoi force-pushed the histlvl branch 6 times, most recently from 2ed4240 to b74f72d Compare August 25, 2023 10:53
@pijyoi pijyoi changed the title ColorMapDisplayItem Allow menu selection of ColorMap(s) Sep 5, 2023
@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Nov 11, 2023

Thanks for this PR @pijyoi sorry I let this sit idle for so long... this diff LGTM, ...having the gradient colormaps be different from the regular color maps always seemed less than...ideal. Merging!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants