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

ghiggi / gpm_api / 8501164034

31 Mar 2024 10:00PM UTC coverage: 87.857% (+0.2%) from 87.669%
8501164034

Pull #53

github

web-flow
Merge ad9383aa4 into 03a72041e
Pull Request #53: Refactor code style

670 of 758 new or added lines in 88 files covered. (88.39%)

332 existing lines in 24 files now uncovered.

9001 of 10245 relevant lines covered (87.86%)

0.88 hits per line

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

99.63
/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

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

55

56
pytestmark = pytest.mark.skipif(
1✔
57
    platform.system() == "Windows", reason="Minor figure differences on Windows"
58
)
59
skip_tests_if_no_data()
1✔
60

61

62
def test_is_generator() -> None:
1✔
63
    """Test the _is_generator function"""
64

65
    def generator():
1✔
UNCOV
66
        yield 1
×
67

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

72

73
def test_preprocess_figure_args() -> None:
1✔
74
    """Test the preprocess_figure_args function"""
75

76
    nothing = {}
1✔
77
    something = {"": 0}
1✔
78

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

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

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

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

94

95
class TestGetDataArrayExtent:
1✔
96
    """Test the get_extent function"""
1✔
97

98
    def test_orbit(
1✔
99
        self,
100
        orbit_dataarray: xr.DataArray,
101
    ) -> None:
102
        """Test getting the extent of orbit data"""
103

104
        returned_extent = plot.get_dataarray_extent(orbit_dataarray)
1✔
105
        expected_extent = (-2.77663454, 22.65579744, -3.53830585, 18.64709521)
1✔
106
        np.testing.assert_allclose(returned_extent, expected_extent, rtol=1e-9)
1✔
107

108
    def test_grid(
1✔
109
        self,
110
        grid_dataarray: xr.DataArray,
111
    ) -> None:
112
        """Test getting the extent of grid data"""
113

114
        returned_extent = plot.get_dataarray_extent(grid_dataarray)
1✔
115
        expected_extent = (-5, 20, -5, 15)
1✔
116
        assert returned_extent == expected_extent
1✔
117

118

119
def test_get_antimeridian_mask(
1✔
120
    orbit_antimeridian_dataarray: xr.DataArray,
121
) -> None:
122
    """Test the get_antimeridian_mask function"""
123

124
    lon = orbit_antimeridian_dataarray["lon"].data
1✔
125
    returned_mask = plot.get_antimeridian_mask(lon)
1✔
126
    # fmt: off
127
    expected_mask = np.array([
1✔
128
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,],
129
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,],
130
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,],
131
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,],
132
    ], dtype=bool)
133
    np.testing.assert_array_equal(returned_mask, expected_mask)
1✔
134

135

136
class TestPlotMap:
1✔
137
    """Test the plot_map function"""
1✔
138

139
    def test_orbit(
1✔
140
        self,
141
        orbit_dataarray: xr.DataArray,
142
    ) -> None:
143
        """Test plotting orbit data"""
144

145
        p = plot.plot_map(orbit_dataarray)
1✔
146
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
147

148
    def test_orbit_antimeridian(
1✔
149
        self,
150
        orbit_antimeridian_dataarray: xr.DataArray,
151
    ) -> None:
152
        """Test plotting orbit data going over the antimeridian"""
153

154
        p = plot.plot_map(orbit_antimeridian_dataarray)
1✔
155
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
156

157
    def test_orbit_antimeridian_recentered(
1✔
158
        self,
159
        orbit_antimeridian_dataarray: xr.DataArray,
160
    ) -> None:
161
        """Test plotting orbit data going over the antimeridian with recentering"""
162

163
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
164
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
165
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
166

167
    def test_orbit_antimeridian_projection(
1✔
168
        self,
169
        orbit_antimeridian_dataarray: xr.DataArray,
170
    ) -> None:
171
        """Test plotting orbit data going over the antimeridian on orthographic projection"""
172

173
        crs_proj = ccrs.Orthographic(180, 0)
1✔
174
        p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
175
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
176

177
    def test_orbit_antimeridian_not_masked_recentered(
1✔
178
        self,
179
        orbit_antimeridian_dataarray: xr.DataArray,
180
    ) -> None:
181
        """Test plotting orbit data going over the antimeridian without masking (recentered)"""
182

183
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
184
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
185
            p = plot.plot_map(orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
186
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
187

188
    def test_orbit_pole(
1✔
189
        self,
190
        orbit_pole_dataarray: xr.DataArray,
191
    ) -> None:
192
        """Test plotting orbit data going over the south pole"""
193

194
        p = plot.plot_map(orbit_pole_dataarray)
1✔
195
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
196

197
    def test_orbit_pole_projection(
1✔
198
        self,
199
        orbit_pole_dataarray: xr.DataArray,
200
    ) -> None:
201
        """Test plotting orbit data going over the south pole on orthographic projection"""
202

203
        crs_proj = ccrs.Orthographic(0, -90)
1✔
204
        p = plot.plot_map(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
205
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
206

207
    ## Test data with nan
208

209
    def test_orbit_data_nan_cross_track(
1✔
210
        self,
211
        orbit_data_nan_cross_track_dataarray: xr.DataArray,
212
    ) -> None:
213
        """Test plotting orbit with NaN values in the data at cross-track edges"""
214

215
        p = plot.plot_map(orbit_data_nan_cross_track_dataarray)
1✔
216
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
217

218
    def test_orbit_data_nan_along_track(
1✔
219
        self,
220
        orbit_data_nan_along_track_dataarray: xr.DataArray,
221
    ) -> None:
222
        """Test plotting orbit with NaN values in the data at along-track edges"""
223

224
        p = plot.plot_map(orbit_data_nan_along_track_dataarray)
1✔
225
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
226

227
    def test_orbit_data_nan_values(
1✔
228
        self,
229
        orbit_dataarray: xr.DataArray,
230
    ) -> None:
231
        """Test plotting orbit with NaN values in the data at one cell"""
232

233
        orbit_dataarray.data[2, 2] = np.nan
1✔
234
        p = plot.plot_map(orbit_dataarray)
1✔
235
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
236

237
    #### Test with NaN coordinates
238

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

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

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

273
    def test_orbit_nan_outer_cross_track(
1✔
274
        self,
275
        orbit_nan_outer_cross_track_dataarray: xr.DataArray,
276
    ) -> None:
277
        """Test plotting orbit data with some NaN coordinates on the outer cross-track cells"""
278

279
        p = plot.plot_map(orbit_nan_outer_cross_track_dataarray)
1✔
280
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
281

282
    def test_orbit_nan_inner_cross_track(
1✔
283
        self,
284
        orbit_nan_inner_cross_track_dataarray: xr.DataArray,
285
    ) -> None:
286
        """Test plotting orbit data with all NaN coordinates on the outer cross-track cells"""
287

288
        p = plot.plot_map(orbit_nan_inner_cross_track_dataarray)
1✔
289
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
290

291
    def test_orbit_nan_slice_along_track(
1✔
292
        self,
293
        orbit_nan_slice_along_track_dataarray: xr.DataArray,
294
    ) -> None:
295
        """Test plotting orbit data with some NaN latitudes along-track"""
296

297
        p = plot.plot_map(orbit_nan_slice_along_track_dataarray)
1✔
298
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
299

300
    #### Test colorbar kwargs
301

302
    def test_orbit_cbar_kwargs(
1✔
303
        self,
304
        orbit_dataarray: xr.DataArray,
305
    ) -> None:
306
        """Test plotting orbit data with colorbar keyword arguments"""
307
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
308

309
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
310
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
311

312
    def test_orbit_horizontal_colorbar(
1✔
313
        self,
314
        orbit_dataarray: xr.DataArray,
315
    ) -> None:
316
        """Test plotting orbit data with a horizontal colorbar"""
317

318
        cbar_kwargs = {"orientation": "horizontal"}
1✔
319
        p = plot.plot_map(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
320
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
321

322
    def test_orbit_rgb(
1✔
323
        self,
324
        orbit_dataarray: xr.DataArray,
325
    ) -> None:
326
        """Test plotting orbit RGB data"""
327

328
        orbit_dataarray = expand_dims(orbit_dataarray, 3, dim="rgb", axis=2)
1✔
329
        p = plot.plot_map(orbit_dataarray, rgb=True)
1✔
330
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
331

332
    def test_orbit_rgba(
1✔
333
        self,
334
        orbit_dataarray: xr.DataArray,
335
    ) -> None:
336
        """Test plotting orbit RGBA data"""
337

338
        orbit_dataarray = expand_dims(orbit_dataarray, 4, dim="rgb", axis=2)
1✔
339
        p = plot.plot_map(orbit_dataarray, rgb=True)
1✔
340
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
341

342
    def test_orbit_rgb_antimeridian_recentered(
1✔
343
        self,
344
        orbit_antimeridian_dataarray: xr.DataArray,
345
    ) -> None:
346
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)"""
347

348
        orbit_dataarray = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
349
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
350
        p = plot.plot_map(orbit_dataarray, subplot_kwargs={"projection": crs_proj}, rgb=True)
1✔
351
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
352

353
    def test_orbit_rgb_antimeridian_not_masked_recentered(
1✔
354
        self,
355
        orbit_antimeridian_dataarray: xr.DataArray,
356
    ) -> None:
357
        """Test plotting orbit RGB data going over the antimeridian without masking (recentered)"""
358

359
        orbit_dataarray = expand_dims(orbit_antimeridian_dataarray, 3, dim="rgb", axis=2)
1✔
360
        crs_proj = ccrs.PlateCarree(central_longitude=180)
1✔
361
        with gpm.config.set({"viz_hide_antimeridian_data": False}):
1✔
362
            p = plot.plot_map(orbit_dataarray, subplot_kwargs={"projection": crs_proj}, rgb=True)
1✔
363
            save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
364

365
    def test_orbit_rgb_invalid(
1✔
366
        self,
367
        orbit_dataarray: xr.DataArray,
368
    ) -> None:
369
        """Test plotting orbit data with RGB flag on non RGB data"""
370

371
        with pytest.raises(ValueError):
1✔
372
            plot.plot_map(orbit_dataarray, rgb=True)
1✔
373

374
    def test_orbit_invalid_values(
1✔
375
        self,
376
        orbit_dataarray: xr.DataArray,
377
    ) -> None:
378
        """Test plotting orbit data with some invalid values"""
379

380
        orbit_dataarray.data[1:4, 1:4] = np.nan
1✔
381
        p = plot.plot_map(orbit_dataarray)
1✔
382
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
383

384
    def test_grid(
1✔
385
        self,
386
        grid_dataarray: xr.DataArray,
387
    ) -> None:
388
        """Test plotting grid data"""
389

390
        p = plot.plot_map(grid_dataarray)
1✔
391
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
392

393
    def test_grid_nan_lon(
1✔
394
        self,
395
        grid_nan_lon_dataarray: xr.DataArray,
396
    ) -> None:
397
        """Test plotting grid data with NaN longitudes"""
398

399
        p = plot.plot_map(grid_nan_lon_dataarray)
1✔
400
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
401

402
    def test_grid_time_dim(
1✔
403
        self,
404
        grid_dataarray: xr.DataArray,
405
    ) -> None:
406
        """Test plotting grid data with time dimension"""
407

408
        grid_dataarray = expand_dims(grid_dataarray, 4, "time")
1✔
409
        with pytest.raises(ValueError):  # Expecting a 2D GPM field
1✔
410
            plot.plot_map(grid_dataarray)
1✔
411

412
    def test_invalid(
1✔
413
        self,
414
    ) -> None:
415
        """Test invalid data"""
416

417
        da = xr.DataArray()
1✔
418
        with pytest.raises(ValueError):
1✔
419
            plot.plot_map(da)
1✔
420

421

422
class TestPlotImage:
1✔
423
    """Test the plot_image function"""
1✔
424

425
    def test_orbit(
1✔
426
        self,
427
        orbit_dataarray: xr.DataArray,
428
    ) -> None:
429
        """Test plotting orbit data"""
430

431
        p = plot.plot_image(orbit_dataarray)
1✔
432
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
433

434
    def test_orbit_cbar_kwargs(
1✔
435
        self,
436
        orbit_dataarray: xr.DataArray,
437
    ) -> None:
438
        """Test plotting orbit data with colorbar keyword arguments"""
439
        cbar_kwargs = {"ticks": [0.1, 0.2, 0.4, 0.6, 0.8], "ticklabels": [42.5, 43, 44, 45, 46]}
1✔
440

441
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
442
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
443

444
    def test_orbit_horizontal_colorbar(
1✔
445
        self,
446
        orbit_dataarray: xr.DataArray,
447
    ) -> None:
448
        """Test plotting orbit data with a horizontal colorbar"""
449

450
        cbar_kwargs = {"orientation": "horizontal"}
1✔
451
        p = plot.plot_image(orbit_dataarray, cbar_kwargs=cbar_kwargs)
1✔
452
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
453

454
    def test_orbit_no_cbar(
1✔
455
        self,
456
        orbit_dataarray: xr.DataArray,
457
    ) -> None:
458
        """Test plotting orbit data without colorbar"""
459

460
        p = plot.plot_image(orbit_dataarray, add_colorbar=False)
1✔
461
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
462

463
    def test_grid(
1✔
464
        self,
465
        grid_dataarray: xr.DataArray,
466
    ) -> None:
467
        """Test plotting grid data"""
468

469
        p = plot.plot_image(grid_dataarray)
1✔
470
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
471

472
    def test_invalid(
1✔
473
        self,
474
    ) -> None:
475
        """Test invalid data"""
476

477
        da = xr.DataArray()
1✔
478
        with pytest.raises(ValueError):
1✔
479
            plot.plot_image(da)
1✔
480

481

482
class TestPlotMapMesh:
1✔
483
    """Test the plot_map_mesh function"""
1✔
484

485
    def test_orbit(
1✔
486
        self,
487
        orbit_dataarray: xr.DataArray,
488
    ) -> None:
489
        """Test plotting orbit data"""
490

491
        p = plot.plot_map_mesh(orbit_dataarray)
1✔
492
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
493

494
    # def test_orbit_antimeridian(  # Does not work, issue in cartopy
495
    #     self,
496
    #     orbit_antimeridian_dataarray: xr.DataArray,
497
    # ) -> None:
498
    #     """Test plotting orbit data going over the antimeridian"""
499

500
    #     p = plot.plot_map_mesh(orbit_antimeridian_dataarray)
501
    #     save_and_check_figure(figure=p.figure, name=get_test_name())
502

503
    def test_orbit_antimeridian_projection(
1✔
504
        self,
505
        orbit_antimeridian_dataarray: xr.DataArray,
506
    ) -> None:
507
        """Test plotting orbit data going over the antimeridian on orthographic projection"""
508

509
        crs_proj = ccrs.Orthographic(180, 0)
1✔
510
        p = plot.plot_map_mesh(
1✔
511
            orbit_antimeridian_dataarray, subplot_kwargs={"projection": crs_proj}
512
        )
513
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
514

515
    def test_orbit_pole(
1✔
516
        self,
517
        orbit_pole_dataarray: xr.DataArray,
518
    ) -> None:
519
        """Test plotting orbit data going over the south pole"""
520

521
        p = plot.plot_map_mesh(orbit_pole_dataarray)
1✔
522
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
523

524
    def test_orbit_pole_projection(
1✔
525
        self,
526
        orbit_pole_dataarray: xr.DataArray,
527
    ) -> None:
528
        """Test plotting orbit data going over the south pole on orthographic projection"""
529

530
        crs_proj = ccrs.Orthographic(0, -90)
1✔
531
        p = plot.plot_map_mesh(orbit_pole_dataarray, subplot_kwargs={"projection": crs_proj})
1✔
532
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
533

534
    def test_grid(
1✔
535
        self,
536
        grid_dataarray: xr.DataArray,
537
    ) -> None:
538
        """Test plotting grid data"""
539

540
        p = plot.plot_map_mesh(grid_dataarray)
1✔
541
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
542

543
    def test_grid_nan_lon(
1✔
544
        self,
545
        grid_nan_lon_dataarray: xr.DataArray,
546
    ) -> None:
547
        """Test plotting grid data with NaN longitudes"""
548

549
        p = plot.plot_map_mesh(grid_nan_lon_dataarray)
1✔
550
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
551

552

553
class TestPlotMapMeshCentroids:
1✔
554
    """Test the plot_map_mesh_centroids function"""
1✔
555

556
    def test_orbit(
1✔
557
        self,
558
        orbit_dataarray: xr.DataArray,
559
    ) -> None:
560
        """Test plotting orbit data"""
561

562
        p = plot.plot_map_mesh_centroids(orbit_dataarray)
1✔
563
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
564

565
    def test_grid(
1✔
566
        self,
567
        grid_dataarray: xr.DataArray,
568
    ) -> None:
569
        """Test plotting grid data"""
570

571
        p = plot.plot_map_mesh_centroids(grid_dataarray)
1✔
572
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
573

574

575
class TestPlotLabels:
1✔
576
    """Test the plot_labels function"""
1✔
577

578
    label_name = "label"
1✔
579

580
    @pytest.fixture()
1✔
581
    def orbit_labels_dataarray(
1✔
582
        self,
583
        orbit_dataarray: xr.DataArray,
584
    ) -> xr.DataArray:
585
        """Create an orbit data array with label coordinates"""
586

587
        labels = np.random.randint(0, 10, orbit_dataarray.shape)
1✔
588
        return orbit_dataarray.assign_coords(
1✔
589
            {self.label_name: (("cross_track", "along_track"), labels)}
590
        )
591

592
    @pytest.fixture()
1✔
593
    def grid_labels_dataarray(
1✔
594
        self,
595
        grid_dataarray: xr.DataArray,
596
    ) -> xr.DataArray:
597
        """Create a grid data array with label coordinates"""
598

599
        labels = np.random.randint(0, 10, grid_dataarray.shape)
1✔
600
        return grid_dataarray.assign_coords({self.label_name: (("lat", "lon"), labels)})
1✔
601

602
    def test_orbit(
1✔
603
        self,
604
        orbit_labels_dataarray: xr.DataArray,
605
    ) -> None:
606
        """Test plotting orbit data"""
607

608
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name)
1✔
609
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
610

611
    def test_orbit_dataset(
1✔
612
        self,
613
        orbit_labels_dataarray: xr.DataArray,
614
    ) -> None:
615
        """Test plotting orbit data from a dataset"""
616

617
        ds = xr.Dataset({self.label_name: orbit_labels_dataarray[self.label_name]})
1✔
618
        p = plot.plot_labels(ds, label_name=self.label_name)
1✔
619
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
620

621
    def test_orbit_labels_dataarray(
1✔
622
        self,
623
        orbit_labels_dataarray: xr.DataArray,
624
    ) -> None:
625
        """Test plotting orbit data from labels data array directly"""
626

627
        p = plot.plot_labels(orbit_labels_dataarray[self.label_name])
1✔
628
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
629

630
    def test_orbit_exceed_labels(
1✔
631
        self,
632
        orbit_labels_dataarray: xr.DataArray,
633
    ) -> None:
634
        """Test plotting orbit data with too many labels for colorbar"""
635

636
        p = plot.plot_labels(orbit_labels_dataarray, label_name=self.label_name, max_n_labels=5)
1✔
637
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
638

639
    def test_grid(
1✔
640
        self,
641
        grid_labels_dataarray: xr.DataArray,
642
    ) -> None:
643
        """Test plotting grid data"""
644

645
        p = plot.plot_labels(grid_labels_dataarray, label_name=self.label_name)
1✔
646
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
647

648
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
649
    def test_generator(
1✔
650
        self,
651
        orbit_labels_dataarray: xr.DataArray,
652
    ) -> None:
653
        """Test plotting orbit data form a generator"""
654

655
        da_list = [
1✔
656
            (0, orbit_labels_dataarray),
657
            (1, orbit_labels_dataarray),
658
        ]
659
        generator = (t for t in da_list)
1✔
660

661
        p = plot.plot_labels(generator, label_name=self.label_name)  # only last plot is returned
1✔
662
        save_and_check_figure(figure=p.figure, name=get_test_name())
1✔
663

664

665
class TestPlotPatches:
1✔
666
    """Test the plot_patches function"""
1✔
667

668
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
669
    def test_orbit(
1✔
670
        self,
671
        orbit_dataarray: xr.DataArray,
672
    ) -> None:
673
        """Test plotting orbit data"""
674

675
        da_list = [
1✔
676
            (0, orbit_dataarray),
677
            (1, orbit_dataarray),
678
        ]
679
        generator = (t for t in da_list)
1✔
680
        plot.plot_patches(generator)  # does not return plotter
1✔
681
        save_and_check_figure(name=get_test_name())
1✔
682

683
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
684
    def test_orbit_dataset(
1✔
685
        self,
686
        orbit_dataarray: xr.DataArray,
687
    ) -> None:
688
        """Test plotting orbit data from a dataset"""
689

690
        variable_name = "variable"
1✔
691
        ds = xr.Dataset({variable_name: orbit_dataarray})
1✔
692
        ds_list = [
1✔
693
            (0, ds),
694
            (1, ds),
695
        ]
696
        generator = (t for t in ds_list)
1✔
697

698
        # Test with missing variable
699
        with pytest.raises(ValueError):
1✔
700
            plot.plot_patches(generator)
1✔
701

702
        plot.plot_patches(generator, variable=variable_name)  # does not return plotter
1✔
703
        save_and_check_figure(name=get_test_name())
1✔
704

705
    @pytest.mark.usefixtures("_prevent_pyplot_show")
1✔
706
    def test_grid(
1✔
707
        self,
708
        grid_dataarray: xr.DataArray,
709
    ) -> None:
710
        """Test plotting grid data"""
711

712
        da_list = [
1✔
713
            (0, grid_dataarray),
714
            (1, grid_dataarray),
715
        ]
716
        generator = (t for t in da_list)
1✔
717
        plot.plot_patches(generator)  # does not return plotter
1✔
718
        save_and_check_figure(name=get_test_name())
1✔
719

720
    def test_invalid(
1✔
721
        self,
722
    ) -> None:
723
        """Test invalid data"""
724

725
        invalid_list = [
1✔
726
            (0, xr.DataArray()),
727
            (1, xr.DataArray()),
728
        ]
729
        generator = (t for t in invalid_list)
1✔
730
        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

© 2026 Coveralls, Inc