Skip to content

Commit b5178a9

Browse files
Prioritise dim coord in _get_lon_lat_coords() (#5029)
* Added in dim_coord prioritisation within _get_lon_lat_coords * Completed testing for dim coord prioritisation, added what's new entry * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated tests to include fixtures * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Mostly formatting changes for readability, largely suggested by Payton for better PyTest consistency. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Replaced with throughout * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * updated docstring in project Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent d56824c commit b5178a9

File tree

3 files changed

+139
-8
lines changed

3 files changed

+139
-8
lines changed

docs/src/whatsnew/latest.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ This document explains the changes made to Iris for this release
4747
:class:`~iris.coords.AuxCoord`, which avoids some specific known usage problems.
4848
(:issue:`4860`, :pull:`5020`)
4949

50+
#. `@Esadek-MO`_ and `@trexfeathers`_ added dim coord
51+
prioritisation to ``_get_lon_lat_coords()`` in :mod:`iris.analysis.cartography`.
52+
This allows :func:`iris.analysis.cartography.area_weights` and
53+
:func:`~iris.analysis.cartography.project` to handle cubes which contain
54+
both dim and aux coords of the same type e.g. ``longitude`` and ``grid_longitude``.
55+
(:issue:`3916`, :pull:`5029`).
56+
5057

5158
🐛 Bugs Fixed
5259
=============

lib/iris/analysis/cartography.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,20 +169,25 @@ def rotate_pole(lons, lats, pole_lon, pole_lat):
169169

170170

171171
def _get_lon_lat_coords(cube):
172-
lat_coords = [
173-
coord for coord in cube.coords() if "latitude" in coord.name()
174-
]
175-
lon_coords = [
176-
coord for coord in cube.coords() if "longitude" in coord.name()
177-
]
172+
def search_for_coord(coord_iterable, coord_name):
173+
return [
174+
coord for coord in coord_iterable if coord_name in coord.name()
175+
]
176+
177+
lat_coords = search_for_coord(
178+
cube.dim_coords, "latitude"
179+
) or search_for_coord(cube.coords(), "latitude")
180+
lon_coords = search_for_coord(
181+
cube.dim_coords, "longitude"
182+
) or search_for_coord(cube.coords(), "longitude")
178183
if len(lat_coords) > 1 or len(lon_coords) > 1:
179184
raise ValueError(
180-
"Calling `_get_lon_lat_coords` with multiple lat or lon coords"
185+
"Calling `_get_lon_lat_coords` with multiple same-type (i.e. dim/aux) lat or lon coords"
181186
" is currently disallowed"
182187
)
183188
lat_coord = lat_coords[0]
184189
lon_coord = lon_coords[0]
185-
return (lon_coord, lat_coord)
190+
return lon_coord, lat_coord
186191

187192

188193
def _xy_range(cube, mode=None):
@@ -578,6 +583,11 @@ def project(cube, target_proj, nx=None, ny=None):
578583
An instance of :class:`iris.cube.Cube` and a list describing the
579584
extent of the projection.
580585
586+
.. note::
587+
588+
If there are both dim and aux latitude-longitude coordinates, only
589+
the dim coordinates will be used.
590+
581591
.. note::
582592
583593
This function assumes global data and will if necessary extrapolate
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright Iris contributors
2+
#
3+
# This file is part of Iris and is released under the LGPL license.
4+
# See COPYING and COPYING.LESSER in the root of the repository for full
5+
# licensing details.
6+
"""Test function :func:`iris.analysis.cartography._get_lon_lat_coords"""
7+
8+
import pytest
9+
10+
from iris.analysis.cartography import _get_lon_lat_coords as g_lon_lat
11+
from iris.coords import AuxCoord
12+
from iris.tests.stock import lat_lon_cube
13+
14+
15+
@pytest.fixture
16+
def dim_only_cube():
17+
return lat_lon_cube()
18+
19+
20+
def test_dim_only(dim_only_cube):
21+
t_lat, t_lon = dim_only_cube.dim_coords
22+
23+
lon, lat = g_lon_lat(dim_only_cube)
24+
25+
assert lon == t_lon
26+
assert lat == t_lat
27+
28+
29+
@pytest.fixture
30+
def dim_aux_cube(dim_only_cube):
31+
lat_dim, lon_dim = dim_only_cube.dim_coords
32+
33+
lat_aux = AuxCoord.from_coord(lat_dim)
34+
lat_aux.standard_name = "grid_latitude"
35+
lon_aux = AuxCoord.from_coord(lon_dim)
36+
lon_aux.standard_name = "grid_longitude"
37+
38+
dim_aux_cube = dim_only_cube
39+
dim_aux_cube.add_aux_coord(lat_aux, 0)
40+
dim_aux_cube.add_aux_coord(lon_aux, 1)
41+
42+
return dim_aux_cube
43+
44+
45+
def test_dim_aux(dim_aux_cube):
46+
t_lat_dim, t_lon_dim = dim_aux_cube.dim_coords
47+
48+
lon, lat = g_lon_lat(dim_aux_cube)
49+
50+
assert lon == t_lon_dim
51+
assert lat == t_lat_dim
52+
53+
54+
@pytest.fixture
55+
def aux_only_cube(dim_aux_cube):
56+
lon_dim, lat_dim = dim_aux_cube.dim_coords
57+
58+
aux_only_cube = dim_aux_cube
59+
aux_only_cube.remove_coord(lon_dim)
60+
aux_only_cube.remove_coord(lat_dim)
61+
62+
return dim_aux_cube
63+
64+
65+
def test_aux_only(aux_only_cube):
66+
aux_lat, aux_lon = aux_only_cube.aux_coords
67+
68+
lon, lat = g_lon_lat(aux_only_cube)
69+
70+
assert lon == aux_lon
71+
assert lat == aux_lat
72+
73+
74+
@pytest.fixture
75+
def double_dim_cube(dim_only_cube):
76+
double_dim_cube = dim_only_cube
77+
double_dim_cube.coord("latitude").standard_name = "grid_longitude"
78+
79+
return double_dim_cube
80+
81+
82+
def test_double_dim(double_dim_cube):
83+
t_error_message = "with multiple.*is currently disallowed"
84+
85+
with pytest.raises(ValueError, match=t_error_message):
86+
g_lon_lat(double_dim_cube)
87+
88+
89+
@pytest.fixture
90+
def double_aux_cube(aux_only_cube):
91+
double_aux_cube = aux_only_cube
92+
double_aux_cube.coord("grid_latitude").standard_name = "longitude"
93+
94+
return double_aux_cube
95+
96+
97+
def test_double_aux(double_aux_cube):
98+
t_error_message = "with multiple.*is currently disallowed"
99+
100+
with pytest.raises(ValueError, match=t_error_message):
101+
g_lon_lat(double_aux_cube)
102+
103+
104+
@pytest.fixture
105+
def missing_lat_cube(dim_only_cube):
106+
missing_lat_cube = dim_only_cube
107+
missing_lat_cube.remove_coord("latitude")
108+
109+
return missing_lat_cube
110+
111+
112+
def test_missing_coord(missing_lat_cube):
113+
with pytest.raises(IndexError):
114+
g_lon_lat(missing_lat_cube)

0 commit comments

Comments
 (0)