|
18 | 18 | from openeo.udf import OpenEoUdfException |
19 | 19 | from openeo.util import deep_get, dict_no_none |
20 | 20 |
|
21 | | -if typing.TYPE_CHECKING: |
22 | | - # Imports for type checking only (circular import issue at runtime). |
23 | | - import matplotlib.colors |
24 | | - |
25 | 21 |
|
26 | 22 | class XarrayDataCube: |
27 | 23 | """ |
@@ -157,126 +153,6 @@ def save_to_file(self, path: Union[str, Path], fmt=None, **kwargs): |
157 | 153 | else: |
158 | 154 | raise ValueError(fmt) |
159 | 155 |
|
160 | | - def plot( |
161 | | - self, |
162 | | - title: str = None, |
163 | | - limits=None, |
164 | | - show_bandnames: bool = True, |
165 | | - show_dates: bool = True, |
166 | | - show_axeslabels: bool = False, |
167 | | - fontsize: float = 10., |
168 | | - oversample: float = 1, |
169 | | - cmap: Union[str, 'matplotlib.colors.Colormap'] = 'RdYlBu_r', |
170 | | - cbartext: str = None, |
171 | | - to_file: str = None, |
172 | | - to_show: bool = True |
173 | | - ): |
174 | | - """ |
175 | | - Visualize a :py:class:`XarrayDataCube` with matplotlib |
176 | | -
|
177 | | - :param datacube: data to plot |
178 | | - :param title: title text drawn in the top left corner (default: nothing) |
179 | | - :param limits: range of the contour plot as a tuple(min,max) (default: None, in which case the min/max is computed from the data) |
180 | | - :param show_bandnames: whether to plot the column names (default: True) |
181 | | - :param show_dates: whether to show the dates for each row (default: True) |
182 | | - :param show_axeslabels: whether to show the labels on the axes (default: False) |
183 | | - :param fontsize: font size in pixels (default: 10) |
184 | | - :param oversample: one value is plotted into oversample x oversample number of pixels (default: 1 which means each value is plotted as a single pixel) |
185 | | - :param cmap: built-in matplotlib color map name or ColorMap object (default: RdYlBu_r which is a blue-yellow-red rainbow) |
186 | | - :param cbartext: text on top of the legend (default: nothing) |
187 | | - :param to_file: filename to save the image to (default: None, which means no file is generated) |
188 | | - :param to_show: whether to show the image in a matplotlib window (default: True) |
189 | | -
|
190 | | - :return: None |
191 | | - """ |
192 | | - from matplotlib import pyplot |
193 | | - |
194 | | - data = self.get_array() |
195 | | - if limits is None: |
196 | | - vmin = data.min() |
197 | | - vmax = data.max() |
198 | | - else: |
199 | | - vmin = limits[0] |
200 | | - vmax = limits[1] |
201 | | - |
202 | | - # fill bands and t if missing |
203 | | - if 'bands' not in data.dims: |
204 | | - data = data.expand_dims(dim={'bands': ['band0']}) |
205 | | - if 't' not in data.dims: |
206 | | - data = data.expand_dims(dim={'t': [numpy.datetime64('today')]}) |
207 | | - if 'bands' not in data.coords: |
208 | | - data['bands'] = ['band0'] |
209 | | - if 't' not in data.coords: |
210 | | - data['t'] = [numpy.datetime64('today')] |
211 | | - |
212 | | - # align with plot |
213 | | - data = data.transpose('t', 'bands', 'y', 'x') |
214 | | - dpi = 100 |
215 | | - xres = len(data.x) / dpi |
216 | | - yres = len(data.y) / dpi |
217 | | - fs = fontsize / oversample |
218 | | - frame = 0.33 |
219 | | - |
220 | | - nrow = data.shape[0] |
221 | | - ncol = data.shape[1] |
222 | | - |
223 | | - fig = pyplot.figure(figsize=((ncol + frame) * xres * 1.1, (nrow + frame) * yres), dpi=int(dpi * oversample)) |
224 | | - gs = pyplot.GridSpec(nrow, ncol, wspace=0., hspace=0., top=nrow / (nrow + frame), bottom=0., |
225 | | - left=frame / (ncol + frame), right=1.) |
226 | | - |
227 | | - xmin = data.x.min() |
228 | | - xmax = data.x.max() |
229 | | - ymin = data.y.min() |
230 | | - ymax = data.y.max() |
231 | | - |
232 | | - # flip around if incorrect, this is in harmony with origin='lower' |
233 | | - if (data.x[0] > data.x[-1]): |
234 | | - data = data.reindex(x=list(reversed(data.x))) |
235 | | - if (data.y[0] > data.y[-1]): |
236 | | - data = data.reindex(y=list(reversed(data.y))) |
237 | | - |
238 | | - extent = (data.x[0], data.x[-1], data.y[0], data.y[-1]) |
239 | | - |
240 | | - for i in range(nrow): |
241 | | - for j in range(ncol): |
242 | | - im = data[i, j] |
243 | | - ax = pyplot.subplot(gs[i, j]) |
244 | | - ax.set_xlim(xmin, xmax) |
245 | | - ax.set_ylim(ymin, ymax) |
246 | | - img = ax.imshow(im, vmin=vmin, vmax=vmax, cmap=cmap, origin='lower', extent=extent) |
247 | | - ax.xaxis.set_tick_params(labelsize=fs) |
248 | | - ax.yaxis.set_tick_params(labelsize=fs) |
249 | | - if not show_axeslabels: |
250 | | - ax.set_axis_off() |
251 | | - ax.set_xticklabels([]) |
252 | | - ax.set_yticklabels([]) |
253 | | - if show_bandnames: |
254 | | - if i == 0: ax.text(0.5, 1.08, data.bands.values[j] + " (" + str(data.dtype) + ")", size=fs, |
255 | | - va="center", |
256 | | - ha="center", transform=ax.transAxes) |
257 | | - if show_dates: |
258 | | - if j == 0: ax.text(-0.08, 0.5, data.t.dt.strftime("%Y-%m-%d").values[i], size=fs, va="center", |
259 | | - ha="center", rotation=90, transform=ax.transAxes) |
260 | | - |
261 | | - if title is not None: |
262 | | - fig.text(0., 1., title.split('/')[-1], size=fs, va="top", ha="left", weight='bold') |
263 | | - |
264 | | - cbar_ax = fig.add_axes([0.01, 0.1, 0.04, 0.5]) |
265 | | - if cbartext is not None: |
266 | | - fig.text(0.06, 0.62, cbartext, size=fs, va="bottom", ha="center") |
267 | | - cbar = fig.colorbar(img, cax=cbar_ax) |
268 | | - cbar.ax.tick_params(labelsize=fs) |
269 | | - cbar.outline.set_visible(False) |
270 | | - cbar.ax.tick_params(size=0) |
271 | | - cbar.ax.yaxis.set_tick_params(pad=0) |
272 | | - |
273 | | - if to_file is not None: |
274 | | - pyplot.savefig(str(to_file)) |
275 | | - if to_show: |
276 | | - pyplot.show() |
277 | | - |
278 | | - pyplot.close() |
279 | | - |
280 | 156 |
|
281 | 157 | class XarrayIO: |
282 | 158 | """ |
|
0 commit comments