|
14 | 14 | requires_mpl_ge_310 = pytest.mark.skipif(not MPL_GE_310, reason="requires mpl >= 3.10") |
15 | 15 |
|
16 | 16 |
|
17 | | -HATCH_FUNCTIONS = ( |
18 | | - pytest.param(mpu.hatch, id="hatch"), |
19 | | - pytest.param(mpu.hatch_map, id="hatch_map"), |
20 | | - pytest.param(mpu.hatch_map_global, id="hatch_map_global"), |
21 | | -) |
22 | | - |
23 | | - |
24 | 17 | def get_hatchcolor(h): |
25 | 18 | if MPL_GE_311: |
26 | 19 | return mpl.colors.to_rgba(h.get_hatchcolor()) |
27 | 20 |
|
28 | 21 | return h._hatch_color |
29 | 22 |
|
30 | 23 |
|
31 | | -@pytest.mark.parametrize("obj", (None, xr.Dataset(), np.array([]))) |
32 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
33 | | -def test_hatch_not_a_dataarray(obj, function): |
| 24 | +class HatchBase: |
34 | 25 |
|
35 | | - with pytest.raises(TypeError, match="Expected a xr.DataArray"): |
36 | | - function(obj, "*") |
| 26 | + @pytest.mark.parametrize("obj", (None, xr.Dataset(), np.array([]))) |
| 27 | + def test_hatch_not_a_dataarray(self, obj): |
37 | 28 |
|
| 29 | + with pytest.raises(TypeError, match="Expected a xr.DataArray"): |
| 30 | + self.function(obj, "*") |
38 | 31 |
|
39 | | -@pytest.mark.parametrize("dtype", (float, int)) |
40 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
41 | | -def test_hatch_not_bool(dtype, function): |
| 32 | + @pytest.mark.parametrize("dtype", (float, int)) |
| 33 | + def test_hatch_not_bool(self, dtype): |
42 | 34 |
|
43 | | - da = xr.DataArray(np.ones((3, 3), dtype=dtype)) |
| 35 | + da = xr.DataArray(np.ones((3, 3), dtype=dtype)) |
44 | 36 |
|
45 | | - with pytest.raises(TypeError, match="Expected a boolean array"): |
46 | | - function(da, "*") |
| 37 | + with pytest.raises(TypeError, match="Expected a boolean array"): |
| 38 | + self.function(da, "*") |
47 | 39 |
|
| 40 | + @pytest.mark.parametrize("ndim", (1, 3)) |
| 41 | + def test_hatch_not_2D(self, ndim): |
48 | 42 |
|
49 | | -@pytest.mark.parametrize("ndim", (1, 3)) |
50 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
51 | | -def test_hatch_not_2D(ndim, function): |
| 43 | + da = xr.DataArray(np.ones([3] * ndim, dtype=bool)) |
52 | 44 |
|
53 | | - da = xr.DataArray(np.ones([3] * ndim, dtype=bool)) |
| 45 | + with pytest.raises(ValueError, match="Expected a 2D array"): |
| 46 | + self.function(da, "*") |
54 | 47 |
|
55 | | - with pytest.raises(ValueError, match="Expected a 2D array"): |
56 | | - function(da, "*") |
| 48 | + def test_hatch_pattern(self): |
57 | 49 |
|
| 50 | + da = xr.DataArray( |
| 51 | + np.ones([3, 3], dtype=bool), |
| 52 | + dims=("lat", "lon"), |
| 53 | + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
| 54 | + ) |
58 | 55 |
|
59 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
60 | | -def test_hatch_pattern(function): |
| 56 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
61 | 57 |
|
62 | | - da = xr.DataArray( |
63 | | - np.ones([3, 3], dtype=bool), |
64 | | - dims=("lat", "lon"), |
65 | | - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
66 | | - ) |
| 58 | + h = self.function(da, "*", ax=ax) |
| 59 | + assert h.hatches == ["", "*"] |
| 60 | + h = self.function(da, "//", ax=ax) |
| 61 | + assert h.hatches == ["", "//"] |
67 | 62 |
|
68 | | - subplot_kw = {"projection": ccrs.PlateCarree()} |
| 63 | + def test_hatch_label(self): |
69 | 64 |
|
70 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 65 | + da = xr.DataArray( |
| 66 | + np.ones([3, 3], dtype=bool), |
| 67 | + dims=("lat", "lon"), |
| 68 | + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
| 69 | + ) |
71 | 70 |
|
72 | | - h = function(da, "*", ax=ax) |
73 | | - assert h.hatches == ["", "*"] |
74 | | - h = function(da, "//", ax=ax) |
75 | | - assert h.hatches == ["", "//"] |
| 71 | + # test label with default color |
| 72 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
76 | 73 |
|
| 74 | + self.function(da, "*", ax=ax, label="label") |
77 | 75 |
|
78 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
79 | | -def test_hatch_label(function): |
| 76 | + legend = ax.legend() |
| 77 | + h = legend.legend_handles |
80 | 78 |
|
81 | | - da = xr.DataArray( |
82 | | - np.ones([3, 3], dtype=bool), |
83 | | - dims=("lat", "lon"), |
84 | | - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
85 | | - ) |
| 79 | + assert len(h) == 1 |
86 | 80 |
|
87 | | - subplot_kw = {"projection": ccrs.PlateCarree()} |
| 81 | + (rect,) = h |
88 | 82 |
|
89 | | - # test label with default color |
90 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 83 | + assert rect.get_label() == "label" |
| 84 | + assert mpl.colors.to_rgba("0.1") == get_hatchcolor(rect) |
91 | 85 |
|
92 | | - function(da, "*", ax=ax, label="label") |
| 86 | + # test 2 labels with non-default color |
| 87 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
93 | 88 |
|
94 | | - legend = ax.legend() |
95 | | - h = legend.legend_handles |
| 89 | + self.function(da, "*", ax=ax, label="label0", color="#2ca25f") |
| 90 | + self.function(da, "*", ax=ax, label="label1", color="#2ca25f") |
96 | 91 |
|
97 | | - assert len(h) == 1 |
| 92 | + legend = ax.legend() |
| 93 | + h = legend.legend_handles |
98 | 94 |
|
99 | | - (rect,) = h |
| 95 | + assert len(h) == 2 |
100 | 96 |
|
101 | | - assert rect.get_label() == "label" |
102 | | - assert mpl.colors.to_rgba("0.1") == get_hatchcolor(rect) |
| 97 | + for i, rect in enumerate(h): |
| 98 | + assert rect.get_label() == f"label{i}" |
| 99 | + assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(rect) |
103 | 100 |
|
104 | | - # test 2 labels with non-default color |
105 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 101 | + @pytest.mark.skipif(MPL_GE_310, reason="only for mpl < 3.10") |
| 102 | + def test_hatch_linewidth_mpl_lt_310(self): |
106 | 103 |
|
107 | | - function(da, "*", ax=ax, label="label0", color="#2ca25f") |
108 | | - function(da, "*", ax=ax, label="label1", color="#2ca25f") |
| 104 | + da = xr.DataArray( |
| 105 | + np.ones([3, 3], dtype=bool), |
| 106 | + dims=("lat", "lon"), |
| 107 | + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
| 108 | + ) |
109 | 109 |
|
110 | | - legend = ax.legend() |
111 | | - h = legend.legend_handles |
| 110 | + # test linewidth default width |
| 111 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
| 112 | + self.function(da, "*", ax=ax) |
112 | 113 |
|
113 | | - assert len(h) == 2 |
| 114 | + assert mpl.rcParams["hatch.linewidth"] == 0.25 |
114 | 115 |
|
115 | | - for i, rect in enumerate(h): |
116 | | - assert rect.get_label() == f"label{i}" |
117 | | - assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(rect) |
| 116 | + # changing away from the default linewidth does not raise a warning |
| 117 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
118 | 118 |
|
| 119 | + self.function(da, "*", ax=ax) |
| 120 | + assert mpl.rcParams["hatch.linewidth"] == 0.25 |
119 | 121 |
|
120 | | -@pytest.mark.skipif(MPL_GE_310, reason="only for mpl < 3.10") |
121 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
122 | | -def test_hatch_linewidth_mpl_lt_310(function): |
| 122 | + with assert_no_warnings(): |
| 123 | + self.function(da, "*", ax=ax, linewidth=1) |
123 | 124 |
|
124 | | - da = xr.DataArray( |
125 | | - np.ones([3, 3], dtype=bool), |
126 | | - dims=("lat", "lon"), |
127 | | - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
128 | | - ) |
| 125 | + assert mpl.rcParams["hatch.linewidth"] == 1 |
129 | 126 |
|
130 | | - subplot_kw = {"projection": ccrs.PlateCarree()} |
| 127 | + # changing away from the linewidth does raise a warning |
| 128 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
131 | 129 |
|
132 | | - # test linewidth default width |
133 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
134 | | - function(da, "*", ax=ax) |
| 130 | + self.function(da, "*", ax=ax, linewidth=2) |
| 131 | + assert mpl.rcParams["hatch.linewidth"] == 2 |
135 | 132 |
|
136 | | - assert mpl.rcParams["hatch.linewidth"] == 0.25 |
| 133 | + with pytest.warns(match="Setting more than one hatch `linewidth`"): |
| 134 | + self.function(da, "*", ax=ax, linewidth=1) |
137 | 135 |
|
138 | | - # changing away from the default linewidth does not raise a warning |
139 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 136 | + assert mpl.rcParams["hatch.linewidth"] == 1 |
140 | 137 |
|
141 | | - function(da, "*", ax=ax) |
142 | | - assert mpl.rcParams["hatch.linewidth"] == 0.25 |
| 138 | + @requires_mpl_ge_310 |
| 139 | + @pytest.mark.filterwarnings("ignore:Passing 'N' to ListedColormap is deprecated") |
| 140 | + def test_hatch_linewidth_mpl_ge_310(self): |
143 | 141 |
|
144 | | - with assert_no_warnings(): |
145 | | - function(da, "*", ax=ax, linewidth=1) |
| 142 | + da = xr.DataArray( |
| 143 | + np.ones([3, 3], dtype=bool), |
| 144 | + dims=("lat", "lon"), |
| 145 | + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
| 146 | + ) |
146 | 147 |
|
147 | | - assert mpl.rcParams["hatch.linewidth"] == 1 |
| 148 | + # test linewidth default width |
| 149 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
| 150 | + q = self.function(da, "*", ax=ax) |
| 151 | + assert q.get_hatch_linewidth() == 0.25 |
| 152 | + assert mpl.rcParams["hatch.linewidth"] == 0.25 |
148 | 153 |
|
149 | | - # changing away from the linewidth does raise a warning |
150 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 154 | + # changing away from the default linewidth does not raise a warning |
| 155 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
151 | 156 |
|
152 | | - function(da, "*", ax=ax, linewidth=2) |
153 | | - assert mpl.rcParams["hatch.linewidth"] == 2 |
| 157 | + q = self.function(da, "*", ax=ax) |
| 158 | + assert q.get_hatch_linewidth() == 0.25 |
| 159 | + assert mpl.rcParams["hatch.linewidth"] == 0.25 |
154 | 160 |
|
155 | | - with pytest.warns(match="Setting more than one hatch `linewidth`"): |
156 | | - function(da, "*", ax=ax, linewidth=1) |
| 161 | + with assert_no_warnings(): |
| 162 | + q = self.function(da, "*", ax=ax, linewidth=1) |
157 | 163 |
|
158 | | - assert mpl.rcParams["hatch.linewidth"] == 1 |
| 164 | + assert q.get_hatch_linewidth() == 1 |
| 165 | + assert mpl.rcParams["hatch.linewidth"] == 1 |
159 | 166 |
|
| 167 | + q = self.function(da, "*", ax=ax) |
| 168 | + assert q.get_hatch_linewidth() == 0.25 |
| 169 | + assert mpl.rcParams["hatch.linewidth"] == 0.25 |
160 | 170 |
|
161 | | -@requires_mpl_ge_310 |
162 | | -@pytest.mark.filterwarnings("ignore:Passing 'N' to ListedColormap is deprecated") |
163 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
164 | | -def test_hatch_linewidth_mpl_ge_310(function): |
| 171 | + # changing away from the linewidth does NOT raise a warning |
| 172 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
165 | 173 |
|
166 | | - da = xr.DataArray( |
167 | | - np.ones([3, 3], dtype=bool), |
168 | | - dims=("lat", "lon"), |
169 | | - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
170 | | - ) |
| 174 | + q = self.function(da, "*", ax=ax, linewidth=2) |
| 175 | + assert q.get_hatch_linewidth() == 2 |
| 176 | + assert mpl.rcParams["hatch.linewidth"] == 2 |
171 | 177 |
|
172 | | - subplot_kw = {"projection": ccrs.PlateCarree()} |
| 178 | + with assert_no_warnings(): |
| 179 | + q = self.function(da, "*", ax=ax, linewidth=1) |
173 | 180 |
|
174 | | - # test linewidth default width |
175 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
176 | | - q = function(da, "*", ax=ax) |
177 | | - assert q.get_hatch_linewidth() == 0.25 |
178 | | - assert mpl.rcParams["hatch.linewidth"] == 0.25 |
| 181 | + assert q.get_hatch_linewidth() == 1 |
| 182 | + assert mpl.rcParams["hatch.linewidth"] == 1 |
179 | 183 |
|
180 | | - # changing away from the default linewidth does not raise a warning |
181 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 184 | + def test_hatch_color(self): |
182 | 185 |
|
183 | | - q = function(da, "*", ax=ax) |
184 | | - assert q.get_hatch_linewidth() == 0.25 |
185 | | - assert mpl.rcParams["hatch.linewidth"] == 0.25 |
| 186 | + da = xr.DataArray( |
| 187 | + np.ones([3, 3], dtype=bool), |
| 188 | + dims=("lat", "lon"), |
| 189 | + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
| 190 | + ) |
186 | 191 |
|
187 | | - with assert_no_warnings(): |
188 | | - q = function(da, "*", ax=ax, linewidth=1) |
| 192 | + # test default color |
| 193 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
| 194 | + h = self.function(da, "*", ax=ax) |
189 | 195 |
|
190 | | - assert q.get_hatch_linewidth() == 1 |
191 | | - assert mpl.rcParams["hatch.linewidth"] == 1 |
| 196 | + assert mpl.colors.to_rgba("0.1") == get_hatchcolor(h) |
192 | 197 |
|
193 | | - q = function(da, "*", ax=ax) |
194 | | - assert q.get_hatch_linewidth() == 0.25 |
195 | | - assert mpl.rcParams["hatch.linewidth"] == 0.25 |
| 198 | + # different colors can be set |
| 199 | + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): |
196 | 200 |
|
197 | | - # changing away from the linewidth does NOT raise a warning |
198 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 201 | + h = self.function(da, "*", ax=ax, color="#2ca25f") |
| 202 | + assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(h) |
199 | 203 |
|
200 | | - q = function(da, "*", ax=ax, linewidth=2) |
201 | | - assert q.get_hatch_linewidth() == 2 |
202 | | - assert mpl.rcParams["hatch.linewidth"] == 2 |
| 204 | + h = self.function(da, "*", ax=ax, color="#e5f5f9") |
| 205 | + assert mpl.colors.to_rgba("#e5f5f9") == get_hatchcolor(h) |
203 | 206 |
|
204 | | - with assert_no_warnings(): |
205 | | - q = function(da, "*", ax=ax, linewidth=1) |
206 | 207 |
|
207 | | - assert q.get_hatch_linewidth() == 1 |
208 | | - assert mpl.rcParams["hatch.linewidth"] == 1 |
| 208 | +class TestHatch(HatchBase): |
209 | 209 |
|
| 210 | + function = staticmethod(mpu.hatch) |
| 211 | + subplot_kw = {} |
210 | 212 |
|
211 | | -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) |
212 | | -def test_hatch_color(function): |
213 | 213 |
|
214 | | - da = xr.DataArray( |
215 | | - np.ones([3, 3], dtype=bool), |
216 | | - dims=("lat", "lon"), |
217 | | - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, |
218 | | - ) |
| 214 | +class TestHatchMap(HatchBase): |
219 | 215 |
|
| 216 | + function = staticmethod(mpu.hatch_map_global) |
220 | 217 | subplot_kw = {"projection": ccrs.PlateCarree()} |
221 | 218 |
|
222 | | - # test default color |
223 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
224 | | - h = function(da, "*", ax=ax) |
225 | | - |
226 | | - assert mpl.colors.to_rgba("0.1") == get_hatchcolor(h) |
227 | 219 |
|
228 | | - # different colors can be set |
229 | | - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): |
| 220 | +class TestHatchMapGlobal(HatchBase): |
230 | 221 |
|
231 | | - h = function(da, "*", ax=ax, color="#2ca25f") |
232 | | - assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(h) |
233 | | - |
234 | | - h = function(da, "*", ax=ax, color="#e5f5f9") |
235 | | - assert mpl.colors.to_rgba("#e5f5f9") == get_hatchcolor(h) |
| 222 | + function = staticmethod(mpu.hatch_map_global) |
| 223 | + subplot_kw = {"projection": ccrs.PlateCarree()} |
236 | 224 |
|
237 | 225 |
|
238 | 226 | def test_hatch_bbox(): |
|
0 commit comments