I'm using the holoviz xarray extension (holoviews.xarray
) to visualize a gridded dataset with landcover classes. Plotting the data is straightforward with da.hvplot()
. This results however in a continuous colormap with standard tick labels, whereas I need the categories plotted using a specific colormap and their labels included in a legend.
So how can I plot gridded categorical data using Holoviews? My plot needs to:
- Have the categories plotted according to a specific colormap (hex color codes).
- Include a legend with labels
["water", "cirrus", ...]
. - Handle situations where the data do not contain all classes. Explanation, when using
da.hvplot(cmap=tuple(color_key.values())
whileda
does not contain all classes this typically results in a plot where the colorbar ticks do not match the color classes. - Have a legend outside the plotted data.
The best I got so far is the example provided below. But how can I move that legend out of the plot? Or is there a more straightforward solution?
import holoviews as hv
import hvplot.xarray
import numpy as np
import xarray as xr
color_key = {
"No Data": "#000000",
"Saturated / Defective": "#ff0000",
"Dark Area Pixels": "#2f2f2f",
"Cloud Shadows": "#643200",
"Vegetation": "#00a000",
"Bare Soils": "#ffe65a",
"water": "#0000ff",
"Clouds low probability / Unclassified": "#808080",
"Clouds medium probability": "#c0c0c0",
"Clouds high probability": "#ffffff",
"Cirrus": "#64c8ff",
"Snow / Ice": "#ff96ff",
}
# Generate sample data
nx = 40
ny = 70
xcoords = [37 + 0.1 * i for i in range(nx)]
ycoords = [5 + 0.2 * i for i in range(ny)]
data = np.random.randint(low=0, high=len(color_key), size=nx * ny).reshape(nx, ny)
da = xr.DataArray(
data,
dims=["x", "y"],
coords={"x": xcoords, "y": ycoords},
)
# Visualization
legend = hv.NdOverlay(
{
k: hv.Points([0, 0], label=f"{k}").opts(color=v, size=0, apply_ranges=False)
for k, v in color_key.items()
},
"Classification",
)
da.hvplot().opts(cmap=tuple(color_key.values())) * legend
You could either set
.opts(legend_location='right')
OR you can override the actual ticks on the colorbar using thecolorbar_opts
option and by providing a fixed ticker along withmajor_label_overrides
like this: