ImageItem: implement persistent default autolevels
Allow user to set whether to perform auto levels by default instead of having to specify it on each data change.
The original behavior is that if unspecified, autoLevels==True. i.e. the user needs to specify autoLevels=False explicitly on each data change.
The example from https://github.com/pyqtgraph/pyqtgraph/issues/2830#issuecomment-1746888360 becomes
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore
import numpy as np
rng = np.random.default_rng(0)
pg.mkQApp()
glw = pg.GraphicsLayoutWidget()
glw.show()
plot = pg.PlotItem()
img = pg.ImageItem(axisOrder='row-major', autoLevels=False)
assert img.getLevels() is None
plot.addItem(img)
hlut = pg.HistogramLUTItem()
hlut.setImageItem(img)
# HistogramLUTItem immediately sets levels [0, 1] to the ImageItem
assert img.getLevels() is not None
hlut.setHistogramRange(0, 10)
glw.addItem(plot, row=0, col=0)
glw.addItem(hlut, row=0, col=1)
# set the levels manually
img.setLevels([0, 4])
def update():
noise = rng.rayleigh(size=(100,100))
XY = np.sinc(np.linspace(-10, 10, 100))
s = rng.random(1)
data = s * 10 * np.abs(XY[:, np.newaxis] * XY)**2 + noise
img.setImage(data)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(100)
pg.exec()
Oh, a plug for https://github.com/pyqtgraph/pyqtgraph/pull/2779: if you are running off master, right-clicking on the colorbar now exposes all the colormaps bundled with pyqtgraph.
If I were to implement enableAutoLevels as a keyword argument for ImageItem to follow PColorMeshItem's API to allow setting during object instantiation, the API becomes weird for ImageItem.
ImageItem has a setOpts method that is called in both __init__ and setImage. If enableAutoLevels were implemented in setOpts, then it would become possible for the user to do the following:
setImage(..., autoLevels=<something>, enableAutoLevels=<something>)
Perhaps enableAutoLevels should be named as autoLevels. This is consistent with the rest of the keyword arguments.
Then in setImage, if autoLevels is present as a keyword argument, it will not get passed on to setOpts.
This is also intuitive in that setImage(autoLevels=<something>) is only supposed to override the persistent value temporarily.
I have reworked things to be more consistent with the API of ImageItem itself.
If the user wants to instantiate ImageItem with autoLevels=False,
- if the data type is float, they have to call
setLevelsmanually - if the data type is integer, they can leave out calling
setLevels, in which case levels is taken to be the min, max of the underlying data type. The above behavior is inherent to the implementation ofImageItem, and is not modified by this PR to retain compatibility.