Skip to content

Commit

Permalink
testing all plotting funcs take axes arg
Browse files Browse the repository at this point in the history
  • Loading branch information
Clark Fitzgerald committed Jul 8, 2015
1 parent ad4ec31 commit 13b5a1b
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 97 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ nosetests.xml
.project
.pydevproject

# PyCharm
# PyCharm and Vim
.idea
*.swp

# xray specific
doc/_build
doc/generated
doc/_static/*.png
xray/version.py
3 changes: 3 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,6 @@ Plotting

DataArray.plot
DataArray.plot_contourf
DataArray.plot_hist
DataArray.plot_imshow
DataArray.plot_line
118 changes: 52 additions & 66 deletions doc/plotting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,16 @@ Introduction

Xray plotting functionality is a thin wrapper around the popular
`matplotlib <http://matplotlib.org/>`__ library.
The metadata from :py:class:`xray.DataArray` objects are used to add
informative labels.
We copy matplotlib syntax and function names as much as possible.
Metadata from :py:class:`xray.DataArray` objects are used to add
informative labels. Matplotlib is required for plotting with xray.
Matplotlib syntax and function names were copied as much as possible, which
makes for an easy transition between the two.

Hence matplotlib is a
dependency for plotting.

xray tries to create reasonable labeled plots based on metadata and the array
dimensions.

But it's not always obvious what to plot. A wise man once said:
'In the face of ambiguity, refuse the temptation to guess.'
So don't be scared if you see some ``ValueError``'s when
trying to plot, it just means you may need to get the data into a form
where plotting is more natural.

To begin, import numpy, pandas and xray:
Begin by importing the necessary modules:

.. ipython:: python
import numpy as np
import pandas as pd
import xray
import matplotlib.pyplot as plt
Expand All @@ -37,41 +25,60 @@ The following line is not necessary, but it makes for a nice style.
plt.style.use('ggplot')
1 Dimension
-----------
One Dimension
-------------

Here is a simple example of plotting.
Xray uses the coordinate name to label the x axis.
Here is a simple example of plotting.
Xray uses the coordinate name to label the x axis:

.. ipython:: python
x = np.linspace(0, 2*np.pi)
sinpts = xray.DataArray(np.sin(x), {'t': x}, name='sin(t)')
t = np.linspace(0, 2*np.pi)
sinpts = xray.DataArray(np.sin(t), {'t': t}, name='sin(t)')
@savefig plotting_example_sin.png width=4in
sinpts.plot()
Additional Arguments
~~~~~~~~~~~~~~~~~~~~~

Histogram
~~~~~~~~~

A histogram of the same data.
Additional arguments are passed directly to the matplotlib function which
does the work. For example,
for a plot with blue triangles marking the data points one can use a
matplotlib format string:

.. ipython:: python
@savefig plotting_example_hist.png width=4in
sinpts.plot_hist()
@savefig plotting_example_sin2.png width=4in
sinpts.plot('b-^')
Keyword arguments work the same way.

Additional arguments are passed directly to ``matplotlib.pyplot.hist``,
which handles the plotting.
Adding to Existing Axis
~~~~~~~~~~~~~~~~~~~~~~~

To add the plot to an existing axis pass in the axis as a keyword argument
``ax``. This works for all xray plotting methods.
In this example ``axes`` is a tuple consisting of the left and right
axes created by ``plt.subplots``.

.. ipython:: python
@savefig plotting_example_hist2.png width=4in
sinpts.plot_hist(bins=3)
fig, axes = plt.subplots(ncols=2)
2 Dimensions
------------
axes
sinpts.plot(ax=axes[0])
sinpts.plot_hist(ax=axes[1])
@savefig plotting_example_existing_axes.png width=6in
plt.show()
Instead of using the default :py:meth:`xray.DataArray.plot` we see a
histogram created by :py:meth:`xray.DataArray.plot_hist`.

Two Dimensions
--------------

For these examples we generate two dimensional data by computing the distance
from a 2d grid point to the origin
Expand All @@ -88,10 +95,7 @@ from a 2d grid point to the origin
distance
The default :py:meth:`xray.DataArray.plot` sees that the data is 2 dimenstional
and calls :py:meth:`xray.DataArray.plot_imshow`. This was chosen as a
default
since it does not perform any smoothing or interpolation; it just shows the
raw data.
and calls :py:meth:`xray.DataArray.plot_imshow`.

.. ipython:: python
Expand Down Expand Up @@ -131,37 +135,19 @@ Visualization is
TODO- This is the same plot as ``imshow``.

Multivariate Normal Density
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Consider the density for a two dimensional normal distribution
evaluated on a square grid::
# TODO this requires scipy as a dependency for docs to build

from scipy.stats import multivariate_normal

g = np.linspace(-3, 3)
xy = np.dstack(np.meshgrid(g, g))

# 2d Normal distribution centered at 1, 0
rv = multivariate_normal(mean=(1, 0))

normal = xray.DataArray(rv.pdf(xy), {'x': g, 'y': g})

# TODO- use xray method
@savefig plotting_example_2dnormal.png
plt.contourf(normal.x, normal.y, normal.data)
Details
-------

There are two ways to use the xray plotting functionality:

Rules
-----
1. Use the ``plot`` convenience methods of :py:class:`xray.DataArray`
2. Directly from the xray plotting submodule::

The following is a more complete description of how xray determines what
and how to plot.
import xray.plotting as xplt

The method :py:meth:`xray.DataArray.plot` dispatches to an appropriate
plotting function based on the dimensions of the ``DataArray``.
The convenience method :py:meth:`xray.DataArray.plot` dispatches to an appropriate
plotting function based on the dimensions of the ``DataArray``. This table
describes what gets plotted:

=============== ======================================
Dimensions Plotting function
Expand Down
3 changes: 3 additions & 0 deletions xray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,9 @@ def func(self, other):


# Add plotting methods
# Alternatively these could be added using a Mixin
# Wondering if it's better to only expose plot and plot_hist here, since
# those always work.

DataArray.plot = plotting.plot
DataArray.plot_line = plotting.plot_line
Expand Down
87 changes: 65 additions & 22 deletions xray/core/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@


# TODO - Is there a better way to import matplotlib in the function?
# Other piece of duplicated logic is the checking for axes.
# Decorators don't preserve the argument names
# But if all the plotting methods have same signature...

Expand All @@ -15,16 +16,26 @@ class FacetGrid():
pass


def plot(darray, ax=None, *args, **kwargs):
def plot(darray, *args, **kwargs):
"""
Default plot of DataArray using matplotlib / pylab.
Calls a plotting function based on the dimensions of
the array:
=============== ======================================
Dimensions Plotting function
--------------- --------------------------------------
1 :py:meth:`xray.DataArray.plot_line`
2 :py:meth:`xray.DataArray.plot_imshow`
Anything else :py:meth:`xray.DataArray.plot_hist`
=============== ======================================
Parameters
----------
darray : DataArray
Must be 1 dimensional
ax : matplotlib axes object
If not passed, uses plt.gca()
If not passed, uses the current axis
args, kwargs
Additional arguments to matplotlib
"""
Expand All @@ -36,19 +47,27 @@ def plot(darray, ax=None, *args, **kwargs):
else:
plotfunc = plot_hist

return plotfunc(darray, ax, *args, **kwargs)
return plotfunc(darray, *args, **kwargs)


def plot_line(darray, ax=None, *args, **kwargs):
def plot_line(darray, *args, **kwargs):
"""
Line plot of DataArray using matplotlib / pylab.
Line plot of 1 dimensional darray index against values
Wraps matplotlib.pyplot.plot
Parameters
----------
darray : DataArray
Must be 1 dimensional
ax : matplotlib axes object
If not passed, uses plt.gca()
If not passed, uses the current axis
args, kwargs
Additional arguments to matplotlib.pyplot.plot
Examples
--------
"""
import matplotlib.pyplot as plt

Expand All @@ -57,7 +76,10 @@ def plot_line(darray, ax=None, *args, **kwargs):
raise ValueError('Line plots are for 1 dimensional DataArrays. '
'Passed DataArray has {} dimensions'.format(ndims))

if ax is None:
# Was an axis passed in?
try:
ax = kwargs.pop('ax')
except KeyError:
ax = plt.gca()

xlabel, x = list(darray.indexes.items())[0]
Expand All @@ -70,25 +92,33 @@ def plot_line(darray, ax=None, *args, **kwargs):
return ax


def plot_imshow(darray, ax=None, add_colorbar=True, *args, **kwargs):
def plot_imshow(darray, add_colorbar=True, *args, **kwargs):
"""
Image plot of 2d DataArray using matplotlib / pylab.
Wraps matplotlib.pyplot.imshow
Parameters
----------
darray : DataArray
Must be 1 dimensional
Must be 2 dimensional
ax : matplotlib axes object
If not passed, uses plt.gca()
If not passed, uses the current axis
args, kwargs
Additional arguments to matplotlib.pyplot.imshow
add_colorbar : Boolean
Adds colorbar to axis
args, kwargs
Additional arguments to matplotlib
Examples
--------
"""
import matplotlib.pyplot as plt

if ax is None:
# Was an axis passed in?
try:
ax = kwargs.pop('ax')
except KeyError:
ax = plt.gca()

# Seems strange that ylab comes first
Expand Down Expand Up @@ -117,13 +147,16 @@ def plot_imshow(darray, ax=None, add_colorbar=True, *args, **kwargs):


# TODO - Could refactor this to avoid duplicating plot_image logic above
def plot_contourf(darray, ax=None, add_colorbar=True, *args, **kwargs):
def plot_contourf(darray, add_colorbar=True, *args, **kwargs):
"""
Contour plot
"""
import matplotlib.pyplot as plt

if ax is None:
# Was an axis passed in?
try:
ax = kwargs.pop('ax')
except KeyError:
ax = plt.gca()

# Seems strange that ylab comes first
Expand All @@ -150,22 +183,32 @@ def plot_contourf(darray, ax=None, add_colorbar=True, *args, **kwargs):
return ax


def plot_hist(darray, ax=None, *args, **kwargs):
def plot_hist(darray, *args, **kwargs):
"""
Histogram of DataArray using matplotlib / pylab.
Uses numpy.ravel to first flatten the array.
Plots N dimensional arrays by first flattening the array.
Wraps matplotlib.pyplot.hist
Parameters
----------
darray : DataArray
Can be any dimensions
Must be 2 dimensional
ax : matplotlib axes object
If not passed, uses plt.gca()
If not passed, uses the current axis
args, kwargs
Additional arguments to matplotlib.pyplot.imshow
Examples
--------
"""
import matplotlib.pyplot as plt

if ax is None:
# Was an axis passed in?
try:
ax = kwargs.pop('ax')
except KeyError:
ax = plt.gca()

ax.hist(np.ravel(darray), *args, **kwargs)
Expand Down
Loading

0 comments on commit 13b5a1b

Please sign in to comment.