-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
map_widgets.py
136 lines (113 loc) · 5.34 KB
/
map_widgets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
"""Various ipywidgets that can be added to a map."""
import ipywidgets
from . import common
class Colorbar(ipywidgets.Output):
"""A matplotlib colorbar widget that can be added to the map."""
def __init__(
self,
vis_params=None,
cmap="gray",
discrete=False,
label=None,
orientation="horizontal",
transparent_bg=False,
font_size=9,
axis_off=False,
max_width=None,
**kwargs,
):
"""Add a matplotlib colorbar to the map.
Args:
vis_params (dict): Visualization parameters as a dictionary. See https://developers.google.com/earth-engine/guides/image_visualization for options.
cmap (str, optional): Matplotlib colormap. Defaults to "gray". See https://matplotlib.org/3.3.4/tutorials/colors/colormaps.html#sphx-glr-tutorials-colors-colormaps-py for options.
discrete (bool, optional): Whether to create a discrete colorbar. Defaults to False.
label (str, optional): Label for the colorbar. Defaults to None.
orientation (str, optional): Orientation of the colorbar, such as "vertical" and "horizontal". Defaults to "horizontal".
transparent_bg (bool, optional): Whether to use transparent background. Defaults to False.
font_size (int, optional): Font size for the colorbar. Defaults to 9.
axis_off (bool, optional): Whether to turn off the axis. Defaults to False.
max_width (str, optional): Maximum width of the colorbar in pixels. Defaults to None.
Raises:
TypeError: If the vis_params is not a dictionary.
ValueError: If the orientation is not either horizontal or vertical.
ValueError: If the provided min value is not scalar type.
ValueError: If the provided max value is not scalar type.
ValueError: If the provided opacity value is not scalar type.
ValueError: If cmap or palette is not provided.
"""
import matplotlib # pylint: disable=import-outside-toplevel
import numpy # pylint: disable=import-outside-toplevel
if max_width is None:
if orientation == "horizontal":
max_width = "270px"
else:
max_width = "100px"
if isinstance(vis_params, (list, tuple)):
vis_params = {"palette": list(vis_params)}
elif not vis_params:
vis_params = {}
if not isinstance(vis_params, dict):
raise TypeError("The vis_params must be a dictionary.")
if isinstance(kwargs.get("colors"), (list, tuple)):
vis_params["palette"] = list(kwargs["colors"])
width, height = self._get_dimensions(orientation, kwargs)
vmin = vis_params.get("min", kwargs.pop("vmin", 0))
if type(vmin) not in (int, float):
raise TypeError("The provided min value must be scalar type.")
vmax = vis_params.get("max", kwargs.pop("mvax", 1))
if type(vmax) not in (int, float):
raise TypeError("The provided max value must be scalar type.")
alpha = vis_params.get("opacity", kwargs.pop("alpha", 1))
if type(alpha) not in (int, float):
raise TypeError("The provided opacity or alpha value must be type scalar.")
if "palette" in vis_params.keys():
hexcodes = common.to_hex_colors(common.check_cmap(vis_params["palette"]))
if discrete:
cmap = matplotlib.colors.ListedColormap(hexcodes)
linspace = numpy.linspace(vmin, vmax, cmap.N + 1)
norm = matplotlib.colors.BoundaryNorm(linspace, cmap.N)
else:
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
"custom", hexcodes, N=256
)
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
elif cmap:
cmap = matplotlib.pyplot.get_cmap(cmap)
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
else:
raise ValueError(
'cmap keyword or "palette" key in vis_params must be provided.'
)
fig, ax = matplotlib.pyplot.subplots(figsize=(width, height))
cb = matplotlib.colorbar.ColorbarBase(
ax,
norm=norm,
alpha=alpha,
cmap=cmap,
orientation=orientation,
**kwargs,
)
label = label or vis_params.get("bands") or kwargs.pop("caption", None)
if label:
cb.set_label(label, fontsize=font_size)
if axis_off:
ax.set_axis_off()
ax.tick_params(labelsize=font_size)
# Set the background color to transparent.
if transparent_bg:
fig.patch.set_alpha(0.0)
super().__init__(layout=ipywidgets.Layout(width=max_width))
with self:
self.outputs = ()
matplotlib.pyplot.show()
def _get_dimensions(self, orientation, kwargs):
default_dims = {"horizontal": (3.0, 0.3), "vertical": (0.3, 3.0)}
if orientation in default_dims:
default = default_dims[orientation]
return (
kwargs.get("width", default[0]),
kwargs.get("height", default[1]),
)
raise ValueError(
f"orientation must be one of [{', '.join(default_dims.keys())}]."
)