• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ghiggi / gpm_api / 13679277988

05 Mar 2025 03:17PM UTC coverage: 89.223% (-5.2%) from 94.43%
13679277988

push

github

web-flow
Update PMW Tutorial (#74)

* Fix gridlines removal for cartopy artist update

* Add TC-PRIMED tutorial

* Update PMW 1C tutorial

65 of 181 new or added lines in 10 files covered. (35.91%)

909 existing lines in 41 files now uncovered.

14911 of 16712 relevant lines covered (89.22%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.72
/gpm/tests/test_visualization/test_plot.py
1
# -----------------------------------------------------------------------------.
2
# MIT License
3

4
# Copyright (c) 2024 GPM-API developers
5
#
6
# This file is part of GPM-API.
7

8
# Permission is hereby granted, free of charge, to any person obtaining a copy
9
# of this software and associated documentation files (the "Software"), to deal
10
# in the Software without restriction, including without limitation the rights
11
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
# copies of the Software, and to permit persons to whom the Software is
13
# furnished to do so, subject to the following conditions:
14
#
15
# The above copyright notice and this permission notice shall be included in all
16
# copies or substantial portions of the Software.
17
#
18
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
# SOFTWARE.
25

26
# -----------------------------------------------------------------------------.
27
import platform
1✔
28

29
import cartopy.crs as ccrs
1✔
30
import numpy as np
1✔
31
import pytest
1✔
32
import xarray as xr
1✔
33
from matplotlib import pyplot as plt
1✔
34

35
import gpm.configs
1✔
36
from gpm.tests.test_visualization.utils import (
1✔
37
    expand_dims,
38
    get_test_name,
39
    save_and_check_figure,
40
    skip_tests_if_no_data,
41
)
42
from gpm.visualization import plot
1✔
43
from gpm.visualization.plot import add_map_inset
1✔
44

45
# Fixtures imported from gpm.tests.conftest:
46
# - orbit_dataarray
47
# - orbit_antimeridian_dataarray
48
# - orbit_pole_dataarray
49
# - orbit_nan_cross_track_dataarray
50
# - orbit_nan_along_track_dataarray
51
# - orbit_nan_lon_cross_track_dataarray
52
# - orbit_nan_lon_along_track_dataarray
53
# - grid_dataarray
54
# - grid_nan_lon_dataarray
55

56

57
pytestmark = pytest.mark.skipif(
1✔
58
    platform.system() == "Windows",
59
    reason="Figure comparison is skipped because of minor differences against Linux.",
60
)
61
skip_tests_if_no_data()
1✔
62

63

64
def test_is_generator() -> None:
1✔
65
    """Test the _is_generator function."""
66

67
    def generator():
1✔
UNCOV
68
        yield 1
×
69

70
    assert plot.is_generator(generator())
1✔
71
    assert plot.is_generator(i for i in range(10))
1✔
72
    assert not plot.is_generator([1, 2, 3])
1✔
73

74

75
def test_preprocess_figure_args() -> None:
1✔
76
    """Test the preprocess_figure_args function."""
77
    nothing = {}
1✔
78
    something = {"": 0}
1✔
79

80
    # Test with ax None
81
    _ = plot.preprocess_figure_args(None, fig_kwargs=nothing, subplot_kwargs=nothing)
1✔
82
    _ = plot.preprocess_figure_args(None, fig_kwargs=something, subplot_kwargs=nothing)
1✔
83
    _ = plot.preprocess_figure_args(None, fig_kwargs=nothing, subplot_kwargs=something)
1✔
84

85
    # Test with ax not None
86
    ax = plt.subplot()
1✔
87
    _ = plot.preprocess_figure_args(ax, fig_kwargs=nothing, subplot_kwargs=nothing)
1✔
88

89
    with pytest.raises(ValueError):
1✔
90
        plot.preprocess_figure_args(ax, fig_kwargs=something, subplot_kwargs=nothing)
1✔
91

92
    with pytest.raises(ValueError):
1✔
93
        plot.preprocess_figure_args(ax, fig_kwargs=nothing, subplot_kwargs=something)
1✔
94

95

96
def test_get_antimeridian_mask(
1✔
97
    orbit_antimeridian_dataarray: xr.DataArray,
98
) -> None:
99
    """Test the get_antimeridian_mask function."""
100
    lon = orbit_antimeridian_dataarray["lon"].data
1✔
101
    returned_mask = plot.get_antimeridian_mask(lon)
1✔
102
    # fmt: off
103
    expected_mask = np.array([
1✔
104
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
105
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
106
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
107
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
108
    ], dtype=bool)
109
    np.testing.assert_array_equal(returned_mask, expected_mask)
1✔
110

111

112
class TestPlotMap:
1✔
113
    """Test the plot_map function."""
114

115
    def test_orbit(
1✔
116
        self,
117
        orbit_dataarray: xr.DataArray,
118
    ) -> None:
119
        """Test plotting orbit data."""
120
        p = plot.plot_map(orbit_dataarray)
1✔
121
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
122

123
    def test_orbit_antimeridian_not_recentered(
1✔
124
        self,
125
        orbit_antimeridian_dataarray: xr.DataArray,
126
    ) -> None:
127
        """Test plotting orbit data going over the antimeridian."""
128
        p = plot.plot_map(orbit_antimeridian_dataarray)
1✔
129
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
130

131
    def test_orbit_antimeridian(
1✔
132
        self,
133
        orbit_antimeridian_dataarray: xr.DataArray,
134
    ) -> None:
135
        """Test plotting orbit data going over the antimeridian with recentering."""
136
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
137
        cmap = "Spectral"  # check that bad is set to 0 to avoid cartopy bug
1✔
138
        p = plot.plot_map(orbit_antimeridian_dataarray, cmap=cmap, subplot_kwargs={"projection": crs_proj})
1✔
139
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
140

141
    def test_orbit_antimeridian_with_nan_coordinates(
1✔
142
        self,
143
        orbit_antimeridian_dataarray: xr.DataArray,
144
    ) -> None:
145
        """Test plotting orbit data going over the antimeridian and with masked values due to nan coordinates."""
146
        orbit_antimeridian_dataarray["lon"].data[1, 2:6] = np.nan
1✔
147
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
148
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
149
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
150

151
    def test_orbit_antimeridian_projection(
1✔
152
        self,
153
        orbit_antimeridian_dataarray: xr.DataArray,
154
    ) -> None:
155
        """Test plotting orbit data going over the antimeridian on orthographic projection."""
156
        crs_proj = ccrs.Orthographic(180, 0)
1✔
157
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
158
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
159

160
    def test_orbit_antimeridian_not_masked(
1✔
161
        self,
162
        orbit_antimeridian_dataarray: xr.DataArray,
163
    ) -> None:
164
        """Test plotting orbit data going over the antimeridian without masking (recentered)."""
165
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
166
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
167
            p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
168
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
169

170
    def test_orbit_pole(
1✔
171
        self,
172
        orbit_pole_dataarray: xr.DataArray,
173
    ) -> None:
174
        """Test plotting orbit data going over the south pole."""
175
        p = plot.plot_map(orbit_pole_dataarray)
1✔
176
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
177

178
    def test_orbit_pole_projection(
1✔
179
        self,
180
        orbit_pole_dataarray: xr.DataArray,
181
    ) -> None:
182
        """Test plotting orbit data going over the south pole on orthographic projection."""
183
        crs_proj = ccrs.Orthographic(0, -90)
1✔
184
        p = plot.plot_map(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
185
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
186

187
    def test_orbit_xy_dim(
1✔
188
        self,
189
        orbit_dataarray: xr.DataArray,
190
    ) -> None:
191
        """Test plotting orbit data with x and y dimensions."""
192
        p = plot.plot_map(orbit_dataarray.rename({"cross_track": "y", "along_track": "x"}))
1✔
193
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
194

195
    def test_orbit_longitude_latitude_coords(
1✔
196
        self,
197
        orbit_dataarray: xr.DataArray,
198
    ) -> None:
199
        """Test plotting orbit data with longitude and latitude  coordinates."""
200
        p = plot.plot_map(orbit_dataarray.rename({"lon": "longitude", "lat": "latitude"}))
1✔
201
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
202

203
    ####------------------------------------------------------------------------
204
    #### - Test with NaN in the data
205

206
    def test_orbit_data_nan_cross_track(
1✔
207
        self,
208
        orbit_data_nan_cross_track_dataarray: xr.DataArray,
209
    ) -> None:
210
        """Test plotting orbit with NaN values in the data at cross-track edges."""
211
        p = plot.plot_map(orbit_data_nan_cross_track_dataarray)
1✔
212
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
213

214
    def test_orbit_data_nan_along_track(
1✔
215
        self,
216
        orbit_data_nan_along_track_dataarray: xr.DataArray,
217
    ) -> None:
218
        """Test plotting orbit with NaN values in the data at along-track edges."""
219
        p = plot.plot_map(orbit_data_nan_along_track_dataarray)
1✔
220
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
221

222
    def test_orbit_data_nan_values(
1✔
223
        self,
224
        orbit_dataarray: xr.DataArray,
225
    ) -> None:
226
        """Test plotting orbit with NaN values in the data at one cell."""
227
        orbit_dataarray.data[2, 2] = np.nan
1✔
228
        p = plot.plot_map(orbit_dataarray)
1✔
229
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
230

231
    def test_orbit_data_all_nan_values(
1✔
232
        self,
233
        orbit_dataarray: xr.DataArray,
234
    ) -> None:
235
        """Test plotting orbit data with some invalid values."""
236
        orbit_dataarray.data[1:4, 1:4] = np.nan
1✔
237
        p = plot.plot_map(orbit_dataarray)
1✔
238
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
239

240
    ####------------------------------------------------------------------------
241
    #### - Test with NaN coordinates
242

243
    def test_orbit_nan_coordinate_at_one_cell(
1✔
244
        self,
245
        orbit_dataarray: xr.DataArray,
246
    ) -> None:
247
        """Test plotting orbit data with NaN coordinates at one cell."""
248
        # NOTE: here we test linear interpolation of coordinates
249
        orbit_dataarray["lon"].data[1, 3] = np.nan
1✔
250
        orbit_dataarray["lat"].data[1, 3] = np.nan
1✔
251
        p = plot.plot_map(orbit_dataarray)
1✔
252
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
253

254
    @pytest.mark.skipif(platform.system() == "Windows", reason="Minor figure difference on Windows")
1✔
255
    def test_orbit_nan_coordinate_at_corners(
1✔
256
        self,
257
        orbit_dataarray: xr.DataArray,
258
    ) -> None:
259
        """Test plotting orbit data with NaN coordinates at the swath corners."""
260
        # NOTE: here we test nearest neighbour interpolation of coordinates
261
        orbit_dataarray["lon"].data[0:2, 0:2] = np.nan
1✔
262
        orbit_dataarray["lat"].data[0:2, 0:2] = np.nan
1✔
263
        p = plot.plot_map(orbit_dataarray)
1✔
264
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
265

266
    def test_orbit_nan_coordinate_at_cross_track_center(
1✔
267
        self,
268
        orbit_dataarray: xr.DataArray,
269
    ) -> None:
270
        """Test plotting orbit data with NaN coordinates at one cell on the cross-track centerline."""
271
        # NOTE: centerline used to identify contiguoues slices. So here assumed not contiguous.
272
        orbit_dataarray["lon"].data[2, 3] = np.nan
1✔
273
        orbit_dataarray["lat"].data[2, 3] = np.nan
1✔
274
        p = plot.plot_map(orbit_dataarray)
1✔
275
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
276

277
    def test_orbit_nan_outer_cross_track(
1✔
278
        self,
279
        orbit_nan_outer_cross_track_dataarray: xr.DataArray,
280
    ) -> None:
281
        """Test plotting orbit data with some NaN coordinates on the outer cross-track cells."""
282
        p = plot.plot_map(orbit_nan_outer_cross_track_dataarray)
1✔
283
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
284

285
    def test_orbit_nan_inner_cross_track(
1✔
286
        self,
287
        orbit_nan_inner_cross_track_dataarray: xr.DataArray,
288
    ) -> None:
289
        """Test plotting orbit data with all NaN coordinates on some inner cross-track cells."""
290
        p = plot.plot_map(orbit_nan_inner_cross_track_dataarray)
1✔
291
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
292

293
    def test_orbit_nan_slice_along_track(
1✔
294
        self,
295
        orbit_nan_slice_along_track_dataarray: xr.DataArray,
296
    ) -> None:
297
        """Test plotting orbit data with some NaN latitudes along-track."""
298
        p = plot.plot_map(orbit_nan_slice_along_track_dataarray)
1✔
299
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
300

301
    ####------------------------------------------------------------------------
302
    #### - Test cross-track/along-track view
303

304
    def test_orbit_cross_track(
1✔
305
        self,
306
        orbit_dataarray: xr.DataArray,
307
    ) -> None:
308
        """Test plotting orbit data."""
309
        p = plot.plot_map(orbit_dataarray.isel(along_track=0))
1✔
310
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
311

312
    def test_orbit_along_track(
1✔
313
        self,
314
        orbit_dataarray: xr.DataArray,
315
    ) -> None:
316
        """Test plotting orbit data."""
317
        p = plot.plot_map(orbit_dataarray.isel(cross_track=0))
1✔
318
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
319

320
    def test_orbit_cross_track_pole_projection(
1✔
321
        self,
322
        orbit_pole_dataarray: xr.DataArray,
323
    ) -> None:
324
        """Test plotting orbit cross-track view going over the south pole on orthographic projection."""
325
        crs_proj = ccrs.Orthographic(0, -90)
1✔
326
        p = plot.plot_map(orbit_pole_dataarray.isel(cross_track=0), subplot_kwargs={"projection": crs_proj})
1✔
327
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
328

329
    def test_orbit_along_track_pole_projection(
1✔
330
        self,
331
        orbit_pole_dataarray: xr.DataArray,
332
    ) -> None:
333
        """Test plotting orbit along-track view going over the south pole on orthographic projection."""
334
        crs_proj = ccrs.Orthographic(0, -90)
1✔
335
        p = plot.plot_map(orbit_pole_dataarray.isel(along_track=0), subplot_kwargs={"projection": crs_proj})
1✔
336
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
337

338
    def test_orbit_cross_track_nan_outer_cross_track(
1✔
339
        self,
340
        orbit_nan_outer_cross_track_dataarray: xr.DataArray,
341
    ) -> None:
342
        """Test plotting orbit cross-track view with some NaN coordinates on the outer cross-track cells."""
343
        p = plot.plot_map(orbit_nan_outer_cross_track_dataarray.isel(along_track=0))
1✔
344
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
345

346
    def test_orbit_cross_track_nan_inner_cross_track(
1✔
347
        self,
348
        orbit_nan_inner_cross_track_dataarray: xr.DataArray,
349
    ) -> None:
350
        """Test plotting orbit cross-track view with all NaN coordinates on some inner cross-track cells."""
351
        p = plot.plot_map(orbit_nan_inner_cross_track_dataarray.isel(along_track=0))
1✔
352
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
353

354
    def test_orbit_along_track_nan_slice_along_track(
1✔
355
        self,
356
        orbit_nan_slice_along_track_dataarray: xr.DataArray,
357
    ) -> None:
358
        """Test plotting orbit along-track view with some NaN latitudes along-track."""
359
        p = plot.plot_map(orbit_nan_slice_along_track_dataarray.isel(cross_track=0))
1✔
360
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
361

362
    ####------------------------------------------------------------------------
363
    #### - Test RGB options
364

365
    def test_orbit_rgb(
1✔
366
        self,
367
        orbit_dataarray: xr.DataArray,
368
    ) -> None:
369
        """Test plotting orbit RGB data."""
370
        orbit_dataarray = expand_dims(orbit_dataarray, 3, dim="rgb", axis=2)
1✔
371
        p = plot.plot_map(orbit_dataarray, rgb="rgb")
1✔
372
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
373

374
    def test_orbit_rgba(
1✔
375
        self,
376
        orbit_dataarray: xr.DataArray,
377
    ) -> None:
378
        """Test plotting orbit RGBA data."""
379
        orbit_dataarray = expand_dims(orbit_dataarray, 4, dim="rgb", axis=2)
1✔
380
        p = plot.plot_map(orbit_dataarray, rgb="rgb")
1✔
381
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
382

383
    def test_orbit_rgb_alpha_value(
1✔
384
        self,
385
        orbit_dataarray: xr.DataArray,
386
    ) -> None:
387
        """Test plotting orbit RGB data with alpha value."""
388
        orbit_dataarray = expand_dims(orbit_dataarray, 3, dim="rgb", axis=2)
1✔
389
        p = plot.plot_map(orbit_dataarray, rgb="rgb", alpha=0.4)
1✔
390
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
391

392
        # NOTE: alpha array not allowed currently
393

394
    def test_orbit_rgb_with_nan_coordinates(
1✔
395
        self,
396
        orbit_dataarray: xr.DataArray,
397
    ) -> None:
398
        """Test plotting orbit RGB data with some NaN coordinates (and thus masked pixels)."""
399
        orbit_dataarray_rgb = expand_dims(orbit_dataarray, 3, dim="rgb", axis=2)
1✔
400
        orbit_dataarray_rgb["lon"].data[3, 5:15] = np.nan
1✔
401
        p = plot.plot_map(orbit_dataarray_rgb, rgb="rgb")
1✔
402
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
403

404
    def test_orbit_rgb_antimeridian(
1✔
405
        self,
406
        orbit_antimeridian_dataarray: xr.DataArray,
407
    ) -> None:
408
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)."""
409
        orbit_dataarray_rgb = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
410
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
411
        p = plot.plot_map(orbit_dataarray_rgb, subplot_kwargs={"projection": crs_proj}, rgb="rgb")
1✔
412
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
413

414
    def test_orbit_rgb_antimeridian_with_nan_coordinates(
1✔
415
        self,
416
        orbit_antimeridian_dataarray: xr.DataArray,
417
    ) -> None:
418
        """Test plotting orbit RGB data going over the antimeridian and with masked values due to nan coordinates."""
419
        orbit_dataarray_rgb = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
420
        orbit_dataarray_rgb["lon"].data[1, 2:6] = np.nan
1✔
421
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
422
        p = plot.plot_map(orbit_dataarray_rgb, subplot_kwargs={"projection": crs_proj}, rgb="rgb")
1✔
423
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
424

425
    def test_orbit_rgb_antimeridian_not_masked(
1✔
426
        self,
427
        orbit_antimeridian_dataarray: xr.DataArray,
428
    ) -> None:
429
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)."""
430
        orbit_dataarray_rgb = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
431
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
432
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
433
            p = plot.plot_map(orbit_dataarray_rgb, subplot_kwargs={"projection": crs_proj}, rgb="rgb")
1✔
434
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
435

436
    def test_orbit_rgb_invalid(
1✔
437
        self,
438
        orbit_dataarray: xr.DataArray,
439
    ) -> None:
440
        """Test plotting orbit data with RGB flag on non RGB data."""
441
        with pytest.raises(ValueError):
1✔
442
            plot.plot_map(orbit_dataarray, rgb="rgb")
1✔
443

444
    ####------------------------------------------------------------------------
445
    #### Test colorbar kwargs
446

447
    def test_orbit_alpha_value(
1✔
448
        self,
449
        orbit_dataarray: xr.DataArray,
450
    ) -> None:
451
        """Test plotting orbit with alpha value."""
452
        p = plot.plot_map(orbit_dataarray, alpha=0.4)
1✔
453
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
454

455
    def test_orbit_alpha_array(
1✔
456
        self,
457
        orbit_dataarray: xr.DataArray,
458
    ) -> None:
459
        """Test plotting orbit with alpha array."""
460
        alpha_arr = np.ones(orbit_dataarray.shape) * np.linspace(0, 1, orbit_dataarray.shape[1])
1✔
461
        p = plot.plot_map(orbit_dataarray, alpha=alpha_arr)
1✔
462
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
463

464
    def test_orbit_alpha_nan_outer_cross_track(
1✔
465
        self,
466
        orbit_nan_outer_cross_track_dataarray: xr.DataArray,
467
    ) -> None:
468
        """Test plotting orbit data with some NaN coordinates on the outer cross-track cells and alpha array."""
469
        alpha_arr = np.ones(orbit_nan_outer_cross_track_dataarray.shape)
1✔
470
        alpha_arr = alpha_arr * np.linspace(0, 1, orbit_nan_outer_cross_track_dataarray.shape[1])
1✔
471
        p = plot.plot_map(orbit_nan_outer_cross_track_dataarray, alpha=alpha_arr)
1✔
472
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
473

474
    def test_orbit_cbar_kwargs(
1✔
475
        self,
476
        orbit_dataarray: xr.DataArray,
477
    ) -> None:
478
        """Test plotting orbit data with colorbar keyword arguments."""
479
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
480

481
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
482
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
483

484
    def test_orbit_horizontal_colorbar(
1✔
485
        self,
486
        orbit_dataarray: xr.DataArray,
487
    ) -> None:
488
        """Test plotting orbit data with a horizontal colorbar."""
489
        cbar_kwargs = {"orientation": "horizontal"}
1✔
490
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
491
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
492

493
    ####------------------------------------------------------------------------
494
    #### Test GRID options
495

496
    def test_grid(
1✔
497
        self,
498
        grid_dataarray: xr.DataArray,
499
    ) -> None:
500
        """Test plotting grid data."""
501
        p = plot.plot_map(grid_dataarray)
1✔
502
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
503

504
    def test_grid_nan_lon(
1✔
505
        self,
506
        grid_nan_lon_dataarray: xr.DataArray,
507
    ) -> None:
508
        """Test plotting grid data with NaN longitudes."""
509
        p = plot.plot_map(grid_nan_lon_dataarray)
1✔
510
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
511

512
    def test_grid_time_dim(
1✔
513
        self,
514
        grid_dataarray: xr.DataArray,
515
    ) -> None:
516
        """Test plotting grid data with time dimension."""
517
        grid_dataarray = expand_dims(grid_dataarray, 4, "time")
1✔
518
        with pytest.raises(ValueError):  # Expecting a 2D GPM field
1✔
519
            plot.plot_map(grid_dataarray)
1✔
520

521
    def test_grid_xy_dim(
1✔
522
        self,
523
        grid_dataarray: xr.DataArray,
524
    ) -> None:
525
        """Test plotting grid data with x and y dimensions."""
526
        p = plot.plot_map(grid_dataarray.rename({"lat": "y", "lon": "x"}))
1✔
527
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
528

529
    def test_grid_longitude_latitude_coords(
1✔
530
        self,
531
        grid_dataarray: xr.DataArray,
532
    ) -> None:
533
        """Test plotting grid data with longitude and latitude  coordinates."""
534
        p = plot.plot_map(grid_dataarray.rename({"lon": "longitude", "lat": "latitude"}))
1✔
535
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
536

537
    def test_invalid(
1✔
538
        self,
539
    ) -> None:
540
        """Test invalid data."""
541
        da = xr.DataArray()
1✔
542
        with pytest.raises(ValueError):
1✔
543
            plot.plot_map(da)
1✔
544

545
    ####------------------------------------------------------------------------
546
    #### Test map inset options
547
    def test_add_map_inset(self, orbit_dataarray: xr.DataArray):
1✔
548
        """Test the add_map_inset function."""
549
        p = plot.plot_map(orbit_dataarray)
1✔
550
        add_map_inset(
1✔
551
            ax=p.axes,
552
            loc="upper left",
553
            inset_height=0.2,
554
            projection=None,
555
            inside_figure=True,
556
            border_pad=0.02,
557
        )
558
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
559

560

561
class TestPlotImage:
1✔
562
    """Test the plot_image function."""
563

564
    def test_orbit(
1✔
565
        self,
566
        orbit_dataarray: xr.DataArray,
567
    ) -> None:
568
        """Test plotting orbit data."""
569
        p = plot.plot_image(orbit_dataarray.drop_vars(["lon", "lat"]))
1✔
570
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
571

572
    def test_orbit_without_coords(
1✔
573
        self,
574
        orbit_dataarray: xr.DataArray,
575
    ) -> None:
576
        """Test plotting orbit data without coordinates."""
577
        p = plot.plot_image(orbit_dataarray.drop_vars(["lon", "lat"]))
1✔
578
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
579

580
    def test_orbit_with_xy_dims(
1✔
581
        self,
582
        orbit_dataarray: xr.DataArray,
583
    ) -> None:
584
        """Test plotting orbit data with x and y dimensions."""
585
        p = plot.plot_image(orbit_dataarray.rename({"cross_track": "y", "along_track": "x"}))
1✔
586
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
587

588
    def test_orbit_alpha_array(
1✔
589
        self,
590
        orbit_dataarray: xr.DataArray,
591
    ) -> None:
592
        """Test plotting orbit with alpha array."""
593
        alpha_arr = np.ones(orbit_dataarray.shape) * np.linspace(0, 1, orbit_dataarray.shape[1])
1✔
594
        p = plot.plot_image(orbit_dataarray, alpha=alpha_arr)
1✔
595
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
596

597
    def test_orbit_with_fully_transparent_cbar(
1✔
598
        self,
599
        orbit_dataarray: xr.DataArray,
600
    ) -> None:
601
        """Test plotting orbit data with invisible colorbar."""
602
        p = plot.plot_image(orbit_dataarray, visible_colorbar=False)
1✔
603
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
604

605
    def test_orbit_without_cbar(
1✔
606
        self,
607
        orbit_dataarray: xr.DataArray,
608
    ) -> None:
609
        """Test plotting orbit data without colorbar."""
610
        p = plot.plot_image(orbit_dataarray, add_colorbar=False)
1✔
611
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
612

613
    def test_orbit_cbar_kwargs(
1✔
614
        self,
615
        orbit_dataarray: xr.DataArray,
616
    ) -> None:
617
        """Test plotting orbit data with colorbar keyword arguments."""
618
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
619

620
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
621
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
622

623
    def test_orbit_horizontal_colorbar(
1✔
624
        self,
625
        orbit_dataarray: xr.DataArray,
626
    ) -> None:
627
        """Test plotting orbit data with a horizontal colorbar."""
628
        cbar_kwargs = {"orientation": "horizontal"}
1✔
629
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
630
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
631

632
    def test_orbit_no_cbar(
1✔
633
        self,
634
        orbit_dataarray: xr.DataArray,
635
    ) -> None:
636
        """Test plotting orbit data without colorbar."""
637
        p = plot.plot_image(orbit_dataarray, add_colorbar=False)
1✔
638
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
639

640
    def test_grid(
1✔
641
        self,
642
        grid_dataarray: xr.DataArray,
643
    ) -> None:
644
        """Test plotting grid data."""
645
        p = plot.plot_image(grid_dataarray)
1✔
646
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
647

648
    def test_grid_without_coords(
1✔
649
        self,
650
        grid_dataarray: xr.DataArray,
651
    ) -> None:
652
        """Test plotting grid data without coordinates."""
653
        p = plot.plot_image(grid_dataarray.drop_vars(["lon", "lat"]))
1✔
654
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
655

656
    def test_grid_with_xy_dims(
1✔
657
        self,
658
        grid_dataarray: xr.DataArray,
659
    ) -> None:
660
        """Test plotting grid data with x and y dimensions."""
661
        p = plot.plot_image(grid_dataarray.rename({"lat": "y", "lon": "x"}))
1✔
662
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
663

664
    def test_grid_with_longitude_latitude_coords(
1✔
665
        self,
666
        grid_dataarray: xr.DataArray,
667
    ) -> None:
668
        """Test plotting grid data with x and y dimensions."""
669
        p = plot.plot_image(grid_dataarray.rename({"lat": "latitude", "lon": "longitude"}))
1✔
670
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
671

672
    def test_invalid(
1✔
673
        self,
674
    ) -> None:
675
        """Test invalid data."""
676
        da = xr.DataArray()
1✔
677
        with pytest.raises(ValueError):
1✔
678
            plot.plot_image(da)
1✔
679

680

681
class TestPlotMapMesh:
1✔
682
    """Test the plot_map_mesh function."""
683

684
    def test_orbit(
1✔
685
        self,
686
        orbit_dataarray: xr.DataArray,
687
    ) -> None:
688
        """Test plotting orbit data."""
689
        p = plot.plot_map_mesh(orbit_dataarray)
1✔
690
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
691

692
    # def test_orbit_antimeridian(  # Does not work, issue in cartopy
693
    #     self,
694
    #     orbit_antimeridian_dataarray: xr.DataArray,
695
    # ) -> None:
696
    #     """Test plotting orbit data going over the antimeridian"""
697

698
    #     p = plot.plot_map_mesh(orbit_antimeridian_dataarray)
699
    #     save_and_check_figure(figure=p.figure, name=get_test_name())
700

701
    def test_orbit_antimeridian_projection(
1✔
702
        self,
703
        orbit_antimeridian_dataarray: xr.DataArray,
704
    ) -> None:
705
        """Test plotting orbit data going over the antimeridian on orthographic projection."""
706
        crs_proj = ccrs.Orthographic(180, 0)
1✔
707
        p = plot.plot_map_mesh(
1✔
708
            orbit_antimeridian_dataarray,
709
            subplot_kwargs={"projection": crs_proj},
710
        )
711
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
712

713
    def test_orbit_pole(
1✔
714
        self,
715
        orbit_pole_dataarray: xr.DataArray,
716
    ) -> None:
717
        """Test plotting orbit data going over the south pole."""
718
        p = plot.plot_map_mesh(orbit_pole_dataarray)
1✔
719
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
720

721
    def test_orbit_pole_projection(
1✔
722
        self,
723
        orbit_pole_dataarray: xr.DataArray,
724
    ) -> None:
725
        """Test plotting orbit data going over the south pole on orthographic projection."""
726
        crs_proj = ccrs.Orthographic(0, -90)
1✔
727
        p = plot.plot_map_mesh(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
728
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
729

730
    def test_grid(
1✔
731
        self,
732
        grid_dataarray: xr.DataArray,
733
    ) -> None:
734
        """Test plotting grid data."""
735
        p = plot.plot_map_mesh(grid_dataarray)
1✔
736
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
737

738
    def test_grid_nan_lon(
1✔
739
        self,
740
        grid_nan_lon_dataarray: xr.DataArray,
741
    ) -> None:
742
        """Test plotting grid data with NaN longitudes."""
743
        p = plot.plot_map_mesh(grid_nan_lon_dataarray)
1✔
744
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
745

746

747
class TestPlotMapMeshCentroids:
1✔
748
    """Test the plot_map_mesh_centroids function."""
749

750
    def test_orbit(
1✔
751
        self,
752
        orbit_dataarray: xr.DataArray,
753
    ) -> None:
754
        """Test plotting orbit data."""
755
        p = plot.plot_map_mesh_centroids(orbit_dataarray)
1✔
756
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
757

758
    def test_grid(
1✔
759
        self,
760
        grid_dataarray: xr.DataArray,
761
    ) -> None:
762
        """Test plotting grid data."""
763
        p = plot.plot_map_mesh_centroids(grid_dataarray)
1✔
764
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
765

766

767
class TestPlotLabels:
1✔
768
    """Test the plot_labels function."""
769

770
    label_name = "label"
1✔
771

772
    @pytest.fixture
1✔
773
    def orbit_labels_dataarray(
1✔
774
        self,
775
        orbit_dataarray: xr.DataArray,
776
    ) -> xr.DataArray:
777
        """Create an orbit data array with label coordinates."""
778
        rng = np.random.default_rng(seed=0)
1✔
779
        labels = rng.integers(0, 10, size=orbit_dataarray.shape)
1✔
780
        return orbit_dataarray.assign_coords(
1✔
781
            {self.label_name: (("cross_track", "along_track"), labels)},
782
        )
783

784
    @pytest.fixture
1✔
785
    def grid_labels_dataarray(
1✔
786
        self,
787
        grid_dataarray: xr.DataArray,
788
    ) -> xr.DataArray:
789
        """Create a grid data array with label coordinates."""
790
        rng = np.random.default_rng(seed=0)
1✔
791
        labels = rng.integers(0, 10, size=grid_dataarray.shape)
1✔
792
        return grid_dataarray.assign_coords({self.label_name: (("lat", "lon"), labels)})
1✔
793

794
    def test_orbit(
1✔
795
        self,
796
        orbit_labels_dataarray: xr.DataArray,
797
    ) -> None:
798
        """Test plotting orbit data."""
799
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name)
1✔
800
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
801

802
    def test_orbit_dataset(
1✔
803
        self,
804
        orbit_labels_dataarray: xr.DataArray,
805
    ) -> None:
806
        """Test plotting orbit data from a dataset."""
807
        ds = xr.Dataset({self.label_name: orbit_labels_dataarray[self.label_name]})
1✔
808
        p = plot.plot_labels(ds, label_name=self.label_name)
1✔
809
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
810

811
    def test_orbit_labels_dataarray(
1✔
812
        self,
813
        orbit_labels_dataarray: xr.DataArray,
814
    ) -> None:
815
        """Test plotting orbit data from labels data array directly."""
816
        p = plot.plot_labels(orbit_labels_dataarray[self.label_name])
1✔
817
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
818

819
    def test_orbit_exceed_labels(
1✔
820
        self,
821
        orbit_labels_dataarray: xr.DataArray,
822
    ) -> None:
823
        """Test plotting orbit data with too many labels for colorbar."""
824
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name, max_n_labels=5)
1✔
825
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
826

827
    def test_grid(
1✔
828
        self,
829
        grid_labels_dataarray: xr.DataArray,
830
    ) -> None:
831
        """Test plotting grid data."""
832
        p = plot.plot_labels(grid_labels_dataarray, label_name=self.label_name)
1✔
833
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
834

835
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
836
    def test_generator(
1✔
837
        self,
838
        orbit_labels_dataarray: xr.DataArray,
839
    ) -> None:
840
        """Test plotting orbit data form a generator."""
841
        da_list = [
1✔
842
            (0, orbit_labels_dataarray),
843
            (1, orbit_labels_dataarray),
844
        ]
845
        generator = (t for t in da_list)
1✔
846

847
        p = plot.plot_labels(generator, label_name=self.label_name)  # only last plot is returned
1✔
848
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
849

850

851
class TestPlotPatches:
1✔
852
    """Test the plot_patches function."""
853

854
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
855
    def test_orbit(
1✔
856
        self,
857
        orbit_dataarray: xr.DataArray,
858
    ) -> None:
859
        """Test plotting orbit data."""
860
        da_list = [
1✔
861
            (0, orbit_dataarray),
862
            (1, orbit_dataarray),
863
        ]
864
        generator = (t for t in da_list)
1✔
865
        plot.plot_patches(generator)  # does not return plotter
1✔
866
        save_and_check_figure(name=get_test_name())
1✔
867

868
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
869
    def test_orbit_dataset(
1✔
870
        self,
871
        orbit_dataarray: xr.DataArray,
872
    ) -> None:
873
        """Test plotting orbit data from a dataset."""
874
        variable_name = "variable"
1✔
875
        ds = xr.Dataset({variable_name: orbit_dataarray})
1✔
876
        ds_list = [
1✔
877
            (0, ds),
878
            (1, ds),
879
        ]
880
        generator = (t for t in ds_list)
1✔
881

882
        # Test with missing variable
883
        with pytest.raises(ValueError):
1✔
884
            plot.plot_patches(generator)
1✔
885

886
        plot.plot_patches(generator, variable=variable_name)  # does not return plotter
1✔
887
        save_and_check_figure(name=get_test_name())
1✔
888

889
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
890
    def test_grid(
1✔
891
        self,
892
        grid_dataarray: xr.DataArray,
893
    ) -> None:
894
        """Test plotting grid data."""
895
        da_list = [
1✔
896
            (0, grid_dataarray),
897
            (1, grid_dataarray),
898
        ]
899
        generator = (t for t in da_list)
1✔
900
        plot.plot_patches(generator)  # does not return plotter
1✔
901
        save_and_check_figure(name=get_test_name())
1✔
902

903
    def test_invalid(
1✔
904
        self,
905
    ) -> None:
906
        """Test invalid data."""
907
        invalid_list = [
1✔
908
            (0, xr.DataArray()),
909
            (1, xr.DataArray()),
910
        ]
911
        generator = (t for t in invalid_list)
1✔
912
        plot.plot_patches(generator)  # passes without error
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc