Skip to content

Commit

Permalink
Merge pull request #25 from ConorMacBride/gallery
Browse files Browse the repository at this point in the history
Add Example Gallery
  • Loading branch information
ConorMacBride authored Apr 14, 2021
2 parents 72014db + e90a7f7 commit 741b881
Show file tree
Hide file tree
Showing 26 changed files with 685 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ MANIFEST
# Sphinx
docs/api
docs/_build
docs/gallery
docs/gen_modules

# Eclipse editor project files
.project
Expand Down
6 changes: 3 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ stages:
- linux: py38-oldestdeps
libraries: {}

- linux: build_docs
posargs: " "
pytest: false
# - linux: build_docs
# posargs: " "
# pytest: false

- stage: FigureTests
displayName: Figure Tests
Expand Down
18 changes: 18 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# -- General configuration ---------------------------------------------------

import sphinx_rtd_theme
from sphinx_gallery.sorting import FileNameSortKey

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
Expand All @@ -47,6 +48,7 @@
'sphinx.ext.napoleon',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
'sphinx_gallery.gen_gallery',
]
numpydoc_show_class_members = False
nbsphinx_execute = 'never'
Expand All @@ -69,6 +71,22 @@
"sklearn": ('https://scikit-learn.org/stable', None),
}

# sphinx-gallery configuration
sphinx_gallery_conf = {
# path to your example scripts
'examples_dirs': ['../examples/gallery'],
# path to where to save gallery generated output
'gallery_dirs': ['gallery'],
# specify that examples should be ordered according to filename
'within_subsection_order': FileNameSortKey,
# directory where function/class granular galleries are stored
'backreferences_dir': 'gen_modules/backreferences',
# Modules for which function/class level galleries are created.
'doc_module': ('mcalf',),
# don't print e.g. sphinx_gallery_thumbnail_number = 2
'remove_config_comments': True,
}

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ a :any:`Module Index <modindex>` are available.
:caption: Contents:

guide/index
gallery/index
code_ref/index
code_of_conduct
license
2 changes: 2 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ sphinx==3.1.2
ipykernel
nbsphinx==0.7.1
sphinx-rtd-theme==0.5.0
sphinx-gallery
pytest
4 changes: 4 additions & 0 deletions examples/gallery/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Example Gallery
***************

Here are a collection of examples on how this package can be used.
4 changes: 4 additions & 0 deletions examples/gallery/visualisation/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Visualisation
=============

Below are examples of plots produced using functions within the visualisation module:
94 changes: 94 additions & 0 deletions examples/gallery/visualisation/plot_bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
Plot a bar chart of classifications
===================================
This is an example showing how to produce a bar chart showing the percentage
abundance of each classification in a 2D or 3D array of classifications.
"""

#%%
# First we shall create a random 3D grid of classifications that can be plotted.
# Usually you would use a method such as
# :meth:`mcalf.models.ModelBase.classify_spectra`
# to classify an array of spectra.

from mcalf.tests.helpers import class_map as c

t = 3 # Three images
x = 50 # 50 coordinates along x-axis
y = 20 # 20 coordinates along y-axis
n = 5 # Possible classifications [0, 1, 2, 3, 4]

class_map = c(t, x, y, n) # 3D array of classifications (t, y, x)

#%%
# Next, we shall import :func:`mcalf.visualisation.bar`.

from mcalf.visualisation import bar

#%%
# We can now simply plot the 3D array.
# By default, the first dimension of a 3D array will be averaged to
# produce a time average, selecting the most common classification
# at each (x, y) coordinate.
# This means the percentage abundances will correspond to the
# most common classification at each coordinate.

bar(class_map)

#%%
# Instead, the percentage abundances can be determined for the whole
# 3D array of classifications by setting ``reduce=True``.
# This skips the averaging process.

bar(class_map, reduce=False)

#%%
# Alternatively, a 2D array can be passed to the function.
# If a 2D array is passed, no averaging is needed, and
# the ``reduce`` parameter is ignored.

#%%
# A narrower range of classifications to be plotted can be
# requested with the ``vmin`` and ``vmax`` parameters.
# To show bars for only classifcations 1, 2, and 3,

bar(class_map, vmin=1, vmax=3)

#%%
# An alternative set of colours can be requested.
# Passing a name of a matplotlib colormap to the
# ``style`` parameter will produce a corresponding
# list of colours for each of the bars.
# For advanced use, explore the ``cmap`` parameter.

bar(class_map, style='viridis')

#%%
# The bar function integrates well with matplotlib, allowing
# extensive flexibility.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, constrained_layout=True)

bar(class_map, vmax=2, style='viridis', ax=ax[0])
bar(class_map, vmin=3, style='cividis', ax=ax[1])

ax[0].set_title('first 3')
ax[1].set_title('last 2')

ax[1].set_ylabel('')

plt.show()

#%%
# Note that ``vmin`` and ``vmax`` are applied before the
# ``reduce`` value is applied. So setting these ranges
# can change the calculated abundances for other
# classifications if ``class_map`` is 3D and
# ``reduce=True``.
#
# The bars do not add up to 100% as a bar for
# negative, invalid classifications (and therefore
# classifications out of the ``vmin`` and ``vmax``
# range) is not shown.
83 changes: 83 additions & 0 deletions examples/gallery/visualisation/plot_multiple_classifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
Combine multiple classification plots
=====================================
This is an example showing how to use multiple classification
plotting functions in a single figure.
"""

#%%
# First we shall create a random 3D grid of classifications that can be plotted.
# Usually you would use a method such as
# :meth:`mcalf.models.ModelBase.classify_spectra`
# to classify an array of spectra.

from mcalf.tests.helpers import class_map as c

t = 1 # One image
x = 20 # 20 coordinates along x-axis
y = 20 # 20 coordinates along y-axis
n = 3 # Possible classifications [0, 1, 2]

class_map = c(t, x, y, n) # 3D array of classifications (t, y, x)

#%%
# Next we shall create a random array of spectra each labelled
# with a random classifications.
# Usually you would provide your own set of hand labelled spectra
# taken from spectral imaging observations of the Sun.
# Or you could provide a set of spectra labelled by the classifier.

from mcalf.tests.visualisation.test_classifications import spectra as s

n = 400 # 200 spectra
w = 20 # 20 wavelength points for each spectrum
low, high = 0, 3 # Possible classifications [0, 1, 2]

# 2D array of spectra (n, w), 1D array of labels (n,)
spectra, labels = s(n, w, low, high)

#%%
# If a GridSpec returned by the plot_classification function has
# free space, a new axes can be added to the returned GridSpec.
# We can then request plot_class_map to plot onto this
# new axes.
# The colorbar axes can be set to ``fig.axes`` such that
# the colorbar takes the full height of the figure, as
# in this case, its colours are the same as the line plots.

import matplotlib.pyplot as plt
from mcalf.visualisation import plot_classifications, plot_class_map

fig = plt.figure(constrained_layout=True)

gs = plot_classifications(spectra, labels, nrows=2, show_labels=False)

ax = fig.add_subplot(gs[-1])
plot_class_map(class_map, ax=ax, colorbar_settings={
'ax': fig.axes,
'label': 'classification',
})

#%%
# The function :func:`mcalf.visualisation.init_class_data`` is
# intended to be an internal function for generating data that
# is common to multiple plotting functions. However, it may be
# used externally if necessary.

from mcalf.visualisation import init_class_data, bar

fig, ax = plt.subplots(1, 2, constrained_layout=True)

data = init_class_data(class_map, resolution=(0.25, 0.25), ax=ax[1])

bar(data=data, ax=ax[0])
plot_class_map(data=data, ax=ax[1], show_colorbar=False)

#%%
# The following example should be equivalent to the example above,

fig, ax = plt.subplots(1, 2, constrained_layout=True)

bar(class_map, ax=ax[0])
plot_class_map(class_map, ax=ax[1], show_colorbar=False,
resolution=(0.25, 0.25))
80 changes: 80 additions & 0 deletions examples/gallery/visualisation/plot_plot_class_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Plot a map of classifications
=============================
This is an example showing how to produce a map showing the spatial
distribution of spectral classifications in a 2D region of the Sun.
"""

#%%
# First we shall create a random 3D grid of classifications that can be plotted.
# Usually you would use a method such as
# :meth:`mcalf.models.ModelBase.classify_spectra`
# to classify an array of spectra.

from mcalf.tests.helpers import class_map as c

t = 3 # Three images
x = 50 # 50 coordinates along x-axis
y = 20 # 20 coordinates along y-axis
n = 5 # Possible classifications [0, 1, 2, 3, 4]

class_map = c(t, x, y, n) # 3D array of classifications (t, y, x)

#%%
# Next, we shall import :func:`mcalf.visualisation.plot_class_map`.

from mcalf.visualisation import plot_class_map

#%%
# We can now simply plot the 3D array.
# By default, the first dimension of a 3D array will be averaged to
# produce a time average, selecting the most common classification
# at each (x, y) coordinate.

plot_class_map(class_map)

#%%
# A spatial resolution with units can be specified for each axis.

import astropy.units as u

plot_class_map(class_map, resolution=(0.75 * u.km, 1.75 * u.Mm),
offset=(-25, -10),
dimension=('x distance', 'y distance'))

#%%
# A narrower range of classifications to be plotted can be
# requested with the ``vmin`` and ``vmax`` parameters.
# Classifications outside of the range will appear as grey,
# the same as pixels with a negative, unassigned classification.

plot_class_map(class_map, vmin=1, vmax=3)

#%%
# An alternative set of colours can be requested.
# Passing a name of a matplotlib colormap to the
# ``style`` parameter will produce a corresponding
# list of colours for each of the classifications.
# For advanced use, explore the ``cmap`` parameter.

plot_class_map(class_map, style='viridis')

#%%
# The plot_class_map function integrates well with
# matplotlib, allowing extensive flexibility.
# This example also shows how you can plot a 2D
# ``class_map`` and skip the averaging.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(2, constrained_layout=True)

plot_class_map(class_map[0], style='viridis', ax=ax[0],
show_colorbar=False)
plot_class_map(class_map[1], style='viridis', ax=ax[1],
colorbar_settings={'ax': ax, 'label': 'classification'})

ax[0].set_title('time $t=0$')
ax[1].set_title('time $t=1$')

plt.show()
54 changes: 54 additions & 0 deletions examples/gallery/visualisation/plot_plot_classifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Plot a grid of spectra grouped by classification
================================================
This is an example showing how to produce a grid of line plots of
an array of spectra labelled with a classification.
"""

#%%
# First we shall create a random array of spectra each labelled
# with a random classifications.
# Usually you would provide your own set of hand labelled spectra
# taken from spectral imaging observations of the Sun.

from mcalf.tests.visualisation.test_classifications import spectra as s

n = 200 # 200 spectra
w = 20 # 20 wavelength points for each spectrum
low, high = 1, 5 # Possible classifications [1, 2, 3, 4]

# 2D array of spectra (n, w), 1D array of labels (n,)
spectra, labels = s(n, w, low, high)

#%%
# Next, we shall import :func:`mcalf.visualisation.plot_classifications`.

from mcalf.visualisation import plot_classifications

#%%
# We can now plot a simple grid of the spectra grouped by their
# classification. By default, a maximum of 20 spectra are plotted
# for each classification. The first 20 spectra are selected.

plot_classifications(spectra, labels)

#%%
# A specific number of rows or columns can be requested,

plot_classifications(spectra, labels, ncols=1)

#%%
# The plot settings can be adjusted,

plot_classifications(spectra, labels, show_labels=False, nlines=5,
style='viridis', plot_settings={'ls': '--', 'marker': 'x'})

#%%
# By default, the y-axis goes from 0 to 1. This is because
# labelled training data will typically be rescaled
# between 0 and 1. However, if a particular classification
# has spectra that are not within 0 and 1, the y-axis limits
# are determined by matplotlib.

spectra[labels == 2] += 0.5
plot_classifications(spectra, labels)
Loading

0 comments on commit 741b881

Please sign in to comment.