You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Colorbar labels show log10-transformed values instead of original intensities when z-log scale is enabled #63
I'm Oriol from ALBA Synchrotron. We are using PlotPy for 2D data plotting in the open source project Taurus. I recently opened a PR for a small bug fix related to updating image data while the z-log scale is enabled: #62
However, I am opening this issue for another aspect related to the z-log scale which may require some discussion.
Right now, ImageItem calculates _log_data and uses it both for painting the image and for calculating the LUT range / colorbar scale. To me, this mixes two different concepts:
Physical data values, which are the values the user is interested in
Color mapping, which is only used for visual inspection
Usually, in scientific applications, the color mapping can be logarithmic (or use another type of normalization), but the legend, tooltip, and cursor still show the original data values. Currently, this is not the case: next to the color legend, I see the logarithmic values instead of the original image intensities. From my point of view, the expected behavior would be to show the original intensities, while mapping them to colors using the logarithmic scale.
Thanks for raising this — you're right, and the problem actually went beyond the color bar labels. The fix is in #86. Here is the approach we took.
Root cause
In Z-log mode, the LUT range of the image item (get_lut_range() / item.min, item.max) was itself expressed in base-10 logarithms. The color bar displays that range, so it showed log values. Every other consumer of the range also had to guess which unit it was in. The cursor and tooltip read item.data, so they were already right. Other places mixed the two units:
the contrast panel: its histogram is computed on the data, but its range selector used logarithms, so "Full range" or "Eliminate %" ended up applying data values as log bounds (single-color image);
cross sections and exports with apply_lut=True, which applied log coefficients to raw data;
set_data(lut_range=...), keep_lut_range, serialization and applications that store the range (e.g. DataLab).
Approach: the LUT range always uses data units
This is the same model as matplotlib's LogNorm: only the color mapping is logarithmic.
set_lut_range / get_lut_range / get_lut_range_full (and set_data(lut_range=...)) always use data units. In log mode, the LUT coefficients are computed internally from log10(vmin) and log10(vmax).
Color bar: the colormap axis switches to QwtLogScaleEngine, with bounds in data units (ticks at 1, 10, 100…, with minor ticks at 2, 4, 6, 8). Your feat/logscale_colorbar branch already used this scale engine, and I kept it. With the scale engine alone, though, the bar would still apply the colormap linearly along a logarithmic axis, so its colors would no longer match the image. The color bar is therefore drawn with a small LogScaleColorMap wrapper, which applies the item colormap to log10(value).
Contrast panel, cross sections and exports with apply_lut=True are now consistent, since everything is in data units.
Non-positive values: instead of clip(1), which made data between 0 and 1 render as a single color, values ≤ 0 are replaced by the smallest positive value of the data, so they get the lowest color of the colormap. NaN values are kept as they are.
Toggling: enabling the log scale sets the LUT range to the full range of the positive values; disabling it restores the previous linear range, as before.
Unsupported items: RGB images, 2D histograms, quad grids and image filters don't draw log data, so ZAxisLogTool now ignores them. The new supports_zaxis_log() method reports this.
The tool now notifies the LUT change (SIG_LUT_CHANGED), so the contrast panel and other listeners pick up the new range.
API note
In log mode, get_lut_range(), set_lut_range(), get_lut_range_full() and set_data(lut_range=...) now take and return data units instead of log10 values. If Taurus sets LUT ranges while the Z-log scale is active, you can now pass plain intensities.
Not included (possible follow-ups)
logarithmic X axis for the contrast histogram;
persistence of the Z-log state;
log support for QuadGridItem;
log colors for ImageFilterItem when it reuses the colormap of a source image in log mode.
This will ship in PlotPy 2.12.0. Feedback from Taurus would be very welcome — thanks again for the report and the initial colorbar patch!
Activity
PierreRaybaut commentedon Oct 29, 2026
Hi @ovallcorba,
Thanks for raising this — you're right, and the problem actually went beyond the color bar labels. The fix is in #86. Here is the approach we took.
Root cause
In Z-log mode, the LUT range of the image item (
get_lut_range()/item.min,item.max) was itself expressed in base-10 logarithms. The color bar displays that range, so it showed log values. Every other consumer of the range also had to guess which unit it was in. The cursor and tooltip readitem.data, so they were already right. Other places mixed the two units:apply_lut=True, which applied log coefficients to raw data;set_data(lut_range=...),keep_lut_range, serialization and applications that store the range (e.g. DataLab).Approach: the LUT range always uses data units
This is the same model as matplotlib's
LogNorm: only the color mapping is logarithmic.set_lut_range/get_lut_range/get_lut_range_full(andset_data(lut_range=...)) always use data units. In log mode, the LUT coefficients are computed internally fromlog10(vmin)andlog10(vmax).QwtLogScaleEngine, with bounds in data units (ticks at 1, 10, 100…, with minor ticks at 2, 4, 6, 8). Yourfeat/logscale_colorbarbranch already used this scale engine, and I kept it. With the scale engine alone, though, the bar would still apply the colormap linearly along a logarithmic axis, so its colors would no longer match the image. The color bar is therefore drawn with a smallLogScaleColorMapwrapper, which applies the item colormap tolog10(value).apply_lut=Trueare now consistent, since everything is in data units.clip(1), which made data between 0 and 1 render as a single color, values ≤ 0 are replaced by the smallest positive value of the data, so they get the lowest color of the colormap. NaN values are kept as they are.ZAxisLogToolnow ignores them. The newsupports_zaxis_log()method reports this.SIG_LUT_CHANGED), so the contrast panel and other listeners pick up the new range.API note
In log mode,
get_lut_range(),set_lut_range(),get_lut_range_full()andset_data(lut_range=...)now take and return data units instead of log10 values. If Taurus sets LUT ranges while the Z-log scale is active, you can now pass plain intensities.Not included (possible follow-ups)
QuadGridItem;ImageFilterItemwhen it reuses the colormap of a source image in log mode.This will ship in PlotPy 2.12.0. Feedback from Taurus would be very welcome — thanks again for the report and the initial colorbar patch!
PierreRaybaut commentedon Oct 29, 2026
Fixed by #86 (merged into
develop), will be part of PlotPy 2.12.0.ovallcorba commentedon Oct 29, 2026
Thanks @PierreRaybaut ! we will give test it as soon as we can.
Regards.