Using faceted
faceted.faceted()
is quite flexible. Here are a couple of examples
illustrating the different features. Using it in many ways resembles using
matplotlib.pyplot.subplots()
.
In [1]: import matplotlib.pyplot as plt
In [2]: import xarray as xr
In [3]: from matplotlib import ticker
In [4]: from faceted import faceted
In [5]: tick_locator = ticker.MaxNLocator(nbins=3)
In [6]: ds = xr.tutorial.load_dataset('rasm').isel(x=slice(30, 37), y=-1,
...: time=slice(0, 11))
...:
In [7]: temp = ds.Tair
In [8]: fig, axes = faceted(2, 3, width=8, aspect=0.618)
In [9]: for i, ax in enumerate(axes):
...: temp.isel(x=i).plot(ax=ax, marker='o', ls='none')
...: ax.set_title('{:0.2f}'.format(temp.xc.isel(x=i).item()))
...: ax.set_xlabel('Time')
...: ax.set_ylabel('Temperature [C]')
...: ax.tick_params(axis='x', labelrotation=45)
...:
In [10]: fig.show()
Padding options
We’ll notice that there are some padding issues in the above plot. We can add
some padding using the outer and inner padding arguments. Specifying an
internal_pad
as a tuple allows us to prescribe different horizontal and
vertical pad values; specifying a left_pad
and bottom_pad
allows us to
make room for the outer axes labels, while maintaining our prescribed figure
width.
In [11]: fig, axes = faceted(2, 3, width=8, aspect=0.618, left_pad=0.75, bottom_pad=0.9,
....: internal_pad=(0.33, 0.66))
....:
In [12]: for i, ax in enumerate(axes):
....: temp.isel(x=i).plot(ax=ax, marker='o', ls='none')
....: ax.set_title('{:0.2f}'.format(temp.xc.isel(x=i).item()))
....: ax.set_xlabel('Time')
....: ax.set_ylabel('Temperature [C]')
....: ax.tick_params(axis='x', labelrotation=45)
....:
In [13]: fig.show()
Types of constrained figures
faceted.faceted()
supports multiple kinds of constrained figures. We simply need
to provide exactly two of the width
, height
, and aspect
arguments and faceted.faceted()
does the rest.
Width-and-aspect constrained figure
This is what we’ve shown already, but for completeness we’ll repeat the example again here.
In [24]: import matplotlib.pyplot as plt
In [25]: import xarray as xr
In [26]: from matplotlib import ticker
In [27]: from faceted import faceted
In [28]: tick_locator = ticker.MaxNLocator(nbins=3)
In [29]: ds = xr.tutorial.load_dataset('rasm').isel(x=slice(30, 37), y=-1,
....: time=slice(0, 11))
....:
In [30]: temp = ds.Tair
In [31]: fig, axes = faceted(2, 3, width=8, aspect=0.618, bottom_pad=0.9, left_pad=0.75,
....: internal_pad=(0.33, 0.66), sharey='row')
....:
In [32]: for i, ax in enumerate(axes):
....: temp.isel(x=i).plot(ax=ax, marker='o', ls='none')
....: ax.set_title('{:0.2f}'.format(temp.xc.isel(x=i).item()))
....: ax.set_xlabel('Time')
....: ax.set_ylabel('Temperature [C]')
....: ax.tick_params(axis='x', labelrotation=45)
....:
In [33]: fig.show()
Height-and-aspect constrained figure
In [34]: import matplotlib.pyplot as plt
In [35]: import xarray as xr
In [36]: from matplotlib import ticker
In [37]: from faceted import faceted
In [38]: tick_locator = ticker.MaxNLocator(nbins=3)
In [39]: ds = xr.tutorial.load_dataset('rasm').isel(x=slice(30, 37), y=-1,
....: time=slice(0, 11))
....:
In [40]: temp = ds.Tair
In [41]: fig, axes = faceted(2, 3, height=8., aspect=0.618, bottom_pad=0.9, left_pad=0.75,
....: internal_pad=(0.33, 0.66), sharey='row')
....:
In [42]: for i, ax in enumerate(axes):
....: temp.isel(x=i).plot(ax=ax, marker='o', ls='none')
....: ax.set_title('{:0.2f}'.format(temp.xc.isel(x=i).item()))
....: ax.set_xlabel('Time')
....: ax.set_ylabel('Temperature [C]')
....: ax.tick_params(axis='x', labelrotation=45)
....:
In [43]: fig.show()
Width-and-height constrained figure
In [44]: import matplotlib.pyplot as plt
In [45]: import xarray as xr
In [46]: from matplotlib import ticker
In [47]: from faceted import faceted
In [48]: tick_locator = ticker.MaxNLocator(nbins=3)
In [49]: ds = xr.tutorial.load_dataset('rasm').isel(x=slice(30, 37), y=-1,
....: time=slice(0, 11))
....:
In [50]: temp = ds.Tair
In [51]: fig, axes = faceted(2, 3, width=8, height=6., bottom_pad=0.9, left_pad=0.75,
....: internal_pad=(0.33, 0.66), sharey='row')
....:
In [52]: for i, ax in enumerate(axes):
....: temp.isel(x=i).plot(ax=ax, marker='o', ls='none')
....: ax.set_title('{:0.2f}'.format(temp.xc.isel(x=i).item()))
....: ax.set_xlabel('Time')
....: ax.set_ylabel('Temperature [C]')
....: ax.tick_params(axis='x', labelrotation=45)
....:
In [53]: fig.show()
Colorbar modes and locations
Let’s say we are plotting 2D data in the form of pcolormesh plots that require
a colorbar. faceted.faceted()
comes with a number of options for placing and sizing
colorbars in a paneled figure. We can add a colorbar to a figure by modifying
the cbar_mode
argument; by default it is set to None
, meaning no
colorbar, as in the plots above. For all of the examples here, we’ll just plot
a time series of maps. Since the xarray tutorial data is geographic in nature,
we’ll also use this opportunity to show how to use cartopy
with
faceted.faceted()
.
Single colorbar
A single colorbar is useful when we use the same color scale for all panels of a figure.
In [54]: import cartopy.crs as ccrs
In [55]: ds = xr.tutorial.load_dataset('air_temperature')
In [56]: aspect = 60. / 130.
In [57]: fig, axes, cax = faceted(2, 3, width=8, aspect=aspect,
....: bottom_pad=0.75, cbar_mode='single',
....: cbar_pad=0.1, internal_pad=0.1,
....: cbar_location='bottom', cbar_short_side_pad=0.,
....: axes_kwargs={'projection': ccrs.PlateCarree()})
....:
In [58]: for i, ax in enumerate(axes):
....: c = ds.air.isel(time=i).plot(
....: ax=ax, add_colorbar=False, transform=ccrs.PlateCarree(),
....: 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()
....:
In [59]: plt.colorbar(c, cax=cax, orientation='horizontal', label='Temperature [K]');
In [60]: fig.show()
Edge colorbars
Edge colorbars are useful when rows or columns of a figure share a colorbar. We’ll show an example where the rows share a colorbar.
In [61]: aspect = 60. / 130.
In [62]: fig, axes, (cax1, cax2) = faceted(2, 3, width=8, aspect=aspect, right_pad=0.75,
....: cbar_mode='edge',
....: cbar_pad=0.1, internal_pad=0.1,
....: cbar_location='right', cbar_short_side_pad=0.,
....: axes_kwargs={'projection': ccrs.PlateCarree()})
....:
In [63]: for i, ax in enumerate(axes[:3]):
....: c1 = ds.air.isel(time=i).plot(
....: ax=ax, add_colorbar=False, transform=ccrs.PlateCarree(),
....: 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()
....:
In [64]: plt.colorbar(c1, cax=cax1, label='[K]');
In [65]: for i, ax in enumerate(axes[3:], start=3):
....: c2 = ds.air.isel(time=i).plot(
....: ax=ax, add_colorbar=False, transform=ccrs.PlateCarree(),
....: 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()
....:
In [66]: plt.colorbar(c2, cax=cax2, label='[K]');
In [67]: fig.show()
Colorbars for each panel
One more common use case is a colorbar for each panel. This can be done by
specifying cbar_mode='each'
as an argument in the call to faceted.faceted()
.
In [68]: tick_locator = ticker.MaxNLocator(nbins=3)
In [69]: aspect = 60. / 130.
In [70]: fig, axes, caxes = faceted(2, 3, 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()})
....:
In [71]: for i, (ax, cax) in enumerate(zip(axes, caxes)):
....: c = ds.air.isel(time=i).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()
....:
In [72]: fig.show()
Creating a single-axis figure
For convenience, faceted
comes with a function built specifically for creating
single-axis figures called faceted.faceted_ax()
. It takes alls the same keyword
arguments as faceted.faceted()
but returns scalar Axes
objects.
In [73]: from faceted import faceted_ax
In [74]: tick_locator = ticker.MaxNLocator(nbins=3)
In [75]: aspect = 60. / 130.
In [76]: 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()})
....:
In [77]: c = ds.air.isel(time=0).plot(
....: ax=ax, add_colorbar=False, transform=ccrs.PlateCarree(),
....: cmap='viridis', vmin=230, vmax=305)
....:
In [78]: ax.set_title('')
Out[78]: Text(0.5, 1.0, '')
In [79]: ax.set_xlabel('')
Out[79]: Text(0.5, 0, '')
In [80]: ax.set_ylabel('')
Out[80]: Text(0, 0.5, '')
In [81]: ax.set_extent([-160, -30, 15, 75], crs=ccrs.PlateCarree())
In [82]: ax.coastlines()
Out[82]: <cartopy.mpl.feature_artist.FeatureArtist at 0x7f0d597c1cd0>
In [83]: cb = plt.colorbar(c, cax=cax, label='[K]')
In [84]: cb.locator = tick_locator
In [85]: cb.update_ticks()
In [86]: fig.show()
Parameter defintions
A full summary of the meanings of the different arguments to faceted.faceted()
can be
found here.
Parameters controlling figure and axes dimensions
W:
width
controls the overall width of the figure in inches.y / x:
aspect
controls the aspect ratio of the panels.z:
cbar_size
controls the thickness of the colorbar in inches.
Parameters controlling padding
A:
left_pad
controls the spacing between the left-most axes and the edge of the figure in inches.B:
right_pad
controls the spacing between the right-most axes and the edge of the figure in inches.C:
bottom_pad
controls the spacing between the bottom-most axes and the edge of the figure in inches.D:
top_pad
controls the spacing between the top-most axes and the edge of the figure in inches.E:
cbar_short_side_pad
controls the spacing between the edges of the colorbar and the edges of the axes in inches.F:
internal_pad
controls the spacing between the non-colorbar axes in inches. It can either be a number (and specify the horizontal and vertical pad at the same time) or it can be a length-two sequence (and specify both the horizontal and vertical pads, respectively).G:
cbar_pad
controls the spacing (in inches) between the edge of the non-colorbar axes and the colorbar axes.