Skip to content

Commit

Permalink
Add a convenience function for creating single-axis figures (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerkclark authored Dec 6, 2020
1 parent 935ca46 commit 5c8f754
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 5 deletions.
1 change: 1 addition & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Functions
:toctree: generated/

faceted
faceted_ax
44 changes: 40 additions & 4 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ a figure.
ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
ax.coastlines()
plt.colorbar(c, cax=cax, orientation='horizontal', label='Temperature [C]');
plt.colorbar(c, cax=cax, orientation='horizontal', label='Temperature [K]');
@savefig example_tair_single_cbar.png
fig.show()
Expand Down Expand Up @@ -260,7 +260,7 @@ We'll show an example where the rows share a colorbar.
ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
ax.coastlines()
plt.colorbar(c1, cax=cax1, label='[C]');
plt.colorbar(c1, cax=cax1, label='[K]');
for i, ax in enumerate(axes[3:], start=3):
c2 = ds.air.isel(time=i).plot(
Expand All @@ -272,7 +272,7 @@ We'll show an example where the rows share a colorbar.
ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
ax.coastlines()
plt.colorbar(c2, cax=cax2, label='[C]');
plt.colorbar(c2, cax=cax2, label='[K]');
@savefig example_tair_edge_cbar.png
fig.show()
Expand Down Expand Up @@ -303,14 +303,50 @@ specifying ``cbar_mode='each'`` as an argument in the call to :py:meth:`faceted.
ax.set_ylabel('')
ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
ax.coastlines()
cb = plt.colorbar(c, cax=cax, label='[C]')
cb = plt.colorbar(c, cax=cax, label='[K]')
cb.locator = tick_locator
cb.update_ticks()
@savefig example_tair_each_cbar.png
fig.show()
Creating a single-axis figure
-----------------------------

For convenience, :py:mod:`faceted` comes with a function built specifically for creating
single-axis figures called :py:meth:`faceted.faceted_ax`. It takes alls the same keyword
arguments as :py:meth:`faceted.faceted` but returns scalar ``Axes`` objects.

.. ipython:: python
:okwarning:
from faceted import faceted_ax
tick_locator = ticker.MaxNLocator(nbins=3)
aspect = 60. / 130.
fig, ax, cax = faceted_ax(width=8, aspect=aspect, right_pad=0.75,
cbar_mode='each',
cbar_pad=0.1, internal_pad=(0.75, 0.1),
cbar_location='right', cbar_short_side_pad=0.,
axes_kwargs={'projection': ccrs.PlateCarree()})
c = ds.air.isel(time=0).plot(
ax=ax, add_colorbar=False, transform=ccrs.PlateCarree(),
cmap='viridis', vmin=230, vmax=305)
ax.set_title('')
ax.set_xlabel('')
ax.set_ylabel('')
ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
ax.coastlines()
cb = plt.colorbar(c, cax=cax, label='[K]')
cb.locator = tick_locator
cb.update_ticks()
@savefig example_tair_each_cbar_faceted_ax.png
fig.show()
Parameter defintions
--------------------

Expand Down
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ v0.2 (2020-12-06)
``aspect`` (it would be cumbersome to have to override one of them with
``None`` in the case of creating a height-and-aspect constrained or
width-and-height constrained figure).
- A new convenience function for creating single-axis figures called
:py:meth:`faceted.faceted_ax`. It takes the same keyword arguments as the
full :py:meth:`faceted.faceted` function, except automatically returns
scalar ``Axes`` objects.

.. _whats-new.0.1:

Expand Down
2 changes: 1 addition & 1 deletion faceted/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .faceted import faceted
from .faceted import faceted, faceted_ax
from ._version import get_versions

__version__ = get_versions()["version"]
Expand Down
61 changes: 61 additions & 0 deletions faceted/faceted.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,67 @@ def faceted(
return grid.fig, grid.axes, grid.caxes


def faceted_ax(cbar_mode=None, **kwargs):
"""A convenience version of faceted for creating single-axis figures.
Exactly two of width, height, and aspect must be defined. The third is
inferred based on the other two values.
Parameters
----------
width : float
Width of figure
height : float
Height of figure
aspect : float
Aspect ratio of plots in each tile
top_pad : float
Spacing (in inches) between top of figure and axes
bottom_pad : float
Spacing (in inches) between bottom of figure and axes
left_pad : float
Spacing (in inches) between left of figure and axes
right_pad : float
Spacing (in inches) between right of figure and axes
internal_pad : float or tuple
Spacing in between panels in both the horizontal and vertical
directions (in inches); if an individual number, the spacing is the
same in the horizontal and vertical; if a tuple is specified, the left
value is the horizontal pad, and the right value is the vertical pad.
cbar_mode : {None, 'single', 'edge', 'each'}
Mode for adding colorbar(s) to figure
cbar_short_side_pad : float
Spacing between the ends of the colorbar and the edges
of the axes (in inches); controls the length of the
colorbar
cbar_pad : float
Spacing between plot axes and the colorbar axes (in inches)
cbar_size : float
Width of the colorbar in inches
cbar_location : {'top', 'bottom', 'left', 'right'}
Side of the plot axes (or figure) for the colorbar
sharex : bool or {'all', 'col', 'row', 'none'}
Share x-axis limits, ticks, and tick labels
sharey : bool or {'all', 'col', 'row', 'none'}
Share y-axis limits, ticks, and tick labels
axes_kwargs : dict
Keyword arguments to pass to Axes constructor
Returns
-------
fig, ax, cax (if cax requested)
"""
if cbar_mode is None:
fig, (ax,) = faceted(1, 1, **kwargs)
return fig, ax
elif cbar_mode == "single":
fig, (ax,), cax = faceted(1, 1, cbar_mode=cbar_mode, **kwargs)
return fig, ax, cax
elif cbar_mode in ("edge", "each"):
fig, (ax,), (cax,) = faceted(1, 1, cbar_mode=cbar_mode, **kwargs)
return fig, ax, cax


_LR = ["left", "right"]
_BT = ["bottom", "top"]

Expand Down
23 changes: 23 additions & 0 deletions faceted/tests/test_faceted.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
from collections import OrderedDict
from itertools import product

import matplotlib.axes
import matplotlib.figure
import matplotlib.pyplot as plt
import numpy as np
import pytest

from ..faceted import (
faceted,
faceted_ax,
_infer_grid_class,
HeightConstrainedAxesGrid,
HeightAndWidthConstrainedAxesGrid,
Expand Down Expand Up @@ -655,3 +658,23 @@ def test_cartopy():
for ax in axes:
assert isinstance(ax, GeoAxes)
plt.close(fig)


@pytest.mark.parametrize(
("cbar_mode", "cbar_expected"),
[(None, False), ("single", True), ("edge", True), ("each", True)],
)
def test_faceted_ax(cbar_mode, cbar_expected):
if cbar_expected:
fig, ax, cax = faceted_ax(
cbar_mode=cbar_mode, width=_WIDTH_CONSTRAINT, aspect=_ASPECT_CONSTRAINT
)
assert isinstance(fig, matplotlib.figure.Figure)
assert isinstance(ax, matplotlib.axes.Axes)
assert isinstance(cax, matplotlib.axes.Axes)
else:
fig, ax = faceted_ax(
cbar_mode=cbar_mode, width=_WIDTH_CONSTRAINT, aspect=_ASPECT_CONSTRAINT
)
assert isinstance(fig, matplotlib.figure.Figure)
assert isinstance(ax, matplotlib.axes.Axes)

0 comments on commit 5c8f754

Please sign in to comment.