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
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Release 1.5 (unreleased)

Features added
--------------
* Scatter plots can now be produced using `iris.plot.scatter` and
`iris.quickplot.scatter`.
* The functions `iris.plot.plot` and `iris.quickplot.plot` now take up to two
arguments, which may be cubes or coordinates, allowing the user to have full
control over what is plotted on each axis. The coords keyword argument is now
Expand Down
2 changes: 2 additions & 0 deletions docs/iris/src/whatsnew/1.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Iris 1.5 features

A summary of the main features added with version 1.5:

* Scatter plots can now be produced using :func:`iris.plot.scatter` and
:func:`iris.quickplot.scatter`.
* The functions :func:`iris.plot.plot` and :func:`iris.quickplot.plot` now take
up to two arguments, which may be cubes or coordinates, allowing the user to
have full control over what is plotted on each axis. The coords keyword argument
Expand Down
26 changes: 26 additions & 0 deletions lib/iris/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,32 @@ def plot(*args, **kwargs):
return _draw_1d_from_points('plot', _plot_args, *args, **kwargs)


def scatter(x, y, *args, **kwargs):
"""
Draws a scatter plot based on the given cube(s) or coordinate(s).

Args:

* x: :class:`~iris.cube.Cube` or :class:`~iris.coords.Coord`
A cube or a coordinate to plot on the x-axis.

* y: :class:`~iris.cube.Cube` or :class:`~iris.coords.Coord`
A cube or a coordinate to plot on the y-axis.

See :func:`matplotlib.pyplot.scatter` for details of valid keyword
arguments.

"""
# here we are more specific about argument types than generic 1d plotting
if not isinstance(x, (iris.cube.Cube, iris.coords.Coord)):
raise TypeError('x must be a cube or a coordinate.')
if not isinstance(y, (iris.cube.Cube, iris.coords.Coord)):
raise TypeError('y must be a cube or a coordinate.')
args = (x, y) + args
_plot_args = None
return _draw_1d_from_points('scatter', _plot_args, *args, **kwargs)


# Provide convenience show method from pyplot
show = plt.show

Expand Down
14 changes: 14 additions & 0 deletions lib/iris/quickplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,5 +237,19 @@ def plot(*args, **kwargs):
return result


def scatter(x, y, *args, **kwargs):
"""
Draws a labelled scatter plot based on the given cubes or
coordinates.

See :func:`iris.plot.scatter` for details of valid arguments and
keyword arguments.

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


# Provide a convenience show method from pyplot.
show = plt.show
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 79 additions & 0 deletions lib/iris/tests/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,85 @@ def setUp(self):
self.draw_method = qplt.plot


@tests.skip_data
class Test1dScatter(tests.GraphicsTest):

def setUp(self):
self.cube = iris.load_cube(
tests.get_data_path(('NAME', 'NAMEIII_trajectory.txt')),
'Temperature')
self.draw_method = iplt.scatter

def test_coord_coord(self):
x = self.cube.coord('longitude')
y = self.cube.coord('height')
c = self.cube.data
self.draw_method(x, y, c=c, edgecolor='none')
self.check_graphic()

def test_coord_coord_map(self):
x = self.cube.coord('longitude')
y = self.cube.coord('latitude')
c = self.cube.data
self.draw_method(x, y, c=c, edgecolor='none')
plt.gca().coastlines()
self.check_graphic()

def test_coord_cube(self):
x = self.cube.coord('latitude')
y = self.cube
c = self.cube.coord('Travel Time').points
self.draw_method(x, y, c=c, edgecolor='none')
self.check_graphic()

def test_cube_coord(self):
x = self.cube
y = self.cube.coord('height')
c = self.cube.coord('Travel Time').points
self.draw_method(x, y, c=c, edgecolor='none')
self.check_graphic()

def test_cube_cube(self):
x = iris.load_cube(
tests.get_data_path(('NAME', 'NAMEIII_trajectory.txt')),
'Rel Humidity')
y = self.cube
c = self.cube.coord('Travel Time').points
self.draw_method(x, y, c=c, edgecolor='none')
self.check_graphic()

def test_incompatible_objects(self):
# cubes/coordinates of different sizes cannot be plotted
x = self.cube
y = self.cube.coord('height')[:-1]
with self.assertRaises(ValueError):
self.draw_method(x, y)

def test_multidimensional(self):
# multidimensional cubes/coordinates are not allowed
x = _load_4d_testcube()[0, :, :, 0]
y = x.coord('model_level_number')
with self.assertRaises(ValueError):
self.draw_method(x, y)

def test_not_cube_or_coord(self):
# inputs must be cubes or coordinates
x = np.arange(self.cube.shape[0])
y = self.cube
with self.assertRaises(TypeError):
self.draw_method(x, y)


@tests.skip_data
class Test1dQuickplotScatter(Test1dScatter):

def setUp(self):
self.cube = iris.load_cube(
tests.get_data_path(('NAME', 'NAMEIII_trajectory.txt')),
'Temperature')
self.draw_method = qplt.scatter


# Caches _load_4d_testcube so subsequent calls are faster
def cache(fn, cache={}):
def inner(*args, **kwargs):
Expand Down