From 1dd0fd4d2db16888d0e51c3b2f8c17da0fb52a45 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 7 May 2024 15:35:37 -0700 Subject: [PATCH 1/3] gallery plus api --- docs/api.rst | 1 + docs/conf.py | 27 +++++- docs/index.rst | 4 +- examples/README.txt | 6 ++ examples/arrayanimatorwcs.py | 87 +++++++++++++++++++ examples/lineanimator.py | 52 +++++++++++ mpl_animators/__init__.py | 2 + ...ure_hashes_mpl_dev_ft_261_astropy_dev.json | 18 ++-- setup.cfg | 2 + tox.ini | 2 +- 10 files changed, 186 insertions(+), 15 deletions(-) create mode 100644 docs/api.rst create mode 100644 examples/README.txt create mode 100644 examples/arrayanimatorwcs.py create mode 100644 examples/lineanimator.py diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..1ce0bf3 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1 @@ +.. automodapi:: mpl_animators diff --git a/docs/conf.py b/docs/conf.py index 2d31b11..0535e53 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,12 +6,15 @@ # full list see the documentation: # http://www.sphinx-doc.org/en/master/config +import datetime +from pathlib import Path # -- Project information ----------------------------------------------------- -project = 'mpl-animators' -copyright = '2021, The SunPy Developers' -author = 'The SunPy Developers' +project = "mpl-animators" +author = "The SunPy Community" +copyright = f"{datetime.datetime.now(datetime.timezone.utc).year}, {author}" # NOQA: A001 +author = "The SunPy Developers" # The full version, including alpha/beta/rc tags from mpl_animators import __version__ @@ -34,6 +37,7 @@ 'sphinx.ext.mathjax', 'sphinx_automodapi.automodapi', 'sphinx_automodapi.smart_resolver', + "sphinx_gallery.gen_gallery", ] # Add any paths that contain templates here, relative to this directory. @@ -77,8 +81,23 @@ # -- Options for HTML output ------------------------------------------------- from sunpy_sphinx_theme.conf import * # NOQA - +from sunpy_sphinx_theme import PNG_ICON # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] + +# -- Sphinx Gallery ------------------------------------------------------------ +sphinx_gallery_conf = { + "backreferences_dir": (Path("generated") / "modules").absolute(), + "filename_pattern": "^((?!skip_).)*$", + "examples_dirs": (Path("..") / "examples").absolute(), + "gallery_dirs": (Path("generated") / "gallery").absolute(), + "matplotlib_animations": True, + "default_thumb_file": PNG_ICON, # NOQA + "abort_on_example_error": False, + "plot_gallery": "True", + "remove_config_comments": True, + "doc_module": ("mpl_animators"), + "only_warn_on_example_error": True, +} diff --git a/docs/index.rst b/docs/index.rst index ce825b0..48d5235 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,4 +11,6 @@ Finally, there are two base classes: `.BaseFuncAnimator` which can be extended t .. toctree:: :maxdepth: 2 - :caption: Contents: + + generated/gallery/index + api diff --git a/examples/README.txt b/examples/README.txt new file mode 100644 index 0000000..6e6dceb --- /dev/null +++ b/examples/README.txt @@ -0,0 +1,6 @@ +*************** +Example Gallery +*************** + +The gallery contains examples of how to use mpl-animators. +Each example is a short and self contained how-to guide for performing a specific task. \ No newline at end of file diff --git a/examples/arrayanimatorwcs.py b/examples/arrayanimatorwcs.py new file mode 100644 index 0000000..7d685fe --- /dev/null +++ b/examples/arrayanimatorwcs.py @@ -0,0 +1,87 @@ +""" +============================================== +Creating a visualization with ArrayAnimatorWCS +============================================== + +This example shows how to create a simple visualization using +`~mpl_animators.ArrayAnimatorWCS`. +""" +import astropy.units as u +import astropy.wcs +import matplotlib.pyplot as plt +import sunpy.map +from astropy.visualization import AsinhStretch, ImageNormalize +from sunpy.data.sample import AIA_171_IMAGE, AIA_193_IMAGE +from sunpy.time import parse_time + +from mpl_animators import ArrayAnimatorWCS + +################################################################################ +# To showcase how to visualize a sequence of 2D images using +# `~mpl_animators.ArrayAnimatorWCS`, we will use images from +# our sample data. The problem with this is that they are not part of +# a continuous dataset. To overcome this we will do two things. +# Create a stacked array of the images and create a `~astropy.wcs.WCS` header. +# The easiest method for the array is to create a `~sunpy.map.MapSequence`. + +# Here we only use two files but you could pass in a larger selection of files. +map_sequence = sunpy.map.Map(AIA_171_IMAGE, AIA_193_IMAGE, sequence=True) + +# Now we can just cast the sequence away into a NumPy array. +sequence_array = map_sequence.as_array() + +# We'll also define a common normalization to use in the animations +norm = ImageNormalize(vmin=0, vmax=3e4, stretch=AsinhStretch(0.01)) + +############################################################################### +# Now we need to create the `~astropy.wcs.WCS` header that +# `~mpl_animators.ArrayAnimatorWCS` will need. +# To create the new header we can use the stored meta information from the +# ``map_sequence``. + +# Now we need to get the time difference between the two observations. +t0, t1 = map(parse_time, [k["date-obs"] for k in map_sequence.all_meta()]) +time_diff = (t1 - t0).to(u.s) + +m = map_sequence[0] + +wcs = astropy.wcs.WCS(naxis=3) +wcs.wcs.crpix = u.Quantity([0 * u.pix, *list(m.reference_pixel)]) +wcs.wcs.cdelt = [time_diff.value, *list(u.Quantity(m.scale).value)] +wcs.wcs.crval = [0, m._reference_longitude.value, m._reference_latitude.value] +wcs.wcs.ctype = ["TIME", *list(m.coordinate_system)] +wcs.wcs.cunit = ["s", *list(m.spatial_units)] +wcs.wcs.aux.rsun_ref = m.rsun_meters.to_value(u.m) + +# Now the resulting WCS object will look like: +print(wcs) + +############################################################################### +# Now we can create the animation. +# `~mpl_animators.ArrayAnimatorWCS` requires you to select which +# axes you want to plot on the image. All other axes should have a ``0`` and +# sliders will be created to control the value for this axis. + +wcs_anim = ArrayAnimatorWCS(sequence_array, wcs, [0, "x", "y"], norm=norm).get_animation() + +plt.show() + +############################################################################### +# You might notice that the animation could do with having the axes look +# neater. `~mpl_animators.ArrayAnimatorWCS` provides a way of setting +# some display properties of the `~astropy.visualization.wcsaxes.WCSAxes` +# object on every frame of the animation via use of the ``coord_params`` dict. +# They keys of the ``coord_params`` dict are either the first half of the +# ``CTYPE`` key, the whole ``CTYPE`` key or the entries in +# ``wcs.world_axis_physical_types`` here we use the short ctype identifiers for +# the latitude and longitude axes. + +coord_params = { + "hpln": {"axislabel": "Helioprojective Longitude", "ticks": {"spacing": 10 * u.arcmin, "color": "black"}}, + "hplt": {"axislabel": "Helioprojective Latitude", "ticks": {"spacing": 10 * u.arcmin, "color": "black"}}, +} + +# We have to recreate the visualization since we displayed it earlier. +wcs_anim = ArrayAnimatorWCS(sequence_array, wcs, [0, "x", "y"], norm=norm, coord_params=coord_params).get_animation() + +plt.show() diff --git a/examples/lineanimator.py b/examples/lineanimator.py new file mode 100644 index 0000000..b7607aa --- /dev/null +++ b/examples/lineanimator.py @@ -0,0 +1,52 @@ +""" +=========================== +How to use the LineAnimator +=========================== + +This example shows off some ways in which you can use the +LineAnimator object to animate line plots. +""" +import matplotlib.pyplot as plt +import numpy as np + +from mpl_animators import LineAnimator + +############################################################################### +# Animate a 2D cube of random data as a line plot along an +# axis where the x-axis drifts with time. + +# Define some random data +data_shape0 = (10, 20) +rng = np.random.default_rng() +data0 = rng.random(data_shape0) + +############################################################################### +# Define the axis that will make up the line plot. + +plot_axis0 = 1 +slider_axis0 = 0 + +############################################################################### +# Let's customize the values along the x-axis. To do this, we must define the +# edges of the pixels/bins being plotted along the x-axis. This requires us to +# supply an array, say xdata, of length equal to data.shape[plot_axis_index]+1. +# In this example, the data has a shape of (10, 20) and let's say we are +# iterating through the 0th axis and plotting the 1st axis, +# i.e. plot_axis_index=1. Therefore we need to define an xdata array of length +# 21. +# This will give the same customized x-axis values for each frame of the +# animation. However, what if we want the x-axis values to change as we +# animate through the other dimensions of the cube? To do this we supply a +# (10, 21) xdata where each row (i.e. xdata[i, :]) gives the pixel/bin edges +# along the x-axis for the of the i-th frame of the animation. Note that this +# API extends in the same way to higher dimension. In our 2D case here though, +# we can define our non-constant x-axis values like so: + +xdata = np.tile(np.linspace(0, 100, (data_shape0[plot_axis0] + 1)), (data_shape0[slider_axis0], 1)) + +############################################################################### +# Generate animation object with variable x-axis data. + +ani = LineAnimator(data0, plot_axis_index=plot_axis0, axis_ranges=[None, xdata]).get_animation() + +plt.show() diff --git a/mpl_animators/__init__.py b/mpl_animators/__init__.py index 27b74a9..4856a15 100644 --- a/mpl_animators/__init__.py +++ b/mpl_animators/__init__.py @@ -5,3 +5,5 @@ from mpl_animators.wcs import * from .version import __version__ + +__all__ = ["ArrayAnimator", "BaseFuncAnimator", "LineAnimator", "ArrayAnimatorWCS", "ImageAnimator", "__version__"] diff --git a/mpl_animators/tests/figure_hashes_mpl_dev_ft_261_astropy_dev.json b/mpl_animators/tests/figure_hashes_mpl_dev_ft_261_astropy_dev.json index eb32bc9..c3bb7a1 100644 --- a/mpl_animators/tests/figure_hashes_mpl_dev_ft_261_astropy_dev.json +++ b/mpl_animators/tests/figure_hashes_mpl_dev_ft_261_astropy_dev.json @@ -1,16 +1,16 @@ { "mpl_animators.tests.test_basefuncanimator.test_lineanimator_figure": "6865a446680cb7088d71becd653e3c9e9e8e982d71956c95f690d52365bfe106", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_simple_plot": "1d0b9c13e72d288e09d1ab85fe3b4df38d6b349eae661c54cf32c18f0af451c6", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_clip_interval": "a78d4ca84423abcde116efeef4631cdf36d98033c71ad038363a033857743776", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_simple_plot": "7cf4b83a10ff179afd40d142860edfac340b922f42647eeae5ae9426627a6c63", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_clip_interval": "f03cf2632d825991cdfa5c5a15542fc53dc3a90d29cb21dabe858365f3f8c4b1", "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_celestial_sliders": "14fc82e6778a7725092a691f210f05420e5669099fe8cb21260fd44336e57f8e", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_update_plot": "0c4a39742b55c4c9eb1336de59891c1e1459e656992505528f245783e4c7cf12", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_transpose_update_plot": "fca79fbb72e9650df3e64beb383b68a7816cfdfd95fa632386f65b5e6d32b5e4", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_colorbar_buttons": "dc5d08188e888fb6b93843b38a1604b8847aec38dc1ba53fa8ef108da6e790d6", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_colorbar_buttons_default_labels": "3026f941a8cf87347e6793b6002dda370eae6036e13961ae7323c3a4fe60d1d1", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_extra_sliders": "fd94e25c0b6a813818c8ab1b42c6d8828e546acf30ea9bc73164e50b22f456ba", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_update_plot": "6d328b74049bb415245901d033efdc103b55b11156a94e483da3c54615057c4b", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_transpose_update_plot": "eca32f981221be9268155d12c3662891951516ea1166a9a17c239eedb4b28c92", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_colorbar_buttons": "1ac74e4adb0fca87e99dee372842302130a90b8c5d2547b4ed9e14a60c9b8e96", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_colorbar_buttons_default_labels": "7dd4f77842219e790df3297773e581382164b00f0dc72c40379f5fca33ed4c36", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_2d_extra_sliders": "67fb82ca58a293bbcebcc06432a919c1aed54fb671a0be0e9d9289645d7897c0", "mpl_animators.tests.test_wcs.test_array_animator_wcs_1d_update_plot": "0618fba2b4285904d3594b4b3d76ebd56337cf2ad4c00aa568ac111f6d3e52aa", "mpl_animators.tests.test_wcs.test_array_animator_wcs_1d_update_plot_masked": "ae635463aaa2da4d494e9e90f040d39adf452eda92ad5f1c988b5be0bf437185", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_coord_params": "6535c5d4c7cfb9699bf99c4ad1919e9854626c5633eaa4d9aa97d5003408634a", + "mpl_animators.tests.test_wcs.test_array_animator_wcs_coord_params": "ba389aca68e8cba9fcaf2e966cc909fba7b7f3e4ba4d65ad3035dae9c8056d57", "mpl_animators.tests.test_wcs.test_array_animator_wcs_coord_params_no_ticks": "536034d8e761ef5d2fdfbf8911c4ab9bbc96308328594befb44d0837eccd671e", - "mpl_animators.tests.test_wcs.test_array_animator_wcs_coord_params_grid": "5b81acf2215c9b8c1a700e2e7371f43be3177363abfe9729b6746eedd7d16686" + "mpl_animators.tests.test_wcs.test_array_animator_wcs_coord_params_grid": "6dacd902ec7ac3e9b34dac8554ef2a83a5b3a12ad5ddf63858511ac6fe02d417" } diff --git a/setup.cfg b/setup.cfg index 9d869c4..bf42064 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,7 +31,9 @@ tests = docs = sphinx sphinx-automodapi + sphinx-gallery sunpy-sphinx-theme + sunpy[all] [tool:pytest] testpaths = "mpl_animators" "docs" diff --git a/tox.ini b/tox.ini index 88bac3e..1b243bd 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ changedir = .tmp/{envname} description = run tests figure: with figure tests - oldestdeps: and with oldest supported dependancies + oldestdeps: and with oldest supported dependencies devdeps: and with development versions of matplotlib and astropy deps = pytest-xdist From d1f56406c755f9a13c1d8488133f02c7c5ee7374 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 7 May 2024 18:06:20 -0700 Subject: [PATCH 2/3] Update index.rst --- docs/index.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 48d5235..f03ef97 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,16 +1,19 @@ -Matplotlib Animators Documentation ----------------------------------- +*************************** +mpl-animators Documentation +*************************** The ``mpl_animators`` package provides a set of classes which allow the easy construction of interactive `matplotlib` widget based animations. "Out of the box" classes are provided for making line or image plots from numpy arrays, with sliders to control the animation automatically added for all dimensions not on the axes of the plot. As well as this there is a specialised `.ArrayAnimatorWCS` class which can make line or image plots for a numpy array and associated World Coordinate System (WCS) object from `astropy`. Finally, there are two base classes: `.BaseFuncAnimator` which can be extended to generate an interactive visualization from any data structure and set of functions to update the plot, and `.ArrayAnimator` which can be extended to generate any visualisation based on the axes of a numpy array. +API +=== .. automodapi:: mpl_animators .. toctree:: - :maxdepth: 2 + :hidden: generated/gallery/index api From 89f29c33fa43726271fce9bc0c951fa49b6816c8 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Tue, 7 May 2024 18:16:03 -0700 Subject: [PATCH 3/3] Update index.rst --- docs/index.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index f03ef97..0e47e7b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,11 +7,6 @@ The ``mpl_animators`` package provides a set of classes which allow the easy con As well as this there is a specialised `.ArrayAnimatorWCS` class which can make line or image plots for a numpy array and associated World Coordinate System (WCS) object from `astropy`. Finally, there are two base classes: `.BaseFuncAnimator` which can be extended to generate an interactive visualization from any data structure and set of functions to update the plot, and `.ArrayAnimator` which can be extended to generate any visualisation based on the axes of a numpy array. -API -=== - -.. automodapi:: mpl_animators - .. toctree:: :hidden: