holoviews icon indicating copy to clipboard operation
holoviews copied to clipboard

Match colorbar ticks to contour levels

Open vlvalenti opened this issue 2 years ago • 2 comments

Is your feature request related to a problem? Please describe.

Contourf plots are useful, however the mismatch between the colorbar ticks and the contour levels displayed on the plot is an issue for the overall understanding and meaning behind the plot. Viewers need to be able to tell what contour color levels represent what values, otherwise it's difficult to interpret a contour plot properly. The colorbar even shows the divisions, but doesn't match those divisions with the corresponding colorbar ticks so the viewer can tell precisely what the plot is showing.

Describe the solution you'd like

A clear and concise description of what you want to happen. When a contour plot is created, the contour intervals used to create color levels in the plot automatically is mapped to the colorbar tick values.

Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered. My workaround. After the contour plot has been created, I get the range of the colorbar, divide by the number of color levels in the plot, and create a Bokeh FixedTicker, which I then add to the plot. It can sometime be inaccurate, but maybe works 80% of the time. Comment out the last line and view the plot to see how the colorbar ticks mismatch without the workaround.

from bokeh.models import FixedTicker
import hvplot.xarray
import xarray as xr

data = xr.tutorial.open_dataset('air_temperature')
plot = data.isel(time=0).hvplot.contourf(x='lon', y='lat', levels=14, colorbar=True, width=700, height=500)
begin = plot.vdims[0].range[0]
end = plot.vdims[0].range[1]
cl = (end - begin) / 14

def frange(start, stop=None, step=None):
    # if set start=0.0 and step = 1.0 if not specified
    start = float(start)
    if stop == None:
        stop = start + 0.0
        start = 0.0
    if step == None:
        step = 1.0

    count = 0
    while True:
        temp = float(start + count * step)
        if step > 0 and temp >= stop:
            break
        elif step < 0 and temp <= stop:
            break
        yield temp
        count += 1

ticks = [begin]
for i in frange(begin, end, cl):
    ticks.append(i)
ticks.append(end)
    
ticker = FixedTicker(ticks=ticks)
plot.opts(colorbar_opts={'ticker': ticker})

The issue with this workaround is I eventually run into this issue if I try to save these plots.

It being built into hvplot would avoid the error (I think/hope?), and would also address the real issue of the viewer not being able to tell what values the contour levels are actually showing. I think it would also be a good idea to do this for holoviews contour plots as well.

vlvalenti avatar Apr 18 '22 23:04 vlvalenti

Illustrating the original post with examples:

  • the problem stated being the colobar ticks not matching the contour levels, as demonstrated here: image
  • the same plot after applying the workaround suggested, the colorbar ticks now match the contour levels: image

This behavior seems to be inherited from HoloViews directly, with which the first plot can be reproduced identically:

import holoviews as hv
import xarray as xr
hv.extension('bokeh')

data = xr.tutorial.open_dataset('air_temperature')
hvds = hv.Dataset(data.isel(time=0))
qm = hv.QuadMesh(hvds)
hv.operation.contours(qm, filled=True, levels=14).opts(colorbar=True, color_levels=14, height=500, width=700, line_alpha=0)

The same issue can be seen with the Matplotlib backend:

image

In HoloViews the ColorBarPlot element of the Matplotlib backend accepts a cbar_ticks which could allow to more or less control the tick locations, there doesn't seem to be an equivalent of this parameter for the Bokeh backend.

maximlt avatar May 02 '22 23:05 maximlt

I'm transferring this issue to HoloViews since it seems that some new features are required at its level before it's made available to hvPlot.

maximlt avatar May 02 '22 23:05 maximlt

Hello, I just wanted to reiterate how useful this feature would be for visualizing data with contours. The workaround shown often produces inaccuracies and errors. Thank you!

vlvalenti avatar Jan 04 '23 17:01 vlvalenti