Skip to content

Commit

Permalink
docs: improved gwpy.plot docs
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanmmacleod committed Jun 14, 2018
1 parent 19ee6c3 commit e643385
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 4 deletions.
88 changes: 88 additions & 0 deletions docs/plot/colorbars.rst
@@ -0,0 +1,88 @@
.. currentmodule:: gwpy.plot

.. _gwpy-plot-colorbars:

#########
Colorbars
#########

======================================
Modifications to the built-in colorbar
======================================

GWpy extends the built-in :mod:`matplotlib`
:meth:`~matplotlib.figure.Figure.colorbar` functionality to improve the
defaults in a number of ways:

- callable from the :class:`~matplotlib.figure.Figure`, or directly from the
relevant :class:`~matplotlib.axes.Axes`
- don't resize the anchor :class:`~matplotlib.axes.Axes`
- simpler specification of log-norm colors
- better log-scale ticks

See the following example for a summary of the improvements:

.. plot::
:include-source:

import numpy
data = numpy.random.rand(100, 100)
from gwpy.timeseries import TimeSeries
from matplotlib import pyplot
fig, axes = pyplot.subplots(nrows=3, figsize=(6.4, 8))
for ax in axes: # plot the same data on each
ax.imshow(data)
fig.colorbar(axes[1].images[0], ax=axes[1]) # matplotlib default
axes[2].colorbar() # gwpy colorbar
pyplot.show()

============================
Logarithmic colorbar scaling
============================

With GWpy, getting logarithmic scaling on a colorbar is as simple as
specifying, ``norm='log'``:

.. plot::
:include-source:

from gwpy.timeseries import TimeSeries
data = TimeSeries.fetch_open_data('L1', 1187008866, 1187008898, tag='C00')
specgram = data.spectrogram2(fftlength=.5, overlap=.25,
window='hann') ** (1/2.)
plot = specgram.plot(yscale='log', ylim=(30, 1400))
plot.colorbar(norm='log', clim=(1e-24, 1e-21), label='Strain ASD')
plot.show()

.. note::

Log-scales can also be specified using :class:`~matplotlib.colors.LogNorm`

===============
Another example
===============

.. plot::
:include-source:

# load data
from gwpy.timeseries import TimeSeries
raw = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)

# calculate filtered timeseries, and Q-transform spectrogram
data = raw.bandpass(50, 300).notch(60).crop(1126259446+1)
qtrans = raw.q_transform()

# plot
from matplotlib import pyplot
plot, axes = pyplot.subplots(nrows=2, sharex=True, figsize=(8, 6))
tax, qax = axes
tax.plot(data, color='gwpy:ligo-livingston')
qax.imshow(qtrans)
tax.set_xlabel('')
tax.set_xscale('auto-gps')
tax.set_xlim(1126259462.2, 1126259462.5)
tax.set_ylabel('Strain amplitude')
qax.set_yscale('log')
qax.set_ylabel('Frequency [Hz]')
qax.colorbar(clim=(0, 35), label='Normalised energy')
97 changes: 97 additions & 0 deletions docs/plot/gps.rst
@@ -0,0 +1,97 @@
.. currentmodule:: gwpy.plot.gps

.. _gwpy-plot-gps:

########################
Plotting GPS time scales
########################

As we have seen, the default :mod:`matplotlib` representation of GPS scales
is not great, given the large zero-offset typically seen with 21st century GPS
times.

To improve displays of data with GPS timestamps, GWpy provides a number of
custom :mod:`scales <mtplotlib.scale>`.
Each scale uses an ``epoch`` and a ``unit`` to recentre and format the GPS
axis in a way that clearly displays the data, without large offsets or
multipliers.

==============
``'auto-gps'``
==============

The ``'auto-gps'`` scale (the default for most GPS-based plots) automatically
calculates an ``epoch`` and ``unit`` each time the figure is drawn, based on
the current view limits and data limits:

.. plot::
:include-source:
:context: reset

>>> from gwpy.timeseries import TimeSeries
>>> raw = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)
>>> data = raw.bandpass(50, 300).notch(60).crop(1126259446+1)
>>> plot = data.plot(xscale='auto-gps')
>>> plot.show()

Here the default epoch is just the epoch for the given `TimeSeries`, and the
unit has been automatically chosen as ``'seconds'``.
However, if we zoom the axes to a tiny fraction of a second, the ``unit`` is
automatically reselected to something more sensible:

.. plot::
:include-source:
:context:

>>> ax = plot.gca()
>>> ax.set_xlim(1126259462.415, 1126259462.425)
>>> plot.refresh()

===========
Fixed units
===========

A GPS axis can be fixed to a specific unit via the
:meth:`~matplotlib.axes.Axes.set_xscale` (or
:meth:`~matplotlib.axes.Axes.set_yscale`) method of the relevant axis.

The available units are

- ``'nanoseconds'``
- ``'microseconds'``
- ``'milliseconds'``
- ``'seconds'``
- ``'minutes'``
- ``'hours'``
- ``'days'``
- ``'weeks'``
- ``'years'``

.. plot::
:include-source:
:context:

>>> ax.set_xscale('seconds')
>>> plot.refresh()

===========
Fixed epoch
===========

A GPS axis can be fixed to a specific epoch via the same
:meth:`~matplotlib.axes.Axes.set_xscale` (or
:meth:`~matplotlib.axes.Axes.set_yscale`) method of the relevant axis, or
via the special :meth:`~gwpy.plot.Axes.set_epoch` method:

.. plot::
:include-source:
:context:

>>> ax.set_xlim(1126259462.2, 1126259462.6)
>>> ax.set_epoch(1126259462.42)
>>> plot.refresh()

.. note::

A fixed epoch can be used with ``'auto-gps'`` as well as any of the
fixed units.
72 changes: 68 additions & 4 deletions docs/plot/index.rst
Expand Up @@ -6,12 +6,16 @@
Plotting in GWpy (:mod:`gwpy.plot`)
###################################

==============
Basic plotting
==============

The :mod:`gwpy.plot` module provides integrated extensions to the fantastic
data visualisation tools provided by |matplotlib|_.

=============================================
---------------------------------------------
Basic plotting with :mod:`~matplotlib.pyplot`
=============================================
---------------------------------------------

Each of the data representations provided by `gwpy` can be directly passed
to the standard methods available in `~matplotlib.pyplot`:
Expand All @@ -25,9 +29,9 @@ to the standard methods available in `~matplotlib.pyplot`:
>>> plt.plot(data)
>>> plt.show()

==============================
------------------------------
:meth:`.plot` instance methods
==============================
------------------------------

Each of the data representations provided by `gwpy` also come with a
:meth:`.plot` method that provides a figure with improved defaults tailored
Expand All @@ -40,3 +44,63 @@ to those data:
>>> data = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)
>>> plot = data.plot()
>>> plot.show()

The :meth:`.plot` methods accept any keywords that can be used to create the
:class:`~matplotlib.figure.Figure` and the :class:`~matplotlib.axes.Axes`,
and to draw the element itself, e.g:

.. plot::
:include-source:

>>> from gwpy.timeseries import TimeSeries
>>> data = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)
>>> plot = data.plot(figsize=(8, 4), ylabel='Strain',
... color='gwpy:ligo-livingston')
>>> plot.show()

----------------
Multi-data plots
----------------

GWpy enables trivial generation of plots with multiple datasets.
The :class:`~gwpy.plot.Plot` constructor will accept an arbitrary
collection of data objects and will build a figure with the required geometry
automatically.
By default, a flat set of objects are shown on the same axes:

.. plot::
:include-source:
:context: reset

>>> from gwpy.timeseries import TimeSeries
>>> hdata = TimeSeries.fetch_open_data('H1', 1126259446, 1126259478)
>>> ldata = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)
>>> from gwpy.plot import Plot
>>> plot = Plot(hdata, ldata, figsize=(12, 4))
>>> plot.show()

However, `separate=True` can be given to show each dataset on a separate
`~gwpy.plot.Axes`:

.. plot::
:include-source:
:context:

plot = Plot(hdata, ldata, figsize=(12, 6), separate=True, sharex=True)
plot.show()

.. warning::

The `Plot` constructor can only handle one plotting method at any time
(e.g. ``ax.plot()``, ``ax.imshow()``), so you can't create plots with
a line and an image using this call,
for example.

==================
Plot customisation
==================

.. toctree::

gps
colorbars

0 comments on commit e643385

Please sign in to comment.