Skip to content

Commit 54f20cf

Browse files
committed
COMPAT: Support for matplotlib 1.5
1 parent 69f1cfa commit 54f20cf

File tree

7 files changed

+152
-33
lines changed

7 files changed

+152
-33
lines changed

ci/install_conda.sh

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ bash miniconda.sh -b -p $HOME/miniconda || exit 1
7272

7373
conda config --set always_yes yes --set changeps1 no || exit 1
7474
conda update -q conda || exit 1
75+
conda config --add channels conda-forge || exit 1
7576
conda config --add channels http://conda.binstar.org/pandas || exit 1
7677
conda config --set ssl_verify false || exit 1
7778

doc/source/whatsnew/v0.17.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Highlights include:
5050
- Documentation comparing SAS to *pandas*, see :ref:`here <compare_with_sas>`
5151
- Removal of the automatic TimeSeries broadcasting, deprecated since 0.8.0, see :ref:`here <whatsnew_0170.prior_deprecations>`
5252
- Compatibility with Python 3.5 (:issue:`11097`)
53+
- Compatibility with matplotlib 1.5.0 (:issue:`11111`)
5354

5455
Check the :ref:`API Changes <whatsnew_0170.api>` and :ref:`deprecations <whatsnew_0170.deprecations>` before updating.
5556

pandas/tests/test_graphics.py

+72-24
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,22 @@ def setUp(self):
7474
'weight': random.normal(161, 32, size=n),
7575
'category': random.randint(4, size=n)})
7676

77-
if str(mpl.__version__) >= LooseVersion('1.4'):
77+
self.mpl_le_1_2_1 = plotting._mpl_le_1_2_1()
78+
self.mpl_ge_1_3_1 = plotting._mpl_ge_1_3_1()
79+
self.mpl_ge_1_4_0 = plotting._mpl_ge_1_4_0()
80+
self.mpl_ge_1_5_0 = plotting._mpl_ge_1_5_0()
81+
82+
if self.mpl_ge_1_4_0:
7883
self.bp_n_objects = 7
7984
else:
8085
self.bp_n_objects = 8
86+
if self.mpl_ge_1_5_0:
87+
# 1.5 added PolyCollections to legend handler
88+
# so we have twice as many items.
89+
self.polycollection_factor = 2
90+
else:
91+
self.polycollection_factor = 1
8192

82-
self.mpl_le_1_2_1 = str(mpl.__version__) <= LooseVersion('1.2.1')
83-
self.mpl_ge_1_3_1 = str(mpl.__version__) >= LooseVersion('1.3.1')
8493

8594
def tearDown(self):
8695
tm.close()
@@ -183,7 +192,7 @@ def _check_colors(self, collections, linecolors=None, facecolors=None,
183192
"""
184193

185194
from matplotlib.lines import Line2D
186-
from matplotlib.collections import Collection
195+
from matplotlib.collections import Collection, PolyCollection
187196
conv = self.colorconverter
188197
if linecolors is not None:
189198

@@ -197,6 +206,8 @@ def _check_colors(self, collections, linecolors=None, facecolors=None,
197206
result = patch.get_color()
198207
# Line2D may contains string color expression
199208
result = conv.to_rgba(result)
209+
elif isinstance(patch, PolyCollection):
210+
result = tuple(patch.get_edgecolor()[0])
200211
else:
201212
result = patch.get_edgecolor()
202213

@@ -472,6 +483,21 @@ def is_grid_on():
472483
obj.plot(kind=kind, grid=True, **kws)
473484
self.assertTrue(is_grid_on())
474485

486+
def _maybe_unpack_cycler(self, rcParams, field='color'):
487+
"""
488+
Compat layer for MPL 1.5 change to color cycle
489+
490+
Before: plt.rcParams['axes.color_cycle'] -> ['b', 'g', 'r'...]
491+
After : plt.rcParams['axes.prop_cycle'] -> cycler(...)
492+
"""
493+
if self.mpl_ge_1_5_0:
494+
cyl = rcParams['axes.prop_cycle']
495+
colors = [v[field] for v in cyl]
496+
else:
497+
colors = rcParams['axes.color_cycle']
498+
return colors
499+
500+
475501
@tm.mplskip
476502
class TestSeriesPlots(TestPlotBase):
477503

@@ -536,9 +562,13 @@ def test_plot_figsize_and_title(self):
536562

537563
def test_dont_modify_rcParams(self):
538564
# GH 8242
539-
colors = self.plt.rcParams['axes.color_cycle']
565+
if self.mpl_ge_1_5_0:
566+
key = 'axes.prop_cycle'
567+
else:
568+
key = 'axes.color_cycle'
569+
colors = self.plt.rcParams[key]
540570
Series([1, 2, 3]).plot()
541-
self.assertEqual(colors, self.plt.rcParams['axes.color_cycle'])
571+
self.assertEqual(colors, self.plt.rcParams[key])
542572

543573
def test_ts_line_lim(self):
544574
ax = self.ts.plot()
@@ -1109,7 +1139,8 @@ def test_errorbar_plot(self):
11091139
s.plot(yerr=np.arange(11))
11101140

11111141
s_err = ['zzz']*10
1112-
with tm.assertRaises(TypeError):
1142+
# in mpl 1.5+ this is a TypeError
1143+
with tm.assertRaises((ValueError, TypeError)):
11131144
s.plot(yerr=s_err)
11141145

11151146
def test_table(self):
@@ -1183,7 +1214,10 @@ def test_time_series_plot_color_kwargs(self):
11831214
def test_time_series_plot_color_with_empty_kwargs(self):
11841215
import matplotlib as mpl
11851216

1186-
def_colors = mpl.rcParams['axes.color_cycle']
1217+
if self.mpl_ge_1_5_0:
1218+
def_colors = self._maybe_unpack_cycler(mpl.rcParams)
1219+
else:
1220+
def_colors = mpl.rcParams['axes.color_cycle']
11871221
index = date_range('1/1/2000', periods=12)
11881222
s = Series(np.arange(1, 13), index=index)
11891223

@@ -1292,7 +1326,11 @@ def test_plot(self):
12921326
fig, ax = self.plt.subplots()
12931327
axes = df.plot.bar(subplots=True, ax=ax)
12941328
self.assertEqual(len(axes), 1)
1295-
self.assertIs(ax.get_axes(), axes[0])
1329+
if self.mpl_ge_1_5_0:
1330+
result = ax.axes
1331+
else:
1332+
result = ax.get_axes() # deprecated
1333+
self.assertIs(result, axes[0])
12961334

12971335
def test_color_and_style_arguments(self):
12981336
df = DataFrame({'x': [1, 2], 'y': [3, 4]})
@@ -1802,8 +1840,7 @@ def test_area_lim(self):
18021840
@slow
18031841
def test_bar_colors(self):
18041842
import matplotlib.pyplot as plt
1805-
1806-
default_colors = plt.rcParams.get('axes.color_cycle')
1843+
default_colors = self._maybe_unpack_cycler(plt.rcParams)
18071844

18081845
df = DataFrame(randn(5, 5))
18091846
ax = df.plot.bar()
@@ -2326,6 +2363,7 @@ def test_kde_missing_vals(self):
23262363

23272364
@slow
23282365
def test_hist_df(self):
2366+
from matplotlib.patches import Rectangle
23292367
if self.mpl_le_1_2_1:
23302368
raise nose.SkipTest("not supported in matplotlib <= 1.2.x")
23312369

@@ -2346,11 +2384,14 @@ def test_hist_df(self):
23462384

23472385
ax = series.plot.hist(normed=True, cumulative=True, bins=4)
23482386
# height of last bin (index 5) must be 1.0
2349-
self.assertAlmostEqual(ax.get_children()[5].get_height(), 1.0)
2387+
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
2388+
self.assertAlmostEqual(rects[-1].get_height(), 1.0)
23502389
tm.close()
23512390

23522391
ax = series.plot.hist(cumulative=True, bins=4)
2353-
self.assertAlmostEqual(ax.get_children()[5].get_height(), 100.0)
2392+
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
2393+
2394+
self.assertAlmostEqual(rects[-2].get_height(), 100.0)
23542395
tm.close()
23552396

23562397
# if horizontal, yticklabels are rotated
@@ -2626,7 +2667,7 @@ def test_line_colors(self):
26262667
def test_line_colors_and_styles_subplots(self):
26272668
# GH 9894
26282669
from matplotlib import cm
2629-
default_colors = self.plt.rcParams.get('axes.color_cycle')
2670+
default_colors = self._maybe_unpack_cycler(self.plt.rcParams)
26302671

26312672
df = DataFrame(randn(5, 5))
26322673

@@ -2698,7 +2739,8 @@ def test_area_colors(self):
26982739

26992740
handles, labels = ax.get_legend_handles_labels()
27002741
# legend is stored as Line2D, thus check linecolors
2701-
self._check_colors(handles, linecolors=custom_colors)
2742+
linehandles = [x for x in handles if not isinstance(x, PolyCollection)]
2743+
self._check_colors(linehandles, linecolors=custom_colors)
27022744
for h in handles:
27032745
self.assertTrue(h.get_alpha() is None)
27042746
tm.close()
@@ -2710,12 +2752,13 @@ def test_area_colors(self):
27102752
self._check_colors(poly, facecolors=jet_colors)
27112753

27122754
handles, labels = ax.get_legend_handles_labels()
2713-
self._check_colors(handles, linecolors=jet_colors)
2755+
linehandles = [x for x in handles if not isinstance(x, PolyCollection)]
2756+
self._check_colors(linehandles, linecolors=jet_colors)
27142757
for h in handles:
27152758
self.assertTrue(h.get_alpha() is None)
27162759
tm.close()
27172760

2718-
# When stacked=True, alpha is set to 0.5
2761+
# When stacked=False, alpha is set to 0.5
27192762
ax = df.plot.area(colormap=cm.jet, stacked=False)
27202763
self._check_colors(ax.get_lines(), linecolors=jet_colors)
27212764
poly = [o for o in ax.get_children() if isinstance(o, PolyCollection)]
@@ -2724,13 +2767,13 @@ def test_area_colors(self):
27242767

27252768
handles, labels = ax.get_legend_handles_labels()
27262769
# Line2D can't have alpha in its linecolor
2727-
self._check_colors(handles, linecolors=jet_colors)
2770+
self._check_colors(handles[:len(jet_colors)], linecolors=jet_colors)
27282771
for h in handles:
27292772
self.assertEqual(h.get_alpha(), 0.5)
27302773

27312774
@slow
27322775
def test_hist_colors(self):
2733-
default_colors = self.plt.rcParams.get('axes.color_cycle')
2776+
default_colors = self._maybe_unpack_cycler(self.plt.rcParams)
27342777

27352778
df = DataFrame(randn(5, 5))
27362779
ax = df.plot.hist()
@@ -2791,7 +2834,7 @@ def test_kde_colors_and_styles_subplots(self):
27912834
_skip_if_no_scipy_gaussian_kde()
27922835

27932836
from matplotlib import cm
2794-
default_colors = self.plt.rcParams.get('axes.color_cycle')
2837+
default_colors = self._maybe_unpack_cycler(self.plt.rcParams)
27952838

27962839
df = DataFrame(randn(5, 5))
27972840

@@ -2853,7 +2896,7 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', fliers_c='b'):
28532896
self._check_colors(bp['fliers'], linecolors=[fliers_c] * len(bp['fliers']))
28542897
self._check_colors(bp['caps'], linecolors=[caps_c] * len(bp['caps']))
28552898

2856-
default_colors = self.plt.rcParams.get('axes.color_cycle')
2899+
default_colors = self._maybe_unpack_cycler(self.plt.rcParams)
28572900

28582901
df = DataFrame(randn(5, 5))
28592902
bp = df.plot.box(return_type='dict')
@@ -2900,12 +2943,17 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', fliers_c='b'):
29002943

29012944
def test_default_color_cycle(self):
29022945
import matplotlib.pyplot as plt
2903-
plt.rcParams['axes.color_cycle'] = list('rgbk')
2946+
colors = list('rgbk')
2947+
if self.mpl_ge_1_5_0:
2948+
import cycler
2949+
plt.rcParams['axes.prop_cycle'] = cycler.cycler('color', colors)
2950+
else:
2951+
plt.rcParams['axes.color_cycle'] = colors
29042952

29052953
df = DataFrame(randn(5, 3))
29062954
ax = df.plot()
29072955

2908-
expected = plt.rcParams['axes.color_cycle'][:3]
2956+
expected = self._maybe_unpack_cycler(plt.rcParams)[:3]
29092957
self._check_colors(ax.get_lines(), linecolors=expected)
29102958

29112959
def test_unordered_ts(self):
@@ -3125,7 +3173,7 @@ def test_errorbar_plot(self):
31253173
df.plot(yerr=np.random.randn(11))
31263174

31273175
df_err = DataFrame({'x': ['zzz']*12, 'y': ['zzz']*12})
3128-
with tm.assertRaises(TypeError):
3176+
with tm.assertRaises((ValueError, TypeError)):
31293177
df.plot(yerr=df_err)
31303178

31313179
@slow

pandas/tests/test_graphics_others.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,8 @@ def test_grouped_plot_fignums(self):
607607

608608
@slow
609609
def test_grouped_hist_legacy(self):
610+
from matplotlib.patches import Rectangle
611+
610612
df = DataFrame(randn(500, 2), columns=['A', 'B'])
611613
df['C'] = np.random.randint(0, 4, 500)
612614
df['D'] = ['X'] * 500
@@ -633,7 +635,8 @@ def test_grouped_hist_legacy(self):
633635
xlabelsize=xf, xrot=xrot, ylabelsize=yf, yrot=yrot)
634636
# height of last bin (index 5) must be 1.0
635637
for ax in axes.ravel():
636-
height = ax.get_children()[5].get_height()
638+
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
639+
height = rects[-1].get_height()
637640
self.assertAlmostEqual(height, 1.0)
638641
self._check_ticks_props(axes, xlabelsize=xf, xrot=xrot,
639642
ylabelsize=yf, yrot=yrot)

0 commit comments

Comments
 (0)