Open MrBeee opened 1 year ago
The colormap loaded by pg.colormap.get("viridis")
actually has 256 stops.
It is the squashed over-painting of these 256 ticks that results in the appearance of a black background.
@pijyoi
Thanks for your reply, but I'm afraid it is only a half-answer.
I checked the file viridis.csv
in the pyqtgraph\pyqtgraph\colors\maps\
folder.
Indeed it contains 256 ticks in lines 15 to 270. So you are right in that respect.
However, viridis is defined again in the file GradientEditorItem.py
where the definition is as follows:
('viridis', {'ticks': [(0.0, (68, 1, 84, 255)), (0.25, (58, 82, 139, 255)), (0.5, (32, 144, 140, 255)), (0.75, (94, 201, 97, 255)), (1.0, (253, 231, 36, 255))], 'mode': 'rgb'})
In my view you should not have two different colormap definitions that carry the same name in the same software package. This is utterly confusing for the end user.
In my view, GradientEditorItem.py
should also pull its resources from the pyqtgraph\pyqtgraph\colors\maps\
folder,
using cmap = pg.colormap.get(item)
.
To create a list with colormaps to chose from, it may have a built-in default list using some default 'limits'
E.g. self.limits = ['thermal', 'flame', 'yellowy', 'bipolar', 'spectrum', 'cyclic', 'greyclip', 'grey', 'viridis', 'inferno', 'plasma', 'magma']
This way, the list can be overruled as a 'limits' option by the end user. But for consistency, the colormaps should always be read from pyqtgraph\pyqtgraph\colors\maps\
.
There are three pyqtgraph examples that define the colormap using cmap = colormap.get('viridis')
. These are MultiDataPlot.py
, PColorMeshItem.py
, and PColorMeshItem.py
.
In these cases there's no 'black background' in the tickmark area, so they (somehow) get their colormap directly from GradientEditorItem.py
The bug (feature?) that I reported only occurs when you define a colormap in a parameter list as shown earlier in the 'Code to reproduce'
Another reason to avoid the use of GradientEditorItem.py
is the occurence of a NotImplementedError
when editing hsv colormaps. I don't want end users to be confronted with this error. To me it seems this file needs a bit of extra work...
The gradients in GradientEditorItem
pre-date the colormaps stored in pyqtgraph/colors/maps
. The former date back to 2012, while the latter are a fairly recent addition (2021/06). Except for GradientEditorItem
, most GraphicsItem
s make use of the pyqtgraph/colors/maps
.
I don't understand your comment about MultiDataPlot.py
. It doesn't show a colorbar to begin with.
As for PColorMeshItem.py
, it shows a colorbar using ColorBarItem
, which doesn't display ticks to begin with.
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
pg.mkQApp()
cmap = pg.colormap.get('viridis')
main = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout()
main.setLayout(layout)
layout.addWidget(QtWidgets.QLabel('GradientWidget loadPreset'))
gw1 = pg.GradientWidget()
gw1.loadPreset('viridis')
layout.addWidget(gw1)
layout.addWidget(QtWidgets.QLabel('GradientWidget setColorMap'))
gw2 = pg.GradientWidget()
gw2.setColorMap(cmap)
layout.addWidget(gw2)
layout.addWidget(QtWidgets.QLabel('ColorBarItem'))
gv = pg.GraphicsView()
cbi = pg.ColorBarItem(colorMap=cmap, orientation='horizontal')
gv.setCentralItem(cbi)
layout.addWidget(gv)
main.resize(200, 200)
main.show()
pg.exec()
Thanks for explaining the history about GradientEditorItem
. And looking a bit more into examples that use that widget, I think I mixed up using cmap = pg.colormap.get('viridis')
to define a value in dict(name='ColorMap', type='colormap', value=cmap),
with the use of loadPreset()
, as demonstrated in the example GradientWidget.py
:
w4 = pg.GradientWidget(orientation='left')
w4.loadPreset('spectrum')
But that still begs the questions;
colorParams = [
dict(name='Color Settings', type='group', children=[
dict(name='ColorMap', type='colormap', value=cmap),
]),
]
Bottom line, the 70 available colormaps in the folder pyqtgraph\pyqtgraph\colors\maps\
and the 12 colormaps in the GradientEditorItem.py
are out of sync.
Presently there is no insightful widget (apart from a plain 'list') that allows for selecting one of these 70 colormaps.
That's why I suggested a solution in discussion issue 2788
Cheers.
PS: thanks for the example code above. If you stretch the main window horizontally, you'll start to notice the individual 256 ticks. At the same time, you see there's no difference in the color gradient between the bar based upon 5 ticks (top) and the one based upon 256 ticks (bottom). So there's no value in applying 256 points. Maybe this was the easiest way to copy stuff from matplotlib, but it certainly wasn't the most clever way...
How do you get the list of 12 available gradient names you can chose from ? How do you set one of these as a colormap value in the code I showed earlier above:
import pyqtgraph as pg
import pyqtgraph.parametertree as ptree
from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
print(list(Gradients.keys()))
cmap = pg.ColorMap(*zip(*Gradients["viridis"]["ticks"]))
pg.mkQApp()
params = ptree.Parameter.create(name='Parameters', type='group', children=[
dict(name='ColorMap', type='colormap', value=cmap),
])
pt = ptree.ParameterTree(showHeader=False)
pt.setParameters(params)
pt.show()
pg.exec()
Thanks very much for going through the effort of creating this example. Much appreciated !
For folk new to the parameter tree (well for me at least) this isn't very obvious (Apart from the import statement, but in order to use this, you need to delve into the source code)
I believe from the discussion on this forum that GradientEditorItem
(the widget underpinning colormap
) is being replaced by another widget, so this may become less of an issue.
Nevertheless, it would be appreciated if class GradientEditorItem
(and/or it successor) would have two more methods:
Whereby in GradientEditorItem
, these methods could be defined as follows::
getGradientList():
return list(Gradients.keys())
getColormap(colormapName):
return pg.ColorMap(*zip(*Gradients[colormapName]["ticks"]))
Alternatively, your code could be included in any of the ParameterTree examples.
Cheers
PS: What is also needed is a manner to limit the nr of colormaps the user can choose from in the context menu. See the following example:
cmapLimits = ['thermal', flame', 'yellow']
params = ptree.Parameter.create(name='Parameters', type='group', limits=cmapLimits, children=[
dict(name='ColorMap', type='colormap', value=cmap),
])
Excuse me, do you know how to set the background color of gradients in GLViewWidget? I only found the function setBackgroundColor(), but it can only set fixed color values, not gradients.
Short description
When loading a colormap parameter, it defaults to a colormap with a gradient between black (left) and red (right) This default 'looks good' but may not be the colormap you would like to use as a default value'
You can provide a default colormap by giving a colormap as a starting value
Code to reproduce
Expected behavior
The viridis colorscheme should be loaded with 5 tickmarks, and a white background behind the tickmarks
Real behavior
The viridis colorscheme is loaded with 5 tickmarks, and a black background behind the tickmarks
Tested environment(s)
Additional context
None