Thanks for that suggestion - I looked through the Bokeh issues for categorical colorbars. It still doesn’t quite address exactly what I think would be a really great improvement to the holoviews contour plots. It seems like in order for a contour plot to accurately convey the values being presented in the colorbar is to have the colorbar ticks match each contour/color levels’ actual value range. This way the viewer can actually understand what values each color is depicting. It’s not just being able to format ticks or place them at certain values, but to actually match the color levels within the holoviews plot. Does that make sense? I can create a custom Ticker now with your suggestions, and created an imperfect workaround where I use the holoviews plots range and the number of color levels depicted to guess at where each contour level begins and ends but its not always cleanly on each level. I think an improvement to holoviews and hvplot contours is that when creating a colorbar for these plots to automatically use each color level value to create colorbar ticks. Would that be a reasonable feature request? Or would that still be a Bokeh issue?
There’s code below that shows my workaround and how it can be imperfect. I took a guess at how holoviews/hvplot creates the color level intervals. The first time selection appears to solve the problem, but then the next time selection is imperfect - the ticks don’t match each color level value cleanly. Let me know what you think.
import hvplot.xarray
from bokeh.models import FixedTicker
import xarray as xr
data = xr.tutorial.open_dataset('air_temperature')
d = data.air.isel(time=0)#time=1 for imperfection
c = d.hvplot.contourf(x='lon', y='lat', levels=14)
def colorbar_ticks(img):
info = img.vdims[0]
r = info.range
begin = r[0]
end = r[1]
sub = end - begin
cl = sub / 14 #divide by number of color levels in plot
ticks = []
for i in range(int(begin), int(end), int(cl)):
ticks.append(i)
ticker = FixedTicker(ticks=ticks)
return ticker
ticker = colorbar_ticks(c)
d.hvplot.contourf(x='lon', y='lat', levels=14, cmap='rainbow').opts(colorbar_opts={'ticker': ticker})