Summary
When both levels and a custom norm (e.g., BoundaryNorm) are passed to plot_hist_with_contours, unexpected color mapping occurs because matplotlib's contourf() interprets both parameters independently.
Root Cause
In plot_contours (lines 1012-1013), there's logic to auto-create a BoundaryNorm from levels when norm is None:
if (norm is None) and (levels is not None) and (len(levels) >= 2):
norm = mpl.colors.BoundaryNorm(levels, 256, clip=True)
However, in plot_hist_with_contours, this logic is absent. When a user provides:
levels=[0.1, 0.3, 0.5, 0.7, 0.9]
norm=BoundaryNorm([vmin, ..., vmax], ncolors)
The levels and norm.boundaries may not match, causing:
- Contour lines at different values than color transitions
- Inconsistent colorbar ticks
Workaround
Pass only levels to plot_hist_with_contours (omit norm):
hist.plot_hist_with_contours(
levels=np.linspace(vmin, vmax, 11),
# Do not pass norm - let matplotlib handle it
)
Or use plot_contours directly which handles this correctly:
hist.plot_contours(use_contourf=True, levels=np.linspace(...))
Environment
- solarwindpy version: current main
- matplotlib: 3.x
Summary
When both
levelsand a customnorm(e.g.,BoundaryNorm) are passed toplot_hist_with_contours, unexpected color mapping occurs because matplotlib'scontourf()interprets both parameters independently.Root Cause
In
plot_contours(lines 1012-1013), there's logic to auto-create aBoundaryNormfromlevelswhennorm is None:However, in
plot_hist_with_contours, this logic is absent. When a user provides:levels=[0.1, 0.3, 0.5, 0.7, 0.9]norm=BoundaryNorm([vmin, ..., vmax], ncolors)The
levelsandnorm.boundariesmay not match, causing:Workaround
Pass only
levelstoplot_hist_with_contours(omitnorm):Or use
plot_contoursdirectly which handles this correctly:Environment