Coverage for C:\src\imod-python\imod\visualize\common.py: 14%
21 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-08 10:26 +0200
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-08 10:26 +0200
1import matplotlib
2import numpy as np
5def _cmapnorm_from_colorslevels(colors, levels):
6 """
7 Create ListedColormap and BoundaryNorm from colors (either a list of colors
8 or a named colormap) and a list of levels. Number of levels must be at least
9 two, and number of colors therefore least three.
11 In the case of a list of colors, the resulting colorbar looks like:
12 < color 0 | color 1 | color 2 ... n-1 | color n >
13 ^ ^ ^
14 level 0 level 1 level n-1
16 Parameters
17 ----------
19 colors : list of str, list of RGBA/RGBA tuples, colormap name (str), or matplotlib.colors.Colormap
20 If list, it should be a Matplotlib acceptable list of colors. Length N.
21 Accepts both tuples of (R, G, B) and hexidecimal (e.g. `#7ec0ee`).
22 If str, use an existing Matplotlib colormap. This function will
23 autmatically add distinctive colors for pixels lower or high than the given
24 min respectively max level.
25 If LinearSegmentedColormap, you can use something like
26 `matplotlib.cm.get_cmap('jet')` as input. This function will not alter
27 the colormap, so add under- and over-colors yourself.
29 Looking for good colormaps? Try: http://colorbrewer2.org/
30 Choose a colormap, and use the HEX JS array.
31 levels : listlike of floats or integers
32 Boundaries between the legend colors/classes. Length: N - 1.
34 Returns
35 -------
36 cmap : matplotlib.colors.ListedColormap
37 norm : matplotlib.colors.BoundaryNorm
38 """
39 # check number of levels
40 if len(levels) < 2:
41 raise ValueError(f"Number of levels {levels} should exceed 1.")
43 # check monotonic increasing levels
44 if not (np.diff(levels) > 0).all():
45 raise ValueError(f"Levels {levels} are not monotonic increasing.")
47 if isinstance(colors, matplotlib.colors.Colormap):
48 # use given cmap
49 cmap = colors
50 else:
51 nlevels = len(levels)
52 if isinstance(colors, str):
53 # Use given cmap, but fix the under and over colors
54 # The colormap (probably) does not have a nice under and over color.
55 # So we cant use `cmap = matplotlib.cm.get_cmap(colors)`
56 cmap = matplotlib.colormaps[colors]
57 colors = cmap(np.linspace(0, 1, nlevels + 1))
59 # Validate number of colors vs number of levels
60 ncolors = len(colors)
61 if not nlevels == ncolors - 1:
62 raise ValueError(
63 f"Incorrect number of levels. Number of colors is {ncolors},"
64 f" expected {ncolors - 1} levels, got {nlevels} levels instead."
65 )
66 # Create cmap from given list of colors
67 cmap = matplotlib.colors.ListedColormap(colors[1:-1])
68 cmap.set_under(
69 colors[0]
70 ) # this is the color for values smaller than raster.min()
71 cmap.set_over(
72 colors[-1]
73 ) # this is the color for values larger than raster.max()
74 norm = matplotlib.colors.BoundaryNorm(levels, cmap.N)
75 return cmap, norm