Skip to content

BUG/VIS: rot and fontsize are not applied to timeseries plots #7844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/v0.15.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ Bug Fixes
(except for the case of two DataFrames with ``pairwise=False``, where behavior is unchanged) (:issue:`7542`)



- Bug in ``DataFrame.plot`` and ``Series.plot`` may ignore ``rot`` and ``fontsize`` keywords (:issue:`7844`)


- Bug in ``DatetimeIndex.value_counts`` doesn't preserve tz (:issue:`7735`)
Expand Down
53 changes: 41 additions & 12 deletions pandas/tests/test_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,21 +240,33 @@ def _check_ticks_props(self, axes, xlabelsize=None, xrot=None,
yrot : number
expected yticks rotation
"""
from matplotlib.ticker import NullFormatter
axes = self._flatten_visible(axes)
for ax in axes:
if xlabelsize or xrot:
xtick = ax.get_xticklabels()[0]
if xlabelsize is not None:
self.assertAlmostEqual(xtick.get_fontsize(), xlabelsize)
if xrot is not None:
self.assertAlmostEqual(xtick.get_rotation(), xrot)
if isinstance(ax.xaxis.get_minor_formatter(), NullFormatter):
# If minor ticks has NullFormatter, rot / fontsize are not retained
labels = ax.get_xticklabels()
else:
labels = ax.get_xticklabels() + ax.get_xticklabels(minor=True)

for label in labels:
if xlabelsize is not None:
self.assertAlmostEqual(label.get_fontsize(), xlabelsize)
if xrot is not None:
self.assertAlmostEqual(label.get_rotation(), xrot)

if ylabelsize or yrot:
ytick = ax.get_yticklabels()[0]
if ylabelsize is not None:
self.assertAlmostEqual(ytick.get_fontsize(), ylabelsize)
if yrot is not None:
self.assertAlmostEqual(ytick.get_rotation(), yrot)
if isinstance(ax.yaxis.get_minor_formatter(), NullFormatter):
labels = ax.get_yticklabels()
else:
labels = ax.get_yticklabels() + ax.get_yticklabels(minor=True)

for label in labels:
if ylabelsize is not None:
self.assertAlmostEqual(label.get_fontsize(), ylabelsize)
if yrot is not None:
self.assertAlmostEqual(label.get_rotation(), yrot)

def _check_ax_scales(self, axes, xaxis='linear', yaxis='linear'):
"""
Expand Down Expand Up @@ -872,6 +884,7 @@ def test_plot(self):
self._check_visible(ax.xaxis)
self._check_visible(ax.get_xticklabels())
self._check_visible([ax.xaxis.get_label()])
self._check_ticks_props(ax, xrot=30)

_check_plot_works(df.plot, title='blah')

Expand Down Expand Up @@ -1069,14 +1082,16 @@ def test_subplots_timeseries(self):
self._check_visible(axes[-1].get_xticklabels(minor=True))
self._check_visible(axes[-1].xaxis.get_label())
self._check_visible(axes[-1].get_yticklabels())
self._check_ticks_props(axes, xrot=30)

axes = df.plot(kind=kind, subplots=True, sharex=False)
axes = df.plot(kind=kind, subplots=True, sharex=False, rot=45, fontsize=7)
for ax in axes:
self._check_visible(ax.xaxis)
self._check_visible(ax.get_xticklabels())
self._check_visible(ax.get_xticklabels(minor=True))
self._check_visible(ax.xaxis.get_label())
self._check_visible(ax.get_yticklabels())
self._check_ticks_props(ax, xlabelsize=7, xrot=45)

def test_negative_log(self):
df = - DataFrame(rand(6, 4),
Expand Down Expand Up @@ -1363,7 +1378,17 @@ def test_plot_bar(self):
_check_plot_works(df.plot, kind='bar')

df = DataFrame({'a': [0, 1], 'b': [1, 0]})
_check_plot_works(df.plot, kind='bar')
ax = _check_plot_works(df.plot, kind='bar')
self._check_ticks_props(ax, xrot=90)

ax = df.plot(kind='bar', rot=35, fontsize=10)
self._check_ticks_props(ax, xrot=35, xlabelsize=10)

ax = _check_plot_works(df.plot, kind='barh')
self._check_ticks_props(ax, yrot=0)

ax = df.plot(kind='barh', rot=55, fontsize=11)
self._check_ticks_props(ax, yrot=55, ylabelsize=11)

def _check_bar_alignment(self, df, kind='bar', stacked=False,
subplots=False, align='center',
Expand Down Expand Up @@ -1591,6 +1616,10 @@ def test_kde(self):
ax = _check_plot_works(df.plot, kind='kde')
expected = [com.pprint_thing(c) for c in df.columns]
self._check_legend_labels(ax, labels=expected)
self._check_ticks_props(ax, xrot=0)

ax = df.plot(kind='kde', rot=20, fontsize=5)
self._check_ticks_props(ax, xrot=20, xlabelsize=5)

axes = _check_plot_works(df.plot, kind='kde', subplots=True)
self._check_axes_shape(axes, axes_num=4, layout=(4, 1))
Expand Down
72 changes: 49 additions & 23 deletions pandas/tools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ class MPLPlot(object):

"""
_default_rot = 0
orientation = None

_pop_attributes = ['label', 'style', 'logy', 'logx', 'loglog',
'mark_right', 'stacked']
Expand Down Expand Up @@ -788,7 +789,14 @@ def __init__(self, data, kind=None, by=None, subplots=False, sharex=True,
self.use_index = use_index

self.fontsize = fontsize
self.rot = rot

if rot is not None:
self.rot = rot
else:
if isinstance(self._default_rot, dict):
self.rot = self._default_rot[self.kind]
else:
self.rot = self._default_rot

if grid is None:
grid = False if secondary_y else True
Expand Down Expand Up @@ -1018,14 +1026,30 @@ def _adorn_subplots(self):
else:
self.axes[0].set_title(self.title)

if self._need_to_set_index:
labels = [com.pprint_thing(key) for key in self.data.index]
labels = dict(zip(range(len(self.data.index)), labels))
labels = [com.pprint_thing(key) for key in self.data.index]
labels = dict(zip(range(len(self.data.index)), labels))

for ax_ in self.axes:
# ax_.set_xticks(self.xticks)
xticklabels = [labels.get(x, '') for x in ax_.get_xticks()]
ax_.set_xticklabels(xticklabels, rotation=self.rot)
for ax in self.axes:
if self.orientation == 'vertical' or self.orientation is None:
if self._need_to_set_index:
xticklabels = [labels.get(x, '') for x in ax.get_xticks()]
ax.set_xticklabels(xticklabels)
self._apply_axis_properties(ax.xaxis, rot=self.rot,
fontsize=self.fontsize)
elif self.orientation == 'horizontal':
if self._need_to_set_index:
yticklabels = [labels.get(y, '') for y in ax.get_yticks()]
ax.set_yticklabels(yticklabels)
self._apply_axis_properties(ax.yaxis, rot=self.rot,
fontsize=self.fontsize)

def _apply_axis_properties(self, axis, rot=None, fontsize=None):
labels = axis.get_majorticklabels() + axis.get_minorticklabels()
for label in labels:
if rot is not None:
label.set_rotation(rot)
if fontsize is not None:
label.set_fontsize(fontsize)

@property
def legend_title(self):
Expand Down Expand Up @@ -1336,6 +1360,8 @@ def _get_errorbars(self, label=None, index=None, xerr=True, yerr=True):


class KdePlot(MPLPlot):
orientation = 'vertical'

def __init__(self, data, bw_method=None, ind=None, **kwargs):
MPLPlot.__init__(self, data, **kwargs)
self.bw_method=bw_method
Expand Down Expand Up @@ -1480,6 +1506,9 @@ def _post_plot_logic(self):

class LinePlot(MPLPlot):

_default_rot = 30
orientation = 'vertical'

def __init__(self, data, **kwargs):
MPLPlot.__init__(self, data, **kwargs)
if self.stacked:
Expand Down Expand Up @@ -1657,16 +1686,9 @@ def _post_plot_logic(self):

index_name = self._get_index_name()

rot = 30
if self.rot is not None:
rot = self.rot

for ax in self.axes:
if condition:
format_date_labels(ax, rot=rot)
elif self.rot is not None:
for l in ax.get_xticklabels():
l.set_rotation(self.rot)
format_date_labels(ax, rot=self.rot)

if index_name is not None:
ax.set_xlabel(index_name)
Expand Down Expand Up @@ -1767,9 +1789,6 @@ def __init__(self, data, **kwargs):
self.ax_pos = self.tick_pos - self.tickoffset

def _args_adjust(self):
if self.rot is None:
self.rot = self._default_rot[self.kind]

if com.is_list_like(self.bottom):
self.bottom = np.array(self.bottom)
if com.is_list_like(self.left):
Expand Down Expand Up @@ -1859,8 +1878,7 @@ def _post_plot_logic(self):
if self.kind == 'bar':
ax.set_xlim((s_edge, e_edge))
ax.set_xticks(self.tick_pos)
ax.set_xticklabels(str_index, rotation=self.rot,
fontsize=self.fontsize)
ax.set_xticklabels(str_index)
if not self.log: # GH3254+
ax.axhline(0, color='k', linestyle='--')
if name is not None:
Expand All @@ -1869,14 +1887,22 @@ def _post_plot_logic(self):
# horizontal bars
ax.set_ylim((s_edge, e_edge))
ax.set_yticks(self.tick_pos)
ax.set_yticklabels(str_index, rotation=self.rot,
fontsize=self.fontsize)
ax.set_yticklabels(str_index)
ax.axvline(0, color='k', linestyle='--')
if name is not None:
ax.set_ylabel(name)
else:
raise NotImplementedError(self.kind)

@property
def orientation(self):
if self.kind == 'bar':
return 'vertical'
elif self.kind == 'barh':
return 'horizontal'
else:
raise NotImplementedError(self.kind)


class PiePlot(MPLPlot):

Expand Down