Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 48 additions & 26 deletions lib/iris/quickplot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# (C) British Crown Copyright 2010 - 2016, Met Office
# (C) British Crown Copyright 2010 - 2018, Met Office
#
# This file is part of Iris.
#
Expand Down Expand Up @@ -61,10 +61,13 @@ def _title(cube_or_coord, with_units):
return title


def _label(cube, mode, result=None, ndims=2, coords=None):
def _label(cube, mode, result=None, ndims=2, coords=None, axes=None):
"""Puts labels on the current plot using the given cube."""

plt.title(_title(cube, with_units=False))
if axes is None:
axes = plt.gca()

axes.set_title(_title(cube, with_units=False))

if result is not None:
draw_edges = mode == iris.coords.POINT_MODE
Expand All @@ -89,22 +92,23 @@ def _label(cube, mode, result=None, ndims=2, coords=None):

if ndims == 2:
if not iplt._can_draw_map(plot_defn.coords):
plt.ylabel(_title(plot_defn.coords[0], with_units=True))
plt.xlabel(_title(plot_defn.coords[1], with_units=True))
axes.set_ylabel(_title(plot_defn.coords[0], with_units=True))
axes.set_xlabel(_title(plot_defn.coords[1], with_units=True))
elif ndims == 1:
plt.xlabel(_title(plot_defn.coords[0], with_units=True))
plt.ylabel(_title(cube, with_units=True))
axes.set_xlabel(_title(plot_defn.coords[0], with_units=True))
axes.set_ylabel(_title(cube, with_units=True))
else:
msg = 'Unexpected number of dimensions (%s) given to _label.' % ndims
msg = 'Unexpected number of dimensions ({}) given to ' \
'_label.'.format(ndims)
raise ValueError(msg)


def _label_with_bounds(cube, result=None, ndims=2, coords=None):
_label(cube, iris.coords.BOUND_MODE, result, ndims, coords)
def _label_with_bounds(cube, result=None, ndims=2, coords=None, axes=None):
_label(cube, iris.coords.BOUND_MODE, result, ndims, coords, axes)


def _label_with_points(cube, result=None, ndims=2, coords=None):
_label(cube, iris.coords.POINT_MODE, result, ndims, coords)
def _label_with_points(cube, result=None, ndims=2, coords=None, axes=None):
_label(cube, iris.coords.POINT_MODE, result, ndims, coords, axes)


def _get_titles(u_object, v_object):
Expand All @@ -126,15 +130,26 @@ def _get_titles(u_object, v_object):
return xlabel, ylabel, title


def _label_1d_plot(*args):
def _label_1d_plot(*args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicit is better than implicit: we don't want to catch all kwargs, because we do nothing with them. Instead, explicitly put axes as a keyword argument here. 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True enough! I'll change that 👍

if len(args) > 1 and isinstance(args[1],
(iris.cube.Cube, iris.coords.Coord)):
xlabel, ylabel, title = _get_titles(*args[:2])
else:
xlabel, ylabel, title = _get_titles(None, args[0])
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)

axes = kwargs.pop('axes', None)

if len(kwargs) != 0:
msg = 'Unexpected kwargs {} given to _label_1d_plot'.format(
kwargs.keys())
raise ValueError(msg)

if axes is None:
axes = plt.gca()

axes.set_title(title)
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)


def contour(cube, *args, **kwargs):
Expand All @@ -158,8 +173,9 @@ def contour(cube, *args, **kwargs):

"""
coords = kwargs.get('coords')
axes = kwargs.get('axes')
result = iplt.contour(cube, *args, **kwargs)
_label_with_points(cube, coords=coords)
_label_with_points(cube, coords=coords, axes=axes)
return result


Expand All @@ -184,12 +200,13 @@ def contourf(cube, *args, **kwargs):

"""
coords = kwargs.get('coords')
axes = kwargs.get('axes')
result = iplt.contourf(cube, *args, **kwargs)
_label_with_points(cube, result, coords=coords)
_label_with_points(cube, result, coords=coords, axes=axes)
return result


def outline(cube, coords=None, color='k', linewidth=None):
def outline(cube, coords=None, color='k', linewidth=None, axes=None):
"""
Draws cell outlines on a labelled plot based on the given Cube.

Expand All @@ -211,9 +228,9 @@ def outline(cube, coords=None, color='k', linewidth=None):

"""
result = iplt.outline(cube, color=color, linewidth=linewidth,
coords=coords)
coords=coords, axes=axes)

_label_with_bounds(cube, coords=coords)
_label_with_bounds(cube, coords=coords, axes=axes)
return result


Expand All @@ -225,8 +242,9 @@ def pcolor(cube, *args, **kwargs):

"""
coords = kwargs.get('coords')
axes = kwargs.get('axes')
result = iplt.pcolor(cube, *args, **kwargs)
_label_with_bounds(cube, result, coords=coords)
_label_with_bounds(cube, result, coords=coords, axes=axes)
return result


Expand All @@ -238,8 +256,9 @@ def pcolormesh(cube, *args, **kwargs):

"""
coords = kwargs.get('coords')
axes = kwargs.get('axes')
result = iplt.pcolormesh(cube, *args, **kwargs)
_label_with_bounds(cube, result, coords=coords)
_label_with_bounds(cube, result, coords=coords, axes=axes)
return result


Expand All @@ -251,8 +270,9 @@ def points(cube, *args, **kwargs):

"""
coords = kwargs.get('coords')
axes = kwargs.get('axes')
result = iplt.points(cube, *args, **kwargs)
_label_with_points(cube, coords=coords)
_label_with_points(cube, coords=coords, axes=axes)
return result


Expand All @@ -265,8 +285,9 @@ def plot(*args, **kwargs):
keyword arguments.

"""
axes = kwargs.get('axes')
result = iplt.plot(*args, **kwargs)
_label_1d_plot(*args)
_label_1d_plot(*args, axes=axes)
return result


Expand All @@ -279,8 +300,9 @@ def scatter(x, y, *args, **kwargs):
keyword arguments.

"""
axes = kwargs.get('axes')
result = iplt.scatter(x, y, *args, **kwargs)
_label_1d_plot(x, y)
_label_1d_plot(x, y, axes=axes)
return result


Expand Down
26 changes: 26 additions & 0 deletions lib/iris/tests/test_quickplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,32 @@ def test_contourf(self):
qplt.contourf(self._small(), coords=['grid_longitude', 'model_level_number'])
self.check_graphic()

def test_contourf_axes_specified(self):
# Check that the contourf function does not modify the matplotlib
# pyplot state machine.

# Create a figure and axes to be used by contourf
plt.figure()
axes1 = plt.axes()

# Create test figure and axes which will be the new results
# of plt.gcf and plt.gca.
plt.figure()
axes2 = plt.axes()

# Add a title to the test axes.
plt.title('This should not be changed')
# Draw the contourf on a specific axes.
qplt.contourf(self._small(), axes=axes1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, would be super interested to know if we can make use of the interface that matplotlib provide to allow plt.contourf(..., data=cube). ref: https://matplotlib.org/gallery/misc/keyword_plotting.html


# Ensure that the correct axes got the appropriate title.
self.assertEqual(axes2.get_title(), 'This should not be changed')
self.assertEqual(axes1.get_title(), 'Air potential temperature')

# Check that the axes labels were set correctly.
self.assertEqual(axes1.get_xlabel(), 'Grid longitude / degrees')
self.assertEqual(axes1.get_ylabel(), 'Altitude / m')

def test_contourf_nameless(self):
cube = self._small()
cube.standard_name = None
Expand Down