Skip to content

Commit bcf0d61

Browse files
authored
Add Facetgrid.row_labels & Facetgrid.col_labels (#3597)
* Add Facetgrid.row_labels & Facetgrid.col_labels This allows labels to be changed later. * Update docs.
1 parent 5c674e6 commit bcf0d61

File tree

5 files changed

+84
-14
lines changed

5 files changed

+84
-14
lines changed

doc/api.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,25 @@ Plotting
625625
plot.imshow
626626
plot.line
627627
plot.pcolormesh
628+
629+
Faceting
630+
--------
631+
.. autosummary::
632+
:toctree: generated/
633+
628634
plot.FacetGrid
635+
plot.FacetGrid.add_colorbar
636+
plot.FacetGrid.add_legend
637+
plot.FacetGrid.map
638+
plot.FacetGrid.map_dataarray
639+
plot.FacetGrid.map_dataarray_line
640+
plot.FacetGrid.map_dataset
641+
plot.FacetGrid.set_axis_labels
642+
plot.FacetGrid.set_ticks
643+
plot.FacetGrid.set_titles
644+
plot.FacetGrid.set_xlabels
645+
plot.FacetGrid.set_ylabels
646+
629647

630648
Testing
631649
=======

doc/plotting.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ Faceting here refers to splitting an array along one or two dimensions and
487487
plotting each group.
488488
xarray's basic plotting is useful for plotting two dimensional arrays. What
489489
about three or four dimensional arrays? That's where facets become helpful.
490+
The general approach to plotting here is called “small multiples”, where the same kind of plot is repeated multiple times, and the specific use of small multiples to display the same relationship conditioned on one ore more other variables is often called a “trellis plot”.
490491

491492
Consider the temperature data set. There are 4 observations per day for two
492493
years which makes for 2920 values along the time dimension.
@@ -572,8 +573,9 @@ Faceted plotting supports other arguments common to xarray 2d plots.
572573
FacetGrid Objects
573574
===================
574575

575-
:py:class:`xarray.plot.FacetGrid` is used to control the behavior of the
576-
multiple plots.
576+
The object returned, ``g`` in the above examples, is a :py:class:`~xarray.plot.FacetGrid`` object
577+
that links a :py:class:`DataArray` to a matplotlib figure with a particular structure.
578+
This object can be used to control the behavior of the multiple plots.
577579
It borrows an API and code from `Seaborn's FacetGrid
578580
<http://seaborn.pydata.org/tutorial/axis_grids.html>`_.
579581
The structure is contained within the ``axes`` and ``name_dicts``
@@ -609,6 +611,13 @@ they have been plotted.
609611
@savefig plot_facet_iterator.png
610612
plt.draw()
611613
614+
615+
:py:class:`~xarray.FacetGrid` objects have methods that let you customize the automatically generated
616+
axis labels, axis ticks and plot titles. See :py:meth:`~xarray.plot.FacetGrid.set_titles`,
617+
:py:meth:`~xarray.plot.FacetGrid.set_xlabels`, :py:meth:`~xarray.plot.FacetGrid.set_ylabels` and
618+
:py:meth:`~xarray.plot.FacetGrid.set_ticks` for more information.
619+
Plotting functions can be applied to each subset of the data by calling :py:meth:`~xarray.plot.FacetGrid.map_dataarray` or to each subplot by calling :py:meth:`FacetGrid.map`.
620+
612621
TODO: add an example of using the ``map`` method to plot dataset variables
613622
(e.g., with ``plt.quiver``).
614623

doc/whats-new.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ Bug fixes
3939
<https://github.com/spencerkclark>`_.
4040
- Fix plotting with transposed 2D non-dimensional coordinates. (:issue:`3138`, :pull:`3441`)
4141
By `Deepak Cherian <https://github.com/dcherian>`_.
42+
- :py:meth:`~xarray.plot.FacetGrid.set_titles` can now replace existing row titles of a
43+
:py:class:`~xarray.plot.FacetGrid` plot. In addition :py:class:`~xarray.plot.FacetGrid` gained
44+
two new attributes: :py:attr:`~xarray.plot.FacetGrid.col_labels` and
45+
:py:attr:`~xarray.plot.FacetGrid.row_labels` contain matplotlib Text handles for both column and
46+
row labels. These can be used to manually change the labels.
47+
By `Deepak Cherian <https://github.com/dcherian>`_.
4248
- Fix issue with Dask-backed datasets raising a ``KeyError`` on some computations involving ``map_blocks`` (:pull:`3598`)
4349
By `Tom Augspurger <https://github.com/TomAugspurger>`_.
4450

xarray/plot/facetgrid.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ class FacetGrid:
6161
axes : numpy object array
6262
Contains axes in corresponding position, as returned from
6363
plt.subplots
64+
col_labels : list
65+
list of :class:`matplotlib.text.Text` instances corresponding to column titles.
66+
row_labels : list
67+
list of :class:`matplotlib.text.Text` instances corresponding to row titles.
6468
fig : matplotlib.Figure
6569
The figure containing all the axes
6670
name_dicts : numpy object array
@@ -200,6 +204,8 @@ def __init__(
200204
self._ncol = ncol
201205
self._col_var = col
202206
self._col_wrap = col_wrap
207+
self.row_labels = [None] * nrow
208+
self.col_labels = [None] * ncol
203209
self._x_var = None
204210
self._y_var = None
205211
self._cmap_extend = None
@@ -482,22 +488,32 @@ def set_titles(self, template="{coord} = {value}", maxchar=30, size=None, **kwar
482488
ax.set_title(title, size=size, **kwargs)
483489
else:
484490
# The row titles on the right edge of the grid
485-
for ax, row_name in zip(self.axes[:, -1], self.row_names):
491+
for index, (ax, row_name, handle) in enumerate(
492+
zip(self.axes[:, -1], self.row_names, self.row_labels)
493+
):
486494
title = nicetitle(coord=self._row_var, value=row_name, maxchar=maxchar)
487-
ax.annotate(
488-
title,
489-
xy=(1.02, 0.5),
490-
xycoords="axes fraction",
491-
rotation=270,
492-
ha="left",
493-
va="center",
494-
**kwargs,
495-
)
495+
if not handle:
496+
self.row_labels[index] = ax.annotate(
497+
title,
498+
xy=(1.02, 0.5),
499+
xycoords="axes fraction",
500+
rotation=270,
501+
ha="left",
502+
va="center",
503+
**kwargs,
504+
)
505+
else:
506+
handle.set_text(title)
496507

497508
# The column titles on the top row
498-
for ax, col_name in zip(self.axes[0, :], self.col_names):
509+
for index, (ax, col_name, handle) in enumerate(
510+
zip(self.axes[0, :], self.col_names, self.col_labels)
511+
):
499512
title = nicetitle(coord=self._col_var, value=col_name, maxchar=maxchar)
500-
ax.set_title(title, size=size, **kwargs)
513+
if not handle:
514+
self.col_labels[index] = ax.set_title(title, size=size, **kwargs)
515+
else:
516+
handle.set_text(title)
501517

502518
return self
503519

xarray/tests/test_plot.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ def substring_in_axes(substring, ax):
6262
return False
6363

6464

65+
def substring_not_in_axes(substring, ax):
66+
"""
67+
Return True if a substring is not found anywhere in an axes
68+
"""
69+
alltxt = {t.get_text() for t in ax.findobj(mpl.text.Text)}
70+
check = [(substring not in txt) for txt in alltxt]
71+
return all(check)
72+
73+
6574
def easy_array(shape, start=0, stop=1):
6675
"""
6776
Make an array with desired shape using np.linspace
@@ -1776,6 +1785,18 @@ def test_default_labels(self):
17761785
for label, ax in zip(self.darray.coords["col"].values, g.axes[0, :]):
17771786
assert substring_in_axes(label, ax)
17781787

1788+
# ensure that row & col labels can be changed
1789+
g.set_titles("abc={value}")
1790+
for label, ax in zip(self.darray.coords["row"].values, g.axes[:, -1]):
1791+
assert substring_in_axes(f"abc={label}", ax)
1792+
# previous labels were "row=row0" etc.
1793+
assert substring_not_in_axes("row=", ax)
1794+
1795+
for label, ax in zip(self.darray.coords["col"].values, g.axes[0, :]):
1796+
assert substring_in_axes(f"abc={label}", ax)
1797+
# previous labels were "col=row0" etc.
1798+
assert substring_not_in_axes("col=", ax)
1799+
17791800

17801801
@pytest.mark.filterwarnings("ignore:tight_layout cannot")
17811802
class TestFacetedLinePlotsLegend(PlotTestCase):

0 commit comments

Comments
 (0)