Skip to content

Commit 619c62c

Browse files
jonseddonpre-commit-ci[bot]trexfeathers
authored
Add barbs plot (#3710)
* Add plot and gallery example * Add a what's new * Added test and reduced size of gallery example * Painted it black * Added test to imagerepo.json but name of file in repo will be wrong * Correct hash inserted * Correctly resolved merge conflict * Hopefully fully compliant with new style gallery now * Consistency with new style documentation * Improved language as Lake Victoria is not relevant and shorelines are not included in this simulated data. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Clarify units * Correct function name. * Test vector plots * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * isort:skip Co-authored-by: Martin Yeo <[email protected]> * Docstring note now visible in Sphinx output Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Martin Yeo <[email protected]>
1 parent d4d0514 commit 619c62c

6 files changed

Lines changed: 197 additions & 6 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""
2+
Plotting Wind Direction Using Barbs
3+
===================================
4+
5+
This example demonstrates using barbs to plot wind speed contours and wind
6+
direction barbs from wind vector component input data. The vector components
7+
are co-located in space in this case.
8+
9+
The magnitude of the wind in the original data is low and so doesn't illustrate
10+
the full range of barbs. The wind is scaled to simulate a storm that better
11+
illustrates the range of barbs that are available.
12+
"""
13+
14+
import matplotlib.pyplot as plt
15+
16+
import iris
17+
import iris.plot as iplt
18+
import iris.quickplot as qplt
19+
20+
21+
def main():
22+
# Load the u and v components of wind from a pp file
23+
infile = iris.sample_data_path("wind_speed_lake_victoria.pp")
24+
25+
uwind = iris.load_cube(infile, "x_wind")
26+
vwind = iris.load_cube(infile, "y_wind")
27+
28+
uwind.convert_units("knot")
29+
vwind.convert_units("knot")
30+
31+
# To illustrate the full range of barbs, scale the wind speed up to pretend
32+
# that a storm is passing over
33+
magnitude = (uwind ** 2 + vwind ** 2) ** 0.5
34+
magnitude.convert_units("knot")
35+
max_speed = magnitude.collapsed(
36+
("latitude", "longitude"), iris.analysis.MAX
37+
).data
38+
max_desired = 65
39+
40+
uwind = uwind / max_speed * max_desired
41+
vwind = vwind / max_speed * max_desired
42+
43+
# Create a cube containing the wind speed
44+
windspeed = (uwind ** 2 + vwind ** 2) ** 0.5
45+
windspeed.rename("windspeed")
46+
windspeed.convert_units("knot")
47+
48+
plt.figure()
49+
50+
# Plot the wind speed as a contour plot
51+
qplt.contourf(windspeed)
52+
53+
# Add wind barbs except for the outermost values which overhang the edge
54+
# of the plot if left
55+
iplt.barbs(uwind[1:-1, 1:-1], vwind[1:-1, 1:-1], pivot="middle", length=6)
56+
57+
plt.title("Wind speed during a simulated storm")
58+
qplt.show()
59+
60+
61+
if __name__ == "__main__":
62+
main()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
7+
# Import Iris tests first so that some things can be initialised before
8+
# importing anything else.
9+
import iris.tests as tests # isort:skip
10+
11+
from .gallerytest_util import (
12+
add_gallery_to_path,
13+
fail_any_deprecation_warnings,
14+
show_replaced_by_check_graphic,
15+
)
16+
17+
18+
class TestWindBarbs(tests.GraphicsTest):
19+
"""Test the wind_barbs example code."""
20+
21+
def test_wind_barbs(self):
22+
with fail_any_deprecation_warnings():
23+
with add_gallery_to_path():
24+
import plot_wind_barbs
25+
with show_replaced_by_check_graphic(self):
26+
plot_wind_barbs.main()
27+
28+
29+
if __name__ == "__main__":
30+
tests.main()

docs/src/whatsnew/latest.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ This document explains the changes made to Iris for this release
4242
the primary coordinate being plotted against is a vertical coordinate. E.g.
4343
``iris.plot.plot(z_cube)`` will produce a z-vs-phenomenon plot, where before
4444
it would have produced a phenomenon-vs-z plot. (:pull:`3906`)
45+
#. `@jonseddon`_ added :meth:`iris.plot.barbs` to provide a convenient way to
46+
use :func:`matplotlib.pyplot.barbs` with Iris cubes. A gallery example was
47+
included to illustrate the new method's use. (:pull:`3710`)
4548

4649
#. `@bjlittle`_ introduced :func:`iris.common.metadata.hexdigest` to the
4750
public API. Previously it was a private function introduced in ``v3.0.0``.

lib/iris/plot.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,55 @@ def _vector_component_args(x_points, y_points, u_data, *args, **kwargs):
14191419
return ((x_points, y_points, u_data, v_data), kwargs)
14201420

14211421

1422+
def barbs(u_cube, v_cube, *args, **kwargs):
1423+
"""
1424+
Draws a barb plot from two vector component cubes. Triangles, full-lines
1425+
and half-lines represent increments of 50, 10 and 5 respectively.
1426+
1427+
Args:
1428+
1429+
* u_cube, v_cube : (:class:`~iris.cube.Cube`)
1430+
u and v vector components. Must have same shape and units.
1431+
If the cubes have geographic coordinates, the values are treated as
1432+
true distance differentials, e.g. windspeeds, and *not* map coordinate
1433+
vectors. The components are aligned with the North and East of the
1434+
cube coordinate system.
1435+
1436+
.. Note::
1437+
1438+
At present, if u_cube and v_cube have geographic coordinates, then they
1439+
must be in a lat-lon coordinate system, though it may be a rotated one.
1440+
To transform wind values between coordinate systems, use
1441+
:func:`iris.analysis.cartography.rotate_grid_vectors`.
1442+
To transform coordinate grid points, you will need to create
1443+
2-dimensional arrays of x and y values. These can be transformed with
1444+
:meth:`cartopy.crs.CRS.transform_points`.
1445+
1446+
Kwargs:
1447+
1448+
* coords: (list of :class:`~iris.coords.Coord` or string)
1449+
Coordinates or coordinate names. Use the given coordinates as the axes
1450+
for the plot. The order of the given coordinates indicates which axis
1451+
to use for each, where the first element is the horizontal
1452+
axis of the plot and the second element is the vertical axis
1453+
of the plot.
1454+
1455+
* axes: the :class:`matplotlib.axes.Axes` to use for drawing.
1456+
Defaults to the current axes if none provided.
1457+
1458+
See :func:`matplotlib.pyplot.barbs` for details of other valid
1459+
keyword arguments.
1460+
1461+
"""
1462+
#
1463+
# TODO: check u + v cubes for compatibility.
1464+
#
1465+
kwargs["_v_data"] = v_cube.data
1466+
return _draw_2d_from_points(
1467+
"barbs", _vector_component_args, u_cube, *args, **kwargs
1468+
)
1469+
1470+
14221471
def quiver(u_cube, v_cube, *args, **kwargs):
14231472
"""
14241473
Draws an arrow plot from two vector component cubes.
@@ -1432,12 +1481,12 @@ def quiver(u_cube, v_cube, *args, **kwargs):
14321481
vectors. The components are aligned with the North and East of the
14331482
cube coordinate system.
14341483
1435-
.. Note:
1484+
.. Note::
14361485
14371486
At present, if u_cube and v_cube have geographic coordinates, then they
14381487
must be in a lat-lon coordinate system, though it may be a rotated one.
14391488
To transform wind values between coordinate systems, use
1440-
:func:`iris.analysis.cartography.rotate_vectors`.
1489+
:func:`iris.analysis.cartography.rotate_grid_vectors`.
14411490
To transform coordinate grid points, you will need to create
14421491
2-dimensional arrays of x and y values. These can be transformed with
14431492
:meth:`cartopy.crs.CRS.transform_points`.

lib/iris/tests/integration/plot/test_vector_plots.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@
2424
if tests.MPL_AVAILABLE:
2525
import matplotlib.pyplot as plt
2626

27-
from iris.plot import quiver
27+
from iris.plot import barbs, quiver
2828

2929

3030
@tests.skip_plot
3131
class MixinVectorPlotCases:
3232
"""
33-
Test examples mixin, used by separate quiver + streamplot classes.
33+
Test examples mixin, used by separate barb, quiver + streamplot classes.
3434
35-
NOTE: at present for quiver only, as streamplot does not support arbitrary
36-
coordinates.
35+
NOTE: at present for barb and quiver only, as streamplot does not support
36+
arbitrary coordinates.
3737
3838
"""
3939

@@ -193,6 +193,34 @@ def test_circular_longitude(self):
193193
self.plot("circular", u_cube, v_cube, coords=("longitude", "latitude"))
194194

195195

196+
class TestBarbs(MixinVectorPlotCases, tests.GraphicsTest):
197+
def setUp(self):
198+
super().setUp()
199+
200+
@staticmethod
201+
def _nonlatlon_xyuv():
202+
# Increase the range of wind speeds used in the barbs test to test more
203+
# barbs shapes than just circles
204+
x, y, u, v = MixinVectorPlotCases._nonlatlon_xyuv()
205+
scale_factor = 50
206+
u *= scale_factor
207+
v *= scale_factor
208+
return x, y, u, v
209+
210+
@staticmethod
211+
def _latlon_uv_cubes(grid_cube):
212+
# Increase the range of wind speeds used in the barbs test to test all
213+
# barbs shapes
214+
u_cube, v_cube = MixinVectorPlotCases._latlon_uv_cubes(grid_cube)
215+
scale_factor = 30
216+
u_cube.data *= scale_factor
217+
v_cube.data *= scale_factor
218+
return u_cube, v_cube
219+
220+
def plot_function_to_test(self):
221+
return barbs
222+
223+
196224
class TestQuiver(MixinVectorPlotCases, tests.GraphicsTest):
197225
def setUp(self):
198226
super().setUp()

lib/iris/tests/results/imagerepo.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@
143143
"https://scitools.github.io/test-iris-imagehash/images/v4/fa8172d0847ecd2bc913939c36846c714933799cc3cc8727e67639f939996a58.png",
144144
"https://scitools.github.io/test-iris-imagehash/images/v4/fa8172c6857ecd38cb3392ce36c564311931d85ec64e9787719a39993c316e66.png"
145145
],
146+
"gallery_tests.test_plot_wind_barbs.TestWindBarbs.test_wind_barbs.0": [
147+
"https://scitools.github.io/test-iris-imagehash/images/v4/e9e960e996169316c1fe9e96c29e36739e13c07c3d61c07f39a13921c07f3e21.png",
148+
"https://scitools.github.io/test-iris-imagehash/images/v4/e9e161e996169316c1fe9e96c29e36739e13c07c3d61c07f39813929c07f3f01.png"
149+
],
146150
"gallery_tests.test_plot_wind_speed.TestWindSpeed.test_plot_wind_speed.0": [
147151
"https://scitools.github.io/test-iris-imagehash/images/v4/bcf924fb9306930ce12ccf97c73236b28ecec4cd3e29847b18e639e6c14f1a09.png",
148152
"https://scitools.github.io/test-iris-imagehash/images/v4/e9e960e996169306c1fe9e96c29e36739e13c06c3d61c07f39a139e1c07f3f01.png"
@@ -173,6 +177,21 @@
173177
"iris.tests.integration.plot.test_plot_2d_coords.Test2dContour.test_2d_coords_contour.0": [
174178
"https://scitools.github.io/test-iris-imagehash/images/v4/b4b2643ecb05cb43b0f23d80c53c4e1d3e5990eb1f81c19f2f983cb1c4ff3e42.png"
175179
],
180+
"iris.tests.integration.plot.test_vector_plots.TestBarbs.test_2d_plain_latlon.0": [
181+
"https://scitools.github.io/test-iris-imagehash/images/v4/eb036726c47c9273918e6e2c6f216336787590eb969a165890ee6c676925b3b3.png"
182+
],
183+
"iris.tests.integration.plot.test_vector_plots.TestBarbs.test_2d_plain_latlon_on_polar_map.0": [
184+
"https://scitools.github.io/test-iris-imagehash/images/v4/e66d673c999031cd6667663398dc332c676364e798959336636660d933998666.png"
185+
],
186+
"iris.tests.integration.plot.test_vector_plots.TestBarbs.test_2d_rotated_latlon.0": [
187+
"https://scitools.github.io/test-iris-imagehash/images/v4/eba037a4c479c273b2963f2c6f6126966865d86f969e33c9b1706c26692793b0.png"
188+
],
189+
"iris.tests.integration.plot.test_vector_plots.TestBarbs.test_non_latlon_1d_coords.0": [
190+
"https://scitools.github.io/test-iris-imagehash/images/v4/a7ac334934d2e65c72596325b343338cb41c92d9c5b36f65330d379692ca6d6c.png"
191+
],
192+
"iris.tests.integration.plot.test_vector_plots.TestBarbs.test_non_latlon_2d_coords.0": [
193+
"https://scitools.github.io/test-iris-imagehash/images/v4/a7acb36134d2e676627963259343330cb43e92d9c5336e67330d379292ca6d6c.png"
194+
],
176195
"iris.tests.integration.plot.test_vector_plots.TestQuiver.test_2d_plain_latlon.0": [
177196
"https://scitools.github.io/test-iris-imagehash/images/v4/fb8d4f21c472b27e919d2e216f216b3178e69c7e961ab39a84696c616d245b94.png"
178197
],

0 commit comments

Comments
 (0)