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

ghiggi / gpm_api / 8295059095

15 Mar 2024 10:52AM UTC coverage: 84.86% (+3.1%) from 81.754%
8295059095

push

github

web-flow
Add pycolorbar for colormaps and colorbar configurations (#44)

* Add pycolorbar configuration files

* Fix cmap=None bug

* Enable plot levels argument

* Fix code indent

* Add pycolorbar dependency

* Fix bug for horizontal colorbars with ticklabels

* Fix deprecation warnings

* Remove utils_cmap code

* Refactor viz internals

* Swith from {} to None for default arguments

* Update package requirements

* Update dataset decoding

* Update tests data

502 of 524 new or added lines in 30 files covered. (95.8%)

24 existing lines in 10 files now uncovered.

8514 of 10033 relevant lines covered (84.86%)

0.85 hits per line

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

99.62
/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 cartopy.crs as ccrs
1✔
28
import pytest
1✔
29
from matplotlib import pyplot as plt
1✔
30
import numpy as np
1✔
31
import xarray as xr
1✔
32

33

34
import gpm.configs
1✔
35
from gpm.visualization import plot
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

43

44
skip_tests_if_no_data()
1✔
45

46

47
def test_is_generator() -> None:
1✔
48
    """Test the _is_generator function"""
49

50
    def generator():
1✔
UNCOV
51
        yield 1
×
52

53
    assert plot.is_generator(generator())
1✔
54
    assert plot.is_generator((i for i in range(10)))
1✔
55
    assert not plot.is_generator([1, 2, 3])
1✔
56

57

58
def test_preprocess_figure_args() -> None:
1✔
59
    """Test the preprocess_figure_args function"""
60

61
    nothing = {}
1✔
62
    something = {"": 0}
1✔
63

64
    # Test with ax None
65
    _ = plot.preprocess_figure_args(None, fig_kwargs=nothing, subplot_kwargs=nothing)
1✔
66
    _ = plot.preprocess_figure_args(None, fig_kwargs=something, subplot_kwargs=nothing)
1✔
67
    _ = plot.preprocess_figure_args(None, fig_kwargs=nothing, subplot_kwargs=something)
1✔
68

69
    # Test with ax not None
70
    ax = plt.subplot()
1✔
71
    _ = plot.preprocess_figure_args(ax, fig_kwargs=nothing, subplot_kwargs=nothing)
1✔
72

73
    with pytest.raises(ValueError):
1✔
74
        plot.preprocess_figure_args(ax, fig_kwargs=something, subplot_kwargs=nothing)
1✔
75

76
    with pytest.raises(ValueError):
1✔
77
        plot.preprocess_figure_args(ax, fig_kwargs=nothing, subplot_kwargs=something)
1✔
78

79

80
class TestGetDataArrayExtent:
1✔
81
    """Test the get_extent function"""
1✔
82

83
    def test_orbit(
1✔
84
        self,
85
        orbit_dataarray: xr.DataArray,
86
    ) -> None:
87
        """Test getting the extent of orbit data"""
88

89
        returned_extent = plot.get_dataarray_extent(orbit_dataarray)
1✔
90
        expected_extent = (-2.77663454, 22.65579744, -3.53830585, 18.64709521)
1✔
91
        np.testing.assert_allclose(returned_extent, expected_extent, rtol=1e-9)
1✔
92

93
    def test_grid(
1✔
94
        self,
95
        grid_dataarray: xr.DataArray,
96
    ) -> None:
97
        """Test getting the extent of grid data"""
98

99
        returned_extent = plot.get_dataarray_extent(grid_dataarray)
1✔
100
        expected_extent = (-5, 20, -5, 15)
1✔
101
        assert returned_extent == expected_extent
1✔
102

103

104
def test_get_antimeridian_mask(
1✔
105
    orbit_antimeridian_dataarray: xr.DataArray,
106
) -> None:
107
    """Test the get_antimeridian_mask function"""
108

109
    lon = orbit_antimeridian_dataarray["lon"].data
1✔
110
    returned_mask = plot.get_antimeridian_mask(lon)
1✔
111
    # fmt: off
112
    expected_mask = np.array([
1✔
113
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,],
114
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,],
115
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,],
116
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,],
117
    ], dtype=bool)
118
    np.testing.assert_array_equal(returned_mask, expected_mask)
1✔
119

120

121
class TestPlotMap:
1✔
122
    """Test the plot_map function"""
1✔
123

124
    def test_orbit(
1✔
125
        self,
126
        orbit_dataarray: xr.DataArray,
127
    ) -> None:
128
        """Test plotting orbit data"""
129

130
        p = plot.plot_map(orbit_dataarray)
1✔
131
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
132

133
    def test_orbit_antimeridian(
1✔
134
        self,
135
        orbit_antimeridian_dataarray: xr.DataArray,
136
    ) -> None:
137
        """Test plotting orbit data going over the antimeridian"""
138

139
        p = plot.plot_map(orbit_antimeridian_dataarray)
1✔
140
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
141

142
    def test_orbit_antimeridian_recentered(
1✔
143
        self,
144
        orbit_antimeridian_dataarray: xr.DataArray,
145
    ) -> None:
146
        """Test plotting orbit data going over the antimeridian with recentering"""
147

148
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
149
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
150
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
151

152
    def test_orbit_antimeridian_projection(
1✔
153
        self,
154
        orbit_antimeridian_dataarray: xr.DataArray,
155
    ) -> None:
156
        """Test plotting orbit data going over the antimeridian on orthographic projection"""
157

158
        crs_proj = ccrs.Orthographic(180, 0)
1✔
159
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
160
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
161

162
    def test_orbit_antimeridian_not_masked_recentered(
1✔
163
        self,
164
        orbit_antimeridian_dataarray: xr.DataArray,
165
    ) -> None:
166
        """Test plotting orbit data going over the antimeridian without masking (recentered)"""
167

168
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
169
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
170
            p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
171
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
172

173
    def test_orbit_pole(
1✔
174
        self,
175
        orbit_pole_dataarray: xr.DataArray,
176
    ) -> None:
177
        """Test plotting orbit data going over the south pole"""
178

179
        p = plot.plot_map(orbit_pole_dataarray)
1✔
180
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
181

182
    def test_orbit_pole_projection(
1✔
183
        self,
184
        orbit_pole_dataarray: xr.DataArray,
185
    ) -> None:
186
        """Test plotting orbit data going over the south pole on orthographic projection"""
187

188
        crs_proj = ccrs.Orthographic(0, -90)
1✔
189
        p = plot.plot_map(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
190
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
191

192
    ## Test data with nan
193

194
    def test_orbit_data_nan_cross_track(
1✔
195
        self,
196
        orbit_data_nan_cross_track_dataarray: xr.DataArray,
197
    ) -> None:
198
        """Test plotting orbit with NaN values in the data at cross-track edges"""
199

200
        p = plot.plot_map(orbit_data_nan_cross_track_dataarray)
1✔
201
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
202

203
    def test_orbit_data_nan_along_track(
1✔
204
        self,
205
        orbit_data_nan_along_track_dataarray: xr.DataArray,
206
    ) -> None:
207
        """Test plotting orbit with NaN values in the data at along-track edges"""
208

209
        p = plot.plot_map(orbit_data_nan_along_track_dataarray)
1✔
210
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
211

212
    def test_orbit_data_nan_values(
1✔
213
        self,
214
        orbit_dataarray: xr.DataArray,
215
    ) -> None:
216
        """Test plotting orbit with NaN values in the data at one cell"""
217

218
        orbit_dataarray.data[2, 2] = np.nan
1✔
219
        p = plot.plot_map(orbit_dataarray)
1✔
220
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
221

222
    #### Test with NaN coordinates
223

224
    def test_orbit_nan_coordinate_at_one_cell(
1✔
225
        self,
226
        orbit_dataarray: xr.DataArray,
227
    ) -> None:
228
        """Test plotting orbit data with NaN coordinates at one cell"""
229
        # NOTE: here we test linear interpolation of coordinates
230
        orbit_dataarray["lon"].data[1, 3] = np.nan
1✔
231
        orbit_dataarray["lat"].data[1, 3] = np.nan
1✔
232
        p = plot.plot_map(orbit_dataarray)
1✔
233
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
234

235
    def test_orbit_nan_coordinate_at_corners(
1✔
236
        self,
237
        orbit_dataarray: xr.DataArray,
238
    ) -> None:
239
        """Test plotting orbit data with NaN coordinates at the swath corners."""
240
        # NOTE: here we test nearest neighbour interpolation of coordinates
241
        orbit_dataarray["lon"].data[0:2, 0:2] = np.nan
1✔
242
        orbit_dataarray["lat"].data[0:2, 0:2] = np.nan
1✔
243
        p = plot.plot_map(orbit_dataarray)
1✔
244
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
245

246
    def test_orbit_nan_coordinate_at_cross_track_center(
1✔
247
        self,
248
        orbit_dataarray: xr.DataArray,
249
    ) -> None:
250
        """Test plotting orbit data with NaN coordinates at one cell on the cross-track centerline"""
251
        # NOTE: centerline used to identify contiguoues slices. So here assumed not contiguous.
252
        orbit_dataarray["lon"].data[2, 3] = np.nan
1✔
253
        orbit_dataarray["lat"].data[2, 3] = np.nan
1✔
254
        p = plot.plot_map(orbit_dataarray)
1✔
255
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
256

257
    def test_orbit_nan_outer_cross_track(
1✔
258
        self,
259
        orbit_nan_outer_cross_track_dataarray: xr.DataArray,
260
    ) -> None:
261
        """Test plotting orbit data with some NaN coordinates on the outer cross-track cells"""
262

263
        p = plot.plot_map(orbit_nan_outer_cross_track_dataarray)
1✔
264
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
265

266
    def test_orbit_nan_inner_cross_track(
1✔
267
        self,
268
        orbit_nan_inner_cross_track_dataarray: xr.DataArray,
269
    ) -> None:
270
        """Test plotting orbit data with all NaN coordinates on the outer cross-track cells"""
271

272
        p = plot.plot_map(orbit_nan_inner_cross_track_dataarray)
1✔
273
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
274

275
    def test_orbit_nan_slice_along_track(
1✔
276
        self,
277
        orbit_nan_slice_along_track_dataarray: xr.DataArray,
278
    ) -> None:
279
        """Test plotting orbit data with some NaN latitudes along-track"""
280

281
        p = plot.plot_map(orbit_nan_slice_along_track_dataarray)
1✔
282
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
283

284
    #### Test colorbar kwargs
285

286
    def test_orbit_cbar_kwargs(
1✔
287
        self,
288
        orbit_dataarray: xr.DataArray,
289
    ) -> None:
290
        """Test plotting orbit data with colorbar keyword arguments"""
291
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
292

293
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
294
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
295

296
    def test_orbit_horizontal_colorbar(
1✔
297
        self,
298
        orbit_dataarray: xr.DataArray,
299
    ) -> None:
300
        """Test plotting orbit data with a horizontal colorbar"""
301

302
        cbar_kwargs = {"orientation": "horizontal"}
1✔
303
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
304
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
305

306
    def test_orbit_rgb(
1✔
307
        self,
308
        orbit_dataarray: xr.DataArray,
309
    ) -> None:
310
        """Test plotting orbit RGB data"""
311

312
        orbit_dataarray = expand_dims(orbit_dataarray, 3, dim="rgb", axis=2)
1✔
313
        p = plot.plot_map(orbit_dataarray, rgb=True)
1✔
314
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
315

316
    def test_orbit_rgba(
1✔
317
        self,
318
        orbit_dataarray: xr.DataArray,
319
    ) -> None:
320
        """Test plotting orbit RGBA data"""
321

322
        orbit_dataarray = expand_dims(orbit_dataarray, 4, dim="rgb", axis=2)
1✔
323
        p = plot.plot_map(orbit_dataarray, rgb=True)
1✔
324
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
325

326
    def test_orbit_rgb_antimeridian_recentered(
1✔
327
        self,
328
        orbit_antimeridian_dataarray: xr.DataArray,
329
    ) -> None:
330
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)"""
331

332
        orbit_dataarray = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
333
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
334
        p = plot.plot_map(orbit_dataarray, subplot_kwargs={"projection": crs_proj}, rgb=True)
1✔
335
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
336

337
    def test_orbit_rgb_antimeridian_not_masked_recentered(
1✔
338
        self,
339
        orbit_antimeridian_dataarray: xr.DataArray,
340
    ) -> None:
341
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)"""
342

343
        orbit_dataarray = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
344
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
345
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
346
            p = plot.plot_map(orbit_dataarray, subplot_kwargs={"projection": crs_proj}, rgb=True)
1✔
347
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
348

349
    def test_orbit_rgb_invalid(
1✔
350
        self,
351
        orbit_dataarray: xr.DataArray,
352
    ) -> None:
353
        """Test plotting orbit data with RGB flag on non RGB data"""
354

355
        with pytest.raises(ValueError):
1✔
356
            plot.plot_map(orbit_dataarray, rgb=True)
1✔
357

358
    def test_orbit_invalid_values(
1✔
359
        self,
360
        orbit_dataarray: xr.DataArray,
361
    ) -> None:
362
        """Test plotting orbit data with some invalid values"""
363

364
        orbit_dataarray.data[1:4, 1:4] = np.nan
1✔
365
        p = plot.plot_map(orbit_dataarray)
1✔
366
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
367

368
    def test_grid(
1✔
369
        self,
370
        grid_dataarray: xr.DataArray,
371
    ) -> None:
372
        """Test plotting grid data"""
373

374
        p = plot.plot_map(grid_dataarray)
1✔
375
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
376

377
    def test_grid_nan_lon(
1✔
378
        self,
379
        grid_nan_lon_dataarray: xr.DataArray,
380
    ) -> None:
381
        """Test plotting grid data with NaN longitudes"""
382

383
        p = plot.plot_map(grid_nan_lon_dataarray)
1✔
384
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
385

386
    def test_grid_time_dim(
1✔
387
        self,
388
        grid_dataarray: xr.DataArray,
389
    ) -> None:
390
        """Test plotting grid data with time dimension"""
391

392
        grid_dataarray = expand_dims(grid_dataarray, 4, "time")
1✔
393
        with pytest.raises(ValueError):  # Expecting a 2D GPM field
1✔
394
            plot.plot_map(grid_dataarray)
1✔
395

396
    def test_invalid(
1✔
397
        self,
398
    ) -> None:
399
        """Test invalid data"""
400

401
        da = xr.DataArray()
1✔
402
        with pytest.raises(ValueError):
1✔
403
            plot.plot_map(da)
1✔
404

405

406
class TestPlotImage:
1✔
407
    """Test the plot_image function"""
1✔
408

409
    def test_orbit(
1✔
410
        self,
411
        orbit_dataarray: xr.DataArray,
412
    ) -> None:
413
        """Test plotting orbit data"""
414

415
        p = plot.plot_image(orbit_dataarray)
1✔
416
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
417

418
    def test_orbit_cbar_kwargs(
1✔
419
        self,
420
        orbit_dataarray: xr.DataArray,
421
    ) -> None:
422
        """Test plotting orbit data with colorbar keyword arguments"""
423
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
424

425
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
426
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
427

428
    def test_orbit_horizontal_colorbar(
1✔
429
        self,
430
        orbit_dataarray: xr.DataArray,
431
    ) -> None:
432
        """Test plotting orbit data with a horizontal colorbar"""
433

434
        cbar_kwargs = {"orientation": "horizontal"}
1✔
435
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
436
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
437

438
    def test_orbit_no_cbar(
1✔
439
        self,
440
        orbit_dataarray: xr.DataArray,
441
    ) -> None:
442
        """Test plotting orbit data without colorbar"""
443

444
        p = plot.plot_image(orbit_dataarray, add_colorbar=False)
1✔
445
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
446

447
    def test_grid(
1✔
448
        self,
449
        grid_dataarray: xr.DataArray,
450
    ) -> None:
451
        """Test plotting grid data"""
452

453
        p = plot.plot_image(grid_dataarray)
1✔
454
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
455

456
    def test_invalid(
1✔
457
        self,
458
    ) -> None:
459
        """Test invalid data"""
460

461
        da = xr.DataArray()
1✔
462
        with pytest.raises(ValueError):
1✔
463
            plot.plot_image(da)
1✔
464

465

466
class TestPlotMapMesh:
1✔
467
    """Test the plot_map_mesh function"""
1✔
468

469
    def test_orbit(
1✔
470
        self,
471
        orbit_dataarray: xr.DataArray,
472
    ) -> None:
473
        """Test plotting orbit data"""
474

475
        p = plot.plot_map_mesh(orbit_dataarray)
1✔
476
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
477

478
    # def test_orbit_antimeridian(  # Does not work, issue in cartopy
479
    #     self,
480
    #     orbit_antimeridian_dataarray: xr.DataArray,
481
    # ) -> None:
482
    #     """Test plotting orbit data going over the antimeridian"""
483

484
    #     p = plot.plot_map_mesh(orbit_antimeridian_dataarray)
485
    #     save_and_check_figure(figure=p.figure, name=get_test_name())
486

487
    def test_orbit_antimeridian_projection(
1✔
488
        self,
489
        orbit_antimeridian_dataarray: xr.DataArray,
490
    ) -> None:
491
        """Test plotting orbit data going over the antimeridian on orthographic projection"""
492

493
        crs_proj = ccrs.Orthographic(180, 0)
1✔
494
        p = plot.plot_map_mesh(
1✔
495
            orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj}
496
        )
497
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
498

499
    def test_orbit_pole(
1✔
500
        self,
501
        orbit_pole_dataarray: xr.DataArray,
502
    ) -> None:
503
        """Test plotting orbit data going over the south pole"""
504

505
        p = plot.plot_map_mesh(orbit_pole_dataarray)
1✔
506
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
507

508
    def test_orbit_pole_projection(
1✔
509
        self,
510
        orbit_pole_dataarray: xr.DataArray,
511
    ) -> None:
512
        """Test plotting orbit data going over the south pole on orthographic projection"""
513

514
        crs_proj = ccrs.Orthographic(0, -90)
1✔
515
        p = plot.plot_map_mesh(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
516
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
517

518
    def test_grid(
1✔
519
        self,
520
        grid_dataarray: xr.DataArray,
521
    ) -> None:
522
        """Test plotting grid data"""
523

524
        p = plot.plot_map_mesh(grid_dataarray)
1✔
525
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
526

527
    def test_grid_nan_lon(
1✔
528
        self,
529
        grid_nan_lon_dataarray: xr.DataArray,
530
    ) -> None:
531
        """Test plotting grid data with NaN longitudes"""
532

533
        p = plot.plot_map_mesh(grid_nan_lon_dataarray)
1✔
534
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
535

536

537
class TestPlotMapMeshCentroids:
1✔
538
    """Test the plot_map_mesh_centroids function"""
1✔
539

540
    def test_orbit(
1✔
541
        self,
542
        orbit_dataarray: xr.DataArray,
543
    ) -> None:
544
        """Test plotting orbit data"""
545

546
        p = plot.plot_map_mesh_centroids(orbit_dataarray)
1✔
547
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
548

549
    def test_grid(
1✔
550
        self,
551
        grid_dataarray: xr.DataArray,
552
    ) -> None:
553
        """Test plotting grid data"""
554

555
        p = plot.plot_map_mesh_centroids(grid_dataarray)
1✔
556
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
557

558

559
class TestPlotLabels:
1✔
560
    """Test the plot_labels function"""
1✔
561

562
    label_name = "label"
1✔
563

564
    @pytest.fixture
1✔
565
    def orbit_labels_dataarray(
1✔
566
        self,
567
        orbit_dataarray: xr.DataArray,
568
    ) -> xr.DataArray:
569
        """Create an orbit data array with label coordinates"""
570

571
        labels = np.random.randint(0, 10, orbit_dataarray.shape)
1✔
572
        orbit_dataarray = orbit_dataarray.assign_coords(
1✔
573
            {self.label_name: (("cross_track", "along_track"), labels)}
574
        )
575
        return orbit_dataarray
1✔
576

577
    @pytest.fixture
1✔
578
    def grid_labels_dataarray(
1✔
579
        self,
580
        grid_dataarray: xr.DataArray,
581
    ) -> xr.DataArray:
582
        """Create a grid data array with label coordinates"""
583

584
        labels = np.random.randint(0, 10, grid_dataarray.shape)
1✔
585
        grid_dataarray = grid_dataarray.assign_coords({self.label_name: (("lat", "lon"), labels)})
1✔
586
        return grid_dataarray
1✔
587

588
    def test_orbit(
1✔
589
        self,
590
        orbit_labels_dataarray: xr.DataArray,
591
    ) -> None:
592
        """Test plotting orbit data"""
593

594
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name)
1✔
595
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
596

597
    def test_orbit_dataset(
1✔
598
        self,
599
        orbit_labels_dataarray: xr.DataArray,
600
    ) -> None:
601
        """Test plotting orbit data from a dataset"""
602

603
        ds = xr.Dataset({self.label_name: orbit_labels_dataarray[self.label_name]})
1✔
604
        p = plot.plot_labels(ds, label_name=self.label_name)
1✔
605
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
606

607
    def test_orbit_labels_dataarray(
1✔
608
        self,
609
        orbit_labels_dataarray: xr.DataArray,
610
    ) -> None:
611
        """Test plotting orbit data from labels data array directly"""
612

613
        p = plot.plot_labels(orbit_labels_dataarray[self.label_name])
1✔
614
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
615

616
    def test_orbit_exceed_labels(
1✔
617
        self,
618
        orbit_labels_dataarray: xr.DataArray,
619
    ) -> None:
620
        """Test plotting orbit data with too many labels for colorbar"""
621

622
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name, max_n_labels=5)
1✔
623
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
624

625
    def test_grid(
1✔
626
        self,
627
        grid_labels_dataarray: xr.DataArray,
628
    ) -> None:
629
        """Test plotting grid data"""
630

631
        p = plot.plot_labels(grid_labels_dataarray, label_name=self.label_name)
1✔
632
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
633

634
    def test_generator(
1✔
635
        self,
636
        orbit_labels_dataarray: xr.DataArray,
637
        prevent_pyplot_show: None,
638
    ) -> None:
639
        """Test plotting orbit data form a generator"""
640

641
        da_list = [
1✔
642
            (0, orbit_labels_dataarray),
643
            (1, orbit_labels_dataarray),
644
        ]
645
        generator = (t for t in da_list)
1✔
646

647
        p = plot.plot_labels(generator, label_name=self.label_name)  # only last plot is returned
1✔
648
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
649

650

651
class TestPlotPatches:
1✔
652
    """Test the plot_patches function"""
1✔
653

654
    def test_orbit(
1✔
655
        self,
656
        orbit_dataarray: xr.DataArray,
657
        prevent_pyplot_show: None,
658
    ) -> None:
659
        """Test plotting orbit data"""
660

661
        da_list = [
1✔
662
            (0, orbit_dataarray),
663
            (1, orbit_dataarray),
664
        ]
665
        generator = (t for t in da_list)
1✔
666
        plot.plot_patches(generator)  # does not return plotter
1✔
667
        save_and_check_figure(name=get_test_name())
1✔
668

669
    def test_orbit_dataset(
1✔
670
        self,
671
        orbit_dataarray: xr.DataArray,
672
        prevent_pyplot_show: None,
673
    ) -> None:
674
        """Test plotting orbit data from a dataset"""
675

676
        variable_name = "variable"
1✔
677
        ds = xr.Dataset({variable_name: orbit_dataarray})
1✔
678
        ds_list = [
1✔
679
            (0, ds),
680
            (1, ds),
681
        ]
682
        generator = (t for t in ds_list)
1✔
683

684
        # Test with missing variable
685
        with pytest.raises(ValueError):
1✔
686
            plot.plot_patches(generator)
1✔
687

688
        plot.plot_patches(generator, variable=variable_name)  # does not return plotter
1✔
689
        save_and_check_figure(name=get_test_name())
1✔
690

691
    def test_grid(
1✔
692
        self,
693
        grid_dataarray: xr.DataArray,
694
        prevent_pyplot_show: None,
695
    ) -> None:
696
        """Test plotting grid data"""
697

698
        da_list = [
1✔
699
            (0, grid_dataarray),
700
            (1, grid_dataarray),
701
        ]
702
        generator = (t for t in da_list)
1✔
703
        plot.plot_patches(generator)  # does not return plotter
1✔
704
        save_and_check_figure(name=get_test_name())
1✔
705

706
    def test_invalid(
1✔
707
        self,
708
    ) -> None:
709
        """Test invalid data"""
710

711
        invalid_list = [
1✔
712
            (0, xr.DataArray()),
713
            (1, xr.DataArray()),
714
        ]
715
        generator = (t for t in invalid_list)
1✔
716
        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