Skip to content

Commit e75e7e1

Browse files
committed
Docs update
1 parent 9d96715 commit e75e7e1

File tree

21 files changed

+510
-142
lines changed

21 files changed

+510
-142
lines changed

continuous-integration/docs.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ channels:
33

44
dependencies:
55
- geos ~=3.12.2
6-
- python =3.12
6+
- python =3.14
77
- wheel
88
- pip:
9-
- -r ./requirements-3.12.txt
9+
- -r ./requirements-3.14.txt
1010
- -e ..[docs]
1.03 MB
Binary file not shown.
313 KB
Loading
127 KB
Loading
3.54 KB
Loading

docs/api/conventions/interface.rst

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,33 @@ the :class:`~emsarray.conventions.Convention` interface.
1515
.. autofunction:: emsarray.open_dataset
1616
.. autofunction:: emsarray.get_dataset_convention
1717

18-
.. autoclass:: emsarray.conventions.Convention
19-
:members:
18+
Convention
19+
==========
2020

21-
.. autoclass:: emsarray.conventions.DimensionConvention
21+
All dataset conventions have the following methods:
2222

23-
.. autoattribute:: grid_dimensions
23+
.. autoclass:: emsarray.conventions.Convention
24+
:members:
2425

2526
.. autoclass:: emsarray.conventions.Grid
2627
:members:
2728

28-
.. autoclass:: emsarray.conventions.DimensionGrid
29-
:members: dimensions
29+
Concepts
30+
========
3031

3132
.. type:: GridKind
3233

33-
Some type that can enumerate the different :ref:`grid types <grids>`
34-
present in a dataset.
35-
This can be an :class:`enum.Enum` listing each different kind of grid.
34+
All datasets define variables on one or more :ref:`grid<grids>`.
35+
:type:`GridKind` enumerates all the available grids for a specific convention,
36+
while :class:`Grid` provides methods for introspecting a particular grid.
37+
38+
The :type:`GridKind` for a dataset is usually an :class:`enum.Enum` listing each different kind of grid.
39+
40+
.. rubric:: Notes
3641

3742
:type:`Index` values will be included in the feature properties
3843
of exported geometry from :mod:`emsarray.operations.geometry`.
39-
If the index type includes the grid kind,
44+
As the native index for a convention usually includes the grid kind,
4045
the grid kind needs to be JSON serializable.
4146
The easiest way to achieve this is to make your GridKind type subclass :class:`str`:
4247

@@ -60,6 +65,20 @@ the :class:`~emsarray.conventions.Convention` interface.
6065
this should be a tuple whos first element is :type:`.GridKind`.
6166
For conventions with a single grid, :type:`.GridKind` is not required.
6267

68+
Dimension conventions
69+
=====================
70+
71+
Most dataset conventions have grids that are uniquely identifiable by their dimensions.
72+
For these conventions the DimensionConvention subclass provides many default implementations.
73+
These details are most relevant for developers implementing new Convention subclasses.
74+
75+
.. autoclass:: emsarray.conventions.DimensionConvention
76+
77+
.. autoattribute:: grid_dimensions
78+
79+
.. autoclass:: emsarray.conventions.DimensionGrid
80+
:members: dimensions
81+
6382
.. autoclass:: emsarray.conventions.Specificity
6483
:members:
6584
:undoc-members:

docs/api/plot.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ and have limited customisation options.
1414
Consult the :ref:`examples gallery <examples>`
1515
for demonstrations on making more customised plots.
1616

17+
The :ref:`examples <examples>` section contains many worked examples on how to generate plots.
18+
:ref:`example-plot-with-clim` is a good place to start.
19+
20+
Shortcuts
21+
=========
22+
23+
These functions will generate an entire plot,
24+
but have limited customisation options.
25+
1726
.. autofunction:: plot_on_figure
1827
.. autofunction:: animate_on_figure
1928

docs/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'sphinx.ext.autodoc',
4040
'sphinx.ext.intersphinx',
4141
'sphinx.ext.napoleon',
42+
'sphinxcontrib.video',
4243
'roles'
4344
]
4445

@@ -56,6 +57,7 @@
5657
# a list of builtin themes.
5758
#
5859
html_theme = 'sphinx_book_theme'
60+
html_theme_options = {'show_toc_level': 2}
5961

6062
# Add any paths that contain custom static files (such as style sheets) here,
6163
# relative to this directory. They are copied after the builtin static files,

docs/examples/animated-plot.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import cartopy.crs
2+
import datetime
3+
import emsarray
4+
import emsarray.plot
5+
import numpy
6+
from cartopy.feature import GSHHSFeature
7+
from emsarray.utils import datetime_from_np_time
8+
from matplotlib import pyplot
9+
from matplotlib.artist import Artist
10+
from matplotlib.animation import FuncAnimation, FFMpegWriter
11+
12+
# Open the dataset
13+
ds = emsarray.tutorial.open_dataset('kgari')
14+
15+
# Select just the surface water and get the current vectors
16+
surface = ds.isel(k=-1)
17+
u, v = surface['u'], surface['v']
18+
# Compute the magnitude of the current vectors
19+
magnitude = numpy.sqrt(u ** 2 + v ** 2)
20+
21+
22+
# The dataset is in Australian Eastern Standard Time, UTC +10
23+
aest_timezone = datetime.timezone(datetime.timedelta(hours=10))
24+
25+
26+
# Make a figure
27+
figure = pyplot.figure(figsize=(8, 8), layout='constrained')
28+
axes = figure.add_subplot(projection=cartopy.crs.PlateCarree())
29+
axes.set_aspect('equal', adjustable='datalim')
30+
coast = GSHHSFeature(scale='intermediate')
31+
axes.add_feature(coast, facecolor='mistyrose', edgecolor='darkgrey', linewidth=0.5)
32+
axes.set_facecolor('aliceblue')
33+
34+
35+
# Make an artist to plot magnitude, selecting the first time step of data.
36+
# When making an animation it is important to keep the artist in a variable
37+
# so you can update the data frame by frame.
38+
magnitude_artist = ds.ems.make_artist(
39+
axes, magnitude.isel(time=0),
40+
add_colorbar=False,
41+
clim=(0, 1), edgecolor='face', cmap='Oranges',
42+
)
43+
figure.colorbar(magnitude_artist, ax=axes, location='right', label="metres per second")
44+
45+
# Make an artist to plot the current vectors
46+
uv_artist = ds.ems.make_artist(
47+
axes, (u.isel(time=0), v.isel(time=0)),
48+
scale=40)
49+
50+
51+
# Finish setting up the plot
52+
axes.autoscale()
53+
54+
55+
def update_plot(frame: int) -> list[Artist]:
56+
# This function is called every frame and should update the plot with new data.
57+
58+
# Disable the matplotlib layout engine after the first frame
59+
# else the plot has a tendency to jiggle around on later frames.
60+
if frame > 0:
61+
figure.set_layout_engine('none')
62+
63+
# Update the plot title to display the frame time
64+
frame_time = datetime_from_np_time(ds['time'].isel(time=frame).values)
65+
frame_time = frame_time.astimezone(aest_timezone)
66+
axes.set_title(f"Surface water currents\n{frame_time:%Y-%m-%d %H:%M %Z}")
67+
68+
# Update the data being plotted by the artists
69+
magnitude_artist.set_data_array(magnitude.isel(time=frame))
70+
uv_artist.set_data_array((u.isel(time=frame), v.isel(time=frame)))
71+
72+
# Return every artist that has been updated this frame
73+
return [axes.title, magnitude_artist, uv_artist]
74+
75+
76+
animation = FuncAnimation(
77+
figure, # The figure to animate
78+
update_plot, # The function to call to update the plot data
79+
frames=ds.sizes['time'], # How many frames of animation to render
80+
)
81+
82+
# Draw and save the first frame of the animation for a thumbnail
83+
update_plot(0)
84+
figure.savefig('animated-plot.png')
85+
86+
# Save the animation
87+
ffmpeg_writer = FFMpegWriter(fps=5, bitrate=1800)
88+
animation.save('animated-plot.mp4', writer=ffmpeg_writer)
89+
90+
pyplot.show(block=True)

docs/examples/animated-plot.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.. _example-animated-plot:
2+
3+
=============
4+
Animated plot
5+
=============
6+
7+
Animated plots are possible with emsarray by using :class:`matplotlib.animation.FuncAnimation`
8+
and calling :meth:`.GridArtist.set_data_array()` each frame.
9+
A :class:`~matplotlib.animation.FuncAnimation` will call a function every frame where you can update the plot.
10+
Each artist returned by :meth:`.Convention.make_artist()` has a :meth:`~.GridArtist.set_data_array()` method
11+
which can be used to update the data in the plot.
12+
In combination this makes animations in emsarray about as straight forward as making a static plot:
13+
14+
.. video:: /_static/images/animated-plot.mp4
15+
:poster: /_static/images/animated-plot.png
16+
:alt: A video of surface water currents around K'gari.
17+
:loop:
18+
:muted:
19+
:width: 100%
20+
21+
Code
22+
====
23+
24+
Saving a video to a file requires `ffmpeg <https://www.ffmpeg.org/>`_
25+
which can be installed using conda:
26+
27+
.. code-block:: shell
28+
29+
$ conda install ffmpeg
30+
31+
:download:`Download animated-plot.py example <animated-plot.py>`.
32+
33+
.. literalinclude:: animated-plot.py
34+
:language: python
35+

0 commit comments

Comments
 (0)