Skip to content

Commit 5f057cb

Browse files
bmagnussonjorisvandenbossche
authored andcommitted
ENH: Add the ability to have a separate title for each subplot when plotting (#14753)
* Add logic such that if 'title' is a list and 'subplots' is True, use each item of the list as the title of the individual subplots.
1 parent 3ac41ab commit 5f057cb

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Other enhancements
5353
- ``pd.cut`` and ``pd.qcut`` now support datetime64 and timedelta64 dtypes (issue:`14714`)
5454
- ``Series`` provides a ``to_excel`` method to output Excel files (:issue:`8825`)
5555
- The ``usecols`` argument in ``pd.read_csv`` now accepts a callable function as a value (:issue:`14154`)
56+
- ``pd.DataFrame.plot`` now prints a title above each subplot if ``suplots=True`` and ``title`` is a list of strings (:issue:`14753`)
5657

5758
.. _whatsnew_0200.api_breaking:
5859

pandas/tests/plotting/test_misc.py

+26-3
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@
1616
from pandas.tests.plotting.common import (TestPlotBase, _check_plot_works,
1717
_ok_for_gaussian_kde)
1818

19-
2019
""" Test cases for misc plot functions """
2120

2221

2322
@tm.mplskip
2423
class TestSeriesPlots(TestPlotBase):
25-
2624
def setUp(self):
2725
TestPlotBase.setUp(self)
2826
import matplotlib as mpl
@@ -54,7 +52,6 @@ def test_bootstrap_plot(self):
5452

5553
@tm.mplskip
5654
class TestDataFramePlots(TestPlotBase):
57-
5855
@slow
5956
def test_scatter_plot_legacy(self):
6057
tm._skip_if_no_scipy()
@@ -277,6 +274,32 @@ def test_radviz(self):
277274
handles, labels = ax.get_legend_handles_labels()
278275
self._check_colors(handles, facecolors=colors)
279276

277+
@slow
278+
def test_subplot_titles(self):
279+
df = self.iris.drop('Name', axis=1).head()
280+
# Use the column names as the subplot titles
281+
title = list(df.columns)
282+
283+
# Case len(title) == len(df)
284+
plot = df.plot(subplots=True, title=title)
285+
self.assertEqual([p.get_title() for p in plot], title)
286+
287+
# Case len(title) > len(df)
288+
self.assertRaises(ValueError, df.plot, subplots=True,
289+
title=title + ["kittens > puppies"])
290+
291+
# Case len(title) < len(df)
292+
self.assertRaises(ValueError, df.plot, subplots=True, title=title[:2])
293+
294+
# Case subplots=False and title is of type list
295+
self.assertRaises(ValueError, df.plot, subplots=False, title=title)
296+
297+
# Case df with 3 numeric columns but layout of (2,2)
298+
plot = df.drop('SepalWidth', axis=1).plot(subplots=True, layout=(2, 2),
299+
title=title[:-1])
300+
title_list = [ax.get_title() for sublist in plot for ax in sublist]
301+
self.assertEqual(title_list, title[:3] + [''])
302+
280303

281304
if __name__ == '__main__':
282305
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],

pandas/tools/plotting.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -1217,8 +1217,25 @@ def _adorn_subplots(self):
12171217

12181218
if self.title:
12191219
if self.subplots:
1220-
self.fig.suptitle(self.title)
1220+
if is_list_like(self.title):
1221+
if len(self.title) != self.nseries:
1222+
msg = ('The length of `title` must equal the number '
1223+
'of columns if using `title` of type `list` '
1224+
'and `subplots=True`.\n'
1225+
'length of title = {}\n'
1226+
'number of columns = {}').format(
1227+
len(self.title), self.nseries)
1228+
raise ValueError(msg)
1229+
1230+
for (ax, title) in zip(self.axes, self.title):
1231+
ax.set_title(title)
1232+
else:
1233+
self.fig.suptitle(self.title)
12211234
else:
1235+
if is_list_like(self.title):
1236+
msg = ('Using `title` of type `list` is not supported '
1237+
'unless `subplots=True` is passed')
1238+
raise ValueError(msg)
12221239
self.axes[0].set_title(self.title)
12231240

12241241
def _apply_axis_properties(self, axis, rot=None, fontsize=None):
@@ -2555,8 +2572,10 @@ def _plot(data, x=None, y=None, subplots=False,
25552572
figsize : a tuple (width, height) in inches
25562573
use_index : boolean, default True
25572574
Use index as ticks for x axis
2558-
title : string
2559-
Title to use for the plot
2575+
title : string or list
2576+
Title to use for the plot. If a string is passed, print the string at
2577+
the top of the figure. If a list is passed and `subplots` is True,
2578+
print each item in the list above the corresponding subplot.
25602579
grid : boolean, default None (matlab style default)
25612580
Axis grid lines
25622581
legend : False/True/'reverse'

0 commit comments

Comments
 (0)