Skip to content

Commit 4f547ee

Browse files
committed
Fixed doctests and minor fixes.
1 parent be4ee4d commit 4f547ee

File tree

1 file changed

+115
-88
lines changed

1 file changed

+115
-88
lines changed

docs/iris/src/userguide/merge_and_concat.rst

Lines changed: 115 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
Merge and Concatenate
55
=====================
66

7-
We saw in the :doc:`loading_iris_cubes` section that Iris tries to load as few cubes as
7+
We saw in the :doc:`loading_iris_cubes` chapter that Iris tries to load as few cubes as
88
possible. This is done by collecting together multiple fields with a shared standard
99
name (and other key metadata) into a single multidimensional cube. The processes that
1010
perform this behaviour in Iris are known as ``merge`` and ``concatenate``.
1111

12-
This section describes the ``merge`` and ``concatenate`` processes; it explains
12+
This chapter describes the ``merge`` and ``concatenate`` processes; it explains
1313
why common issues occur when using them and gives advice on how prevent these
1414
issues from occurring.
1515

@@ -32,12 +32,12 @@ sequential dimension coordinates*.
3232

3333
Let's imagine 28 individual cubes representing the
3434
temperature at a location ``(y, x)``, one cube for each day of February. We can use
35-
:meth:`merge <iris.cube.CubeList.merge>` to combine the 28 ``(y, x)`` cubes into
35+
:meth:`~iris.cube.CubeList.merge` to combine the 28 ``(y, x)`` cubes into
3636
a single ``(t, y, x)`` cube, where the length of the ``t`` dimension is 28.
3737

3838
Now imagine 12 individual cubes representing daily temperature at a time and
3939
location ``(t, y, x)``, one cube for each month in the year. We can use
40-
:meth:`concatenate <iris.cube.CubeList.concatenate>` to combine the 12
40+
:meth:`~iris.cube.CubeList.concatenate` to combine the 12
4141
``(t, y, x)`` cubes into a single ``(t, y, x)`` cube, where the length
4242
of the ``t`` dimension is now 365.
4343

@@ -59,7 +59,7 @@ if the scalar coordinate sequences form an orthogonal basis.
5959
.. important::
6060

6161
The shape, metadata, attributes, coordinates, coordinates metadata, fill value and
62-
other aspects of the a cube must be consistent across all of the input cubes.
62+
other aspects of the input cubes must be consistent across all of the input cubes.
6363

6464
The ``merge`` process will fail if these are not consistent. Such failures are
6565
covered in the :ref:`merge_concat_common_issues` section.
@@ -77,7 +77,7 @@ The :meth:`CubeList.merge <iris.cube.CubeList.merge>` method operates on a list
7777
of cubes and returns a new :class:`~iris.cube.CubeList` containing the cubes
7878
that have been merged.
7979

80-
.. testsetup::
80+
.. testsetup:: merge
8181

8282
import numpy as np
8383
import iris
@@ -96,7 +96,7 @@ variable called ``cubes``, each with a scalar ``z`` coordinate of
9696
differing value. We can merge these cubes by stacking the scalar ``z`` coordinates to
9797
make a new ``z`` dimension coordinate:
9898

99-
.. doctest::
99+
.. doctest:: merge
100100
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
101101

102102
>>> print cubes
@@ -166,7 +166,6 @@ into a single cube:
166166
cubes = iris.cube.CubeList([_xy_cube(1), _xy_cube(2), _xy_cube(3)])
167167
cubes[0].attributes['Conventions'] = 'CF-1.5'
168168

169-
170169
.. doctest:: merge_vs_merge_cube
171170
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
172171

@@ -177,9 +176,9 @@ into a single cube:
177176

178177
>>> print cubes[0].attributes
179178
{'Conventions': 'CF-1.5'}
180-
>>> print cubes[1]
179+
>>> print cubes[1].attributes
181180
{}
182-
>>> print cubes[2]
181+
>>> print cubes[2].attributes
183182
{}
184183

185184
>>> print cubes.merge()
@@ -220,7 +219,6 @@ load cubes from files without the ``merge`` process taking place. The return val
220219
:func:`iris.load_raw` is always a :class:`~iris.cube.CubeList` instance.
221220

222221

223-
224222
Concatenate
225223
-----------
226224

@@ -236,7 +234,7 @@ The order of the input cubes does not affect the ``concatenate`` process.
236234
.. important::
237235

238236
The shape, metadata, attributes, coordinates, coordinates metadata, fill value and
239-
other aspects of the a cube must be consistent across all of the input cubes.
237+
other aspects of the input cubes must be consistent across all of the input cubes.
240238

241239
The ``concatenate`` process will fail if these are not consistent. Such failures are
242240
covered in the :ref:`merge_concat_common_issues` section.
@@ -258,7 +256,22 @@ Let's have a look at the :meth:`~iris.cube.CubeList.concatenate` method in opera
258256
In the example below we have three 3D (*x*, *y*, *t*) cubes whose ``t`` coordinates
259257
have sequentially increasing ranges.
260258
These cubes can be concatenated by combining the ``t`` coordinates of the input
261-
cubes to form a new cube with an extended ``t`` coordinate::
259+
cubes to form a new cube with an extended ``t`` coordinate:
260+
261+
.. testsetup:: concatenate
262+
263+
import numpy as np
264+
import iris
265+
def _xyt_cube(t):
266+
cube = iris.cube.Cube(np.arange(12 * len(t)).reshape(-1, 3, 4), 'air_temperature', units='kelvin')
267+
cube.add_dim_coord(iris.coords.DimCoord(range(3), long_name='y'), 1)
268+
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='x'), 2)
269+
cube.add_dim_coord(iris.coords.DimCoord(t, long_name='t'), 0)
270+
return cube
271+
cubes = iris.cube.CubeList([_xyt_cube(np.arange(31)), _xyt_cube(np.arange(28) + 31), _xyt_cube(np.arange(31) + 59)])
272+
273+
.. doctest:: concatenate
274+
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
262275

263276
>>> print cubes
264277
0: air_temperature / (kelvin) (t: 31; y: 3; x: 4)
@@ -269,25 +282,6 @@ cubes to form a new cube with an extended ``t`` coordinate::
269282
0: air_temperature / (kelvin) (t: 90; y: 3; x: 4)
270283

271284

272-
..
273-
274-
DOCTEST DISABLED TEMPORARILY
275-
.. testsetup:: concatenate
276-
277-
import numpy as np
278-
import iris
279-
def _xyt_cube(t):
280-
cube = iris.cube.Cube(np.arange(12 * len(t)).reshape(-1, 3, 4), 'air_temperature', units='kelvin')
281-
cube.add_dim_coord(iris.coords.DimCoord(range(3), long_name='y'), 1)
282-
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='x'), 2)
283-
cube.add_dim_coord(iris.coords.DimCoord(t, long_name='t'), 0)
284-
return cube
285-
cubes = iris.cube.CubeList([_xyt_cube(range(31)), _xyt_cube(range(28)), _xyt_cube(range(31))])
286-
287-
.. doctest:: concatenate
288-
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
289-
290-
291285
The following diagram illustrates what has taken place in this example:
292286

293287
.. image:: concat.svg
@@ -317,8 +311,23 @@ from the earlier merge example.
317311
For the purposes of this example we'll add a *History* attribute to the first
318312
cube's :data:`~iris.cube.Cube.attributes` dictionary.
319313
Remember that the attributes *must* be consistent across all cubes in order to
320-
concatenate into a single cube::
314+
concatenate into a single cube:
321315

316+
.. testsetup:: concatenate_vs_concatenate_cube
317+
318+
import numpy as np
319+
import iris
320+
def _xyt_cube(t):
321+
cube = iris.cube.Cube(np.arange(12 * len(t)).reshape(-1, 3, 4), 'air_temperature', units='kelvin')
322+
cube.add_dim_coord(iris.coords.DimCoord(range(3), long_name='y'), 1)
323+
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='x'), 2)
324+
cube.add_dim_coord(iris.coords.DimCoord(t, long_name='t'), 0)
325+
return cube
326+
cubes = iris.cube.CubeList([_xyt_cube(np.arange(31)), _xyt_cube(np.arange(28) + 31), _xyt_cube(np.arange(31) + 59)])
327+
cubes[0].attributes['History'] = 'Created 2010-06-30'
328+
329+
.. doctest:: concatenate_vs_concatenate_cube
330+
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
322331

323332
>>> print cubes
324333
0: air_temperature / (kelvin) (t: 31; y: 3; x: 4)
@@ -331,8 +340,8 @@ concatenate into a single cube::
331340
{}
332341

333342
>>> print cubes.concatenate()
334-
0: air_temperature / (kelvin) (t: 31; x: 10; y: 10)
335-
1: air_temperature / (kelvin) (t: 59; x: 10; y: 10)
343+
0: air_temperature / (kelvin) (t: 31; y: 3; x: 4)
344+
1: air_temperature / (kelvin) (t: 59; y: 3; x: 4)
336345
>>> print cubes.concatenate_cube()
337346
Traceback (most recent call last):
338347
...
@@ -341,29 +350,6 @@ concatenate into a single cube::
341350
Cube metadata differs for phenomenon: air_temperature
342351

343352

344-
..
345-
346-
DOCTEST DISABLED TEMPORARILY
347-
348-
.. testsetup:: concatenate_vs_concatenate_cube
349-
350-
import numpy as np
351-
import iris
352-
def _xyt_cube(t):
353-
cube = iris.cube.Cube(np.arange(12 * len(t)).reshape(-1, 3, 4), 'air_temperature', units='kelvin')
354-
cube.add_dim_coord(iris.coords.DimCoord(range(3), long_name='y'), 1)
355-
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='x'), 2)
356-
cube.add_dim_coord(iris.coords.DimCoord(t, long_name='t'), 0)
357-
return cube
358-
cubes = iris.cube.CubeList([_xyt_cube(range(31)), _xyt_cube(range(28)), _xyt_cube(range(31))])
359-
cubes[0].attributes['History'] = 'Created 2010-06-30'
360-
361-
362-
.. doctest:: concatenate_vs_concatenate_cube
363-
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
364-
365-
366-
367353
Note that :meth:`~iris.cube.CubeList.concatenate` returns two cubes here.
368354
All the cubes that can be concatenated have been. Any cubes that can't be concatenated are
369355
included unchanged in the returned :class:`~iris.cube.CubeList`.
@@ -379,22 +365,22 @@ single cube. An example of fixing an issue like this can be found in the
379365
Common issues with merge and concatenate
380366
----------------------------------------
381367

382-
The Iris algorithms that drive :meth:`merge <iris.cube.CubeList.merge>` and
383-
:meth:`concatenate <iris.cube.CubeList.concatenate>` are complex and depend
368+
The Iris algorithms that drive :meth:`~iris.cube.CubeList.merge` and
369+
:meth:`~iris.cube.CubeList.concatenate` are complex and depend
384370
on a number of different elements of the input cubes being consistent across
385371
all input cubes.
386372
If this consistency is not maintained then the
387-
:meth:`merge <iris.cube.CubeList.merge>` or
388-
:meth:`concatenate <iris.cube.CubeList.concatenate>` process can fail in a
373+
:meth:`~iris.cube.CubeList.merge` or
374+
:meth:`~iris.cube.CubeList.concatenate` process can fail in a
389375
seemingly arbitrary manner.
390376

391-
The methods :meth:`merge_cube <iris.cube.CubeList.merge_cube>` and
392-
:meth:`concatenate_cube <iris.cube.CubeList.concatenate_cube>`
377+
The methods :meth:`~iris.cube.CubeList.merge_cube` and
378+
:meth:`~iris.cube.CubeList.concatenate_cube`
393379
were introduced to Iris to help you locate differences in input cubes
394380
that prevent the input cubes merging or concatenating.
395381
Nevertheless, certain difficulties with using
396-
:meth:`merge <iris.cube.CubeList.merge>` and
397-
:meth:`concatenate <iris.cube.CubeList.concatenate>` occur frequently.
382+
:meth:`~iris.cube.CubeList.merge` and
383+
:meth:`~iris.cube.CubeList.concatenate` occur frequently.
398384
This section describes these common difficulties, why they arise and
399385
what you can do to avoid them.
400386

@@ -423,8 +409,7 @@ To demonstrate using :func:`~iris.experimental.equalise_cubes.equalise_attribute
423409
let's return to our non-merging list of input cubes from the merge_cube example
424410
from earlier.
425411
We'll call :func:`~iris.experimental.equalise_cubes.equalise_attributes` on the
426-
input cubes before merging the input cubes using :meth:`~iris.cube.CubeList.merge_cube`::
427-
412+
input cubes before merging the input cubes using :meth:`~iris.cube.CubeList.merge_cube`:
428413

429414
.. doctest:: merge_vs_merge_cube
430415
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
@@ -437,9 +422,9 @@ input cubes before merging the input cubes using :meth:`~iris.cube.CubeList.merg
437422

438423
>>> print cubes[0].attributes
439424
{'Conventions': 'CF-1.5'}
440-
>>> print cubes[1]
425+
>>> print cubes[1].attributes
441426
{}
442-
>>> print cubes[2]
427+
>>> print cubes[2].attributes
443428
{}
444429

445430
>>> print cubes.merge_cube()
@@ -455,7 +440,11 @@ input cubes before merging the input cubes using :meth:`~iris.cube.CubeList.merg
455440
{}
456441

457442
>>> print cubes.merge_cube()
458-
0: air_temperature / (kelvin) (z: 3; y: 4; x: 5)
443+
air_temperature / (kelvin) (z: 3; y: 4; x: 5)
444+
Dimension coordinates:
445+
z x - -
446+
y - x -
447+
x - - x
459448

460449

461450
**Incomplete Data**
@@ -495,21 +484,39 @@ scalar ``z`` coordinate with value 2 and the third has a scalar ``z``
495484
coordinate with value 1.
496485
The first and third cubes are thus identical.
497486
We will demonstrate the effect of merging the input cubes with ``unique=False``
498-
(duplicate cubes allowed) and ``unique=True`` (duplicate cubes not allowed)::
487+
(duplicate cubes allowed) and ``unique=True`` (duplicate cubes not allowed):
488+
489+
.. testsetup:: merge_duplicate
490+
491+
import numpy as np
492+
import iris
493+
def _xy_cube(z):
494+
cube = iris.cube.Cube(np.arange(20).reshape(4, 5), 'air_temperature', units='kelvin')
495+
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='y'), 0)
496+
cube.add_dim_coord(iris.coords.DimCoord(range(5), long_name='x'), 1)
497+
cube.add_aux_coord(iris.coords.DimCoord(z, long_name='z', units='meters'))
498+
return cube
499+
cubes = iris.cube.CubeList([_xy_cube(1), _xy_cube(2), _xy_cube(1)])
500+
501+
.. doctest:: merge_duplicate
502+
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
499503

500504
>>> print cubes
501-
0: air_temperature / (kelvin) (x: 10; y: 10)
502-
1: air_temperature / (kelvin) (x: 10; y: 10)
503-
2: air_temperature / (kelvin) (x: 10; y: 10)
505+
0: air_temperature / (kelvin) (y: 4; x: 5)
506+
1: air_temperature / (kelvin) (y: 4; x: 5)
507+
2: air_temperature / (kelvin) (y: 4; x: 5)
508+
504509
>>> print cubes.merge(unique=False)
505-
0: air_temperature / (kelvin) (z: 2; x: 10; y: 10)
506-
1: air_temperature / (kelvin) (z: 2; x: 10; y: 10)
507-
>>> print cubelist.merge() # unique=True is the default.
510+
0: air_temperature / (kelvin) (z: 2; y: 4; x: 5)
511+
1: air_temperature / (kelvin) (z: 2; y: 4; x: 5)
512+
513+
>>> print cubes.merge() # unique=True is the default.
508514
Traceback (most recent call last):
509515
...
510516
iris.exceptions.DuplicateDataError: failed to merge into a single cube.
511517
Duplicate 'air_temperature' cube, with scalar coordinates z=Cell(point=1, bound=None)
512518

519+
513520
Notice how merging the input cubes with duplicate cubes allowed produces a result
514521
with **four** `z` coordinate values.
515522
Closer inspection of these two resultant cubes demonstrates that the
@@ -578,12 +585,33 @@ To demonstrate using :func:`~iris.util.unify_time_units`,
578585
let's adapt our list of input cubes from the ``concatenate_cube`` example from earlier.
579586
We'll give the input cubes unequal time coordinate units and call
580587
:func:`~iris.util.unify_time_units` on the input cubes before concatenating
581-
the input cubes using :meth:`~iris.cube.CubeList.concatenate_cube`::
588+
the input cubes using :meth:`~iris.cube.CubeList.concatenate_cube`:
589+
590+
.. testsetup:: concatenate_time_units
591+
592+
import numpy as np
593+
import iris
594+
def _xyt_cube(t):
595+
cube = iris.cube.Cube(np.arange(12 * len(t)).reshape(-1, 3, 4), 'air_temperature', units='kelvin')
596+
cube.add_dim_coord(iris.coords.DimCoord(range(3), long_name='y'), 1)
597+
cube.add_dim_coord(iris.coords.DimCoord(range(4), long_name='x'), 2)
598+
cube.add_dim_coord(iris.coords.DimCoord(t, long_name='t'), 0)
599+
return cube
600+
cubes = iris.cube.CubeList([_xyt_cube(np.arange(31).astype(np.float64)),
601+
_xyt_cube(np.arange(28).astype(np.float64) + 31),
602+
_xyt_cube(np.arange(31).astype(np.float64) + 59)])
603+
cubes[0].coord('t').units = 'days since 1990-02-15'
604+
cubes[1].coord('t').units = 'days since 1970-01-01'
605+
cubes[2].coord('t').units = 'days since 1970-01-01'
606+
607+
.. doctest:: concatenate_time_units
608+
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE
582609

583610
>>> from iris.util import unify_time_units
584611
>>> print cubes
585-
0: air_temperature / (kelvin) (t: 10; x: 10; y: 10)
586-
1: air_temperature / (kelvin) (t: 10; x: 10; y: 10)
612+
0: air_temperature / (kelvin) (t: 31; y: 3; x: 4)
613+
1: air_temperature / (kelvin) (t: 28; y: 3; x: 4)
614+
2: air_temperature / (kelvin) (t: 31; y: 3; x: 4)
587615

588616
>>> print cubes[0].coord('t').units
589617
days since 1990-02-15
@@ -592,8 +620,8 @@ the input cubes using :meth:`~iris.cube.CubeList.concatenate_cube`::
592620

593621
>>> print cubes.concatenate_cube()
594622
Traceback (most recent call last):
595-
...
596-
iris.exceptions.ConcatenateError: failed to concatenate into a single cube.
623+
...
624+
ConcatenateError: failed to concatenate into a single cube.
597625
Dimension coordinates metadata differ: t != t
598626

599627
>>> unify_time_units(cubes)
@@ -602,12 +630,11 @@ the input cubes using :meth:`~iris.cube.CubeList.concatenate_cube`::
602630
days since 1990-02-15
603631

604632
>>> print cubes.concatenate_cube()
605-
air_temperature / (kelvin) (t: 20; x: 10; y: 10)
633+
air_temperature / (kelvin) (t: 90; y: 3; x: 4)
606634
Dimension coordinates:
607-
t x - -
608-
x - x -
609-
y - - x
610-
635+
t x - -
636+
y - x -
637+
x - - x
611638

612639
**Attributes Mismatch**
613640

0 commit comments

Comments
 (0)