Skip to content

Commit ba2df22

Browse files
TomAugspurgerjorisvandenbossche
authored andcommitted
COMPAT/TST Matplotlib 2.0 compatability (pandas-dev#13662)
1 parent df2d9ab commit ba2df22

File tree

8 files changed

+106
-33
lines changed

8 files changed

+106
-33
lines changed

ci/install_travis.sh

+4
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,9 @@ else
138138

139139
fi
140140

141+
if [ "$JOB_NAME" == "34_slow" ]; then
142+
conda install -c conda-forge/label/rc -c conda-forge matplotlib
143+
fi
144+
141145
echo "done"
142146
exit 0

doc/source/whatsnew/v0.19.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ Other enhancements
427427

428428
- Added documentation to :ref:`I/O<io.dtypes>` regarding the perils of reading in columns with mixed dtypes and how to handle it (:issue:`13746`)
429429
- Raise ``ImportError`` in the sql functions when ``sqlalchemy`` is not installed and a connection string is used (:issue:`11920`).
430-
430+
- Compatibility with matplotlib 2.0. Older versions of pandas should also work with matplotlib 2.0 (:issue:`13333`)
431431

432432
.. _whatsnew_0190.api:
433433

pandas/tests/plotting/common.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def setUp(self):
5252
self.mpl_ge_1_3_1 = plotting._mpl_ge_1_3_1()
5353
self.mpl_ge_1_4_0 = plotting._mpl_ge_1_4_0()
5454
self.mpl_ge_1_5_0 = plotting._mpl_ge_1_5_0()
55+
self.mpl_ge_2_0_0 = plotting._mpl_ge_2_0_0()
5556

5657
if self.mpl_ge_1_4_0:
5758
self.bp_n_objects = 7
@@ -64,6 +65,11 @@ def setUp(self):
6465
else:
6566
self.polycollection_factor = 1
6667

68+
if self.mpl_ge_2_0_0:
69+
self.default_figsize = (6.4, 4.8)
70+
else:
71+
self.default_figsize = (8.0, 6.0)
72+
self.default_tick_position = 'left' if self.mpl_ge_2_0_0 else 'default'
6773
# common test data
6874
from pandas import read_csv
6975
path = os.path.join(os.path.dirname(curpath()), 'data', 'iris.csv')
@@ -189,7 +195,9 @@ def _check_colors(self, collections, linecolors=None, facecolors=None,
189195
"""
190196

191197
from matplotlib.lines import Line2D
192-
from matplotlib.collections import Collection, PolyCollection
198+
from matplotlib.collections import (
199+
Collection, PolyCollection, LineCollection
200+
)
193201
conv = self.colorconverter
194202
if linecolors is not None:
195203

@@ -203,7 +211,7 @@ def _check_colors(self, collections, linecolors=None, facecolors=None,
203211
result = patch.get_color()
204212
# Line2D may contains string color expression
205213
result = conv.to_rgba(result)
206-
elif isinstance(patch, PolyCollection):
214+
elif isinstance(patch, (PolyCollection, LineCollection)):
207215
result = tuple(patch.get_edgecolor()[0])
208216
else:
209217
result = patch.get_edgecolor()
@@ -318,7 +326,7 @@ def _check_ax_scales(self, axes, xaxis='linear', yaxis='linear'):
318326
self.assertEqual(ax.yaxis.get_scale(), yaxis)
319327

320328
def _check_axes_shape(self, axes, axes_num=None, layout=None,
321-
figsize=(8.0, 6.0)):
329+
figsize=None):
322330
"""
323331
Check expected number of axes is drawn in expected layout
324332
@@ -333,6 +341,8 @@ def _check_axes_shape(self, axes, axes_num=None, layout=None,
333341
figsize : tuple
334342
expected figsize. default is matplotlib default
335343
"""
344+
if figsize is None:
345+
figsize = self.default_figsize
336346
visible_axes = self._flatten_visible(axes)
337347

338348
if axes_num is not None:
@@ -346,7 +356,7 @@ def _check_axes_shape(self, axes, axes_num=None, layout=None,
346356
self.assertEqual(result, layout)
347357

348358
self.assert_numpy_array_equal(
349-
np.round(visible_axes[0].figure.get_size_inches()),
359+
visible_axes[0].figure.get_size_inches(),
350360
np.array(figsize, dtype=np.float64))
351361

352362
def _get_axes_layout(self, axes):

pandas/tests/plotting/test_datetimelike.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class TestTSPlot(TestPlotBase):
2626

2727
def setUp(self):
2828
TestPlotBase.setUp(self)
29+
2930
freq = ['S', 'T', 'H', 'D', 'W', 'M', 'Q', 'A']
3031
idx = [period_range('12/31/1999', freq=x, periods=100) for x in freq]
3132
self.period_ser = [Series(np.random.randn(len(x)), x) for x in idx]
@@ -122,7 +123,8 @@ def test_tsplot(self):
122123
_check_plot_works(s.plot, ax=ax)
123124

124125
ax = ts.plot(style='k')
125-
self.assertEqual((0., 0., 0.), ax.get_lines()[0].get_color())
126+
color = (0., 0., 0., 1) if self.mpl_ge_2_0_0 else (0., 0., 0.)
127+
self.assertEqual(color, ax.get_lines()[0].get_color())
126128

127129
def test_both_style_and_color(self):
128130
import matplotlib.pyplot as plt # noqa
@@ -575,7 +577,8 @@ def test_secondary_y(self):
575577
plt.close(fig)
576578

577579
ax2 = ser2.plot()
578-
self.assertEqual(ax2.get_yaxis().get_ticks_position(), 'default')
580+
self.assertEqual(ax2.get_yaxis().get_ticks_position(),
581+
self.default_tick_position)
579582
plt.close(ax2.get_figure())
580583

581584
ax = ser2.plot()
@@ -605,7 +608,8 @@ def test_secondary_y_ts(self):
605608
plt.close(fig)
606609

607610
ax2 = ser2.plot()
608-
self.assertEqual(ax2.get_yaxis().get_ticks_position(), 'default')
611+
self.assertEqual(ax2.get_yaxis().get_ticks_position(),
612+
self.default_tick_position)
609613
plt.close(ax2.get_figure())
610614

611615
ax = ser2.plot()
@@ -639,15 +643,17 @@ def test_secondary_frame(self):
639643
df = DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c'])
640644
axes = df.plot(secondary_y=['a', 'c'], subplots=True)
641645
self.assertEqual(axes[0].get_yaxis().get_ticks_position(), 'right')
642-
self.assertEqual(axes[1].get_yaxis().get_ticks_position(), 'default')
646+
self.assertEqual(axes[1].get_yaxis().get_ticks_position(),
647+
self.default_tick_position)
643648
self.assertEqual(axes[2].get_yaxis().get_ticks_position(), 'right')
644649

645650
@slow
646651
def test_secondary_bar_frame(self):
647652
df = DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c'])
648653
axes = df.plot(kind='bar', secondary_y=['a', 'c'], subplots=True)
649654
self.assertEqual(axes[0].get_yaxis().get_ticks_position(), 'right')
650-
self.assertEqual(axes[1].get_yaxis().get_ticks_position(), 'default')
655+
self.assertEqual(axes[1].get_yaxis().get_ticks_position(),
656+
self.default_tick_position)
651657
self.assertEqual(axes[2].get_yaxis().get_ticks_position(), 'right')
652658

653659
def test_mixed_freq_regular_first(self):

pandas/tests/plotting/test_frame.py

+57-19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import pandas as pd
1111
from pandas import (Series, DataFrame, MultiIndex, PeriodIndex, date_range,
1212
bdate_range)
13+
from pandas.types.api import is_list_like
1314
from pandas.compat import (range, lrange, StringIO, lmap, lzip, u, zip, PY3)
1415
from pandas.formats.printing import pprint_thing
1516
import pandas.util.testing as tm
@@ -952,9 +953,12 @@ def test_scatter_colors(self):
952953
with tm.assertRaises(TypeError):
953954
df.plot.scatter(x='a', y='b', c='c', color='green')
954955

956+
default_colors = self._maybe_unpack_cycler(self.plt.rcParams)
957+
955958
ax = df.plot.scatter(x='a', y='b', c='c')
956-
tm.assert_numpy_array_equal(ax.collections[0].get_facecolor()[0],
957-
np.array([0, 0, 1, 1], dtype=np.float64))
959+
tm.assert_numpy_array_equal(
960+
ax.collections[0].get_facecolor()[0],
961+
np.array(self.colorconverter.to_rgba(default_colors[0])))
958962

959963
ax = df.plot.scatter(x='a', y='b', color='white')
960964
tm.assert_numpy_array_equal(ax.collections[0].get_facecolor()[0],
@@ -1623,6 +1627,8 @@ def test_line_colors_and_styles_subplots(self):
16231627

16241628
axes = df.plot(subplots=True)
16251629
for ax, c in zip(axes, list(default_colors)):
1630+
if self.mpl_ge_2_0_0:
1631+
c = [c]
16261632
self._check_colors(ax.get_lines(), linecolors=c)
16271633
tm.close()
16281634

@@ -1703,9 +1709,14 @@ def test_area_colors(self):
17031709
self._check_colors(poly, facecolors=custom_colors)
17041710

17051711
handles, labels = ax.get_legend_handles_labels()
1706-
# legend is stored as Line2D, thus check linecolors
1707-
linehandles = [x for x in handles if not isinstance(x, PolyCollection)]
1708-
self._check_colors(linehandles, linecolors=custom_colors)
1712+
if self.mpl_ge_1_5_0:
1713+
self._check_colors(handles, facecolors=custom_colors)
1714+
else:
1715+
# legend is stored as Line2D, thus check linecolors
1716+
linehandles = [x for x in handles
1717+
if not isinstance(x, PolyCollection)]
1718+
self._check_colors(linehandles, linecolors=custom_colors)
1719+
17091720
for h in handles:
17101721
self.assertTrue(h.get_alpha() is None)
17111722
tm.close()
@@ -1717,8 +1728,12 @@ def test_area_colors(self):
17171728
self._check_colors(poly, facecolors=jet_colors)
17181729

17191730
handles, labels = ax.get_legend_handles_labels()
1720-
linehandles = [x for x in handles if not isinstance(x, PolyCollection)]
1721-
self._check_colors(linehandles, linecolors=jet_colors)
1731+
if self.mpl_ge_1_5_0:
1732+
self._check_colors(handles, facecolors=jet_colors)
1733+
else:
1734+
linehandles = [x for x in handles
1735+
if not isinstance(x, PolyCollection)]
1736+
self._check_colors(linehandles, linecolors=jet_colors)
17221737
for h in handles:
17231738
self.assertTrue(h.get_alpha() is None)
17241739
tm.close()
@@ -1731,8 +1746,12 @@ def test_area_colors(self):
17311746
self._check_colors(poly, facecolors=jet_with_alpha)
17321747

17331748
handles, labels = ax.get_legend_handles_labels()
1734-
# Line2D can't have alpha in its linecolor
1735-
self._check_colors(handles[:len(jet_colors)], linecolors=jet_colors)
1749+
if self.mpl_ge_1_5_0:
1750+
linecolors = jet_with_alpha
1751+
else:
1752+
# Line2D can't have alpha in its linecolor
1753+
linecolors = jet_colors
1754+
self._check_colors(handles[:len(jet_colors)], linecolors=linecolors)
17361755
for h in handles:
17371756
self.assertEqual(h.get_alpha(), 0.5)
17381757

@@ -1855,7 +1874,10 @@ def test_kde_colors_and_styles_subplots(self):
18551874
@slow
18561875
def test_boxplot_colors(self):
18571876
def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k',
1858-
fliers_c='b'):
1877+
fliers_c=None):
1878+
# TODO: outside this func?
1879+
if fliers_c is None:
1880+
fliers_c = 'k' if self.mpl_ge_2_0_0 else 'b'
18591881
self._check_colors(bp['boxes'],
18601882
linecolors=[box_c] * len(bp['boxes']))
18611883
self._check_colors(bp['whiskers'],
@@ -2232,16 +2254,24 @@ def test_errorbar_asymmetrical(self):
22322254
np.random.seed(0)
22332255
err = np.random.rand(3, 2, 5)
22342256

2235-
data = np.random.randn(5, 3)
2236-
df = DataFrame(data)
2257+
# each column is [0, 1, 2, 3, 4], [3, 4, 5, 6, 7]...
2258+
df = DataFrame(np.arange(15).reshape(3, 5)).T
2259+
data = df.values
22372260

22382261
ax = df.plot(yerr=err, xerr=err / 2)
22392262

2240-
self.assertEqual(ax.lines[7].get_ydata()[0], data[0, 1] - err[1, 0, 0])
2241-
self.assertEqual(ax.lines[8].get_ydata()[0], data[0, 1] + err[1, 1, 0])
2263+
if self.mpl_ge_2_0_0:
2264+
yerr_0_0 = ax.collections[1].get_paths()[0].vertices[:, 1]
2265+
expected_0_0 = err[0, :, 0] * np.array([-1, 1])
2266+
tm.assert_almost_equal(yerr_0_0, expected_0_0)
2267+
else:
2268+
self.assertEqual(ax.lines[7].get_ydata()[0],
2269+
data[0, 1] - err[1, 0, 0])
2270+
self.assertEqual(ax.lines[8].get_ydata()[0],
2271+
data[0, 1] + err[1, 1, 0])
22422272

2243-
self.assertEqual(ax.lines[5].get_xdata()[0], -err[1, 0, 0] / 2)
2244-
self.assertEqual(ax.lines[6].get_xdata()[0], err[1, 1, 0] / 2)
2273+
self.assertEqual(ax.lines[5].get_xdata()[0], -err[1, 0, 0] / 2)
2274+
self.assertEqual(ax.lines[6].get_xdata()[0], err[1, 1, 0] / 2)
22452275

22462276
with tm.assertRaises(ValueError):
22472277
df.plot(yerr=err.T)
@@ -2277,9 +2307,17 @@ def test_errorbar_scatter(self):
22772307
self._check_has_errorbars(ax, xerr=1, yerr=1)
22782308

22792309
def _check_errorbar_color(containers, expected, has_err='has_xerr'):
2280-
errs = [c.lines[1][0]
2281-
for c in ax.containers if getattr(c, has_err, False)]
2282-
self._check_colors(errs, linecolors=[expected] * len(errs))
2310+
lines = []
2311+
errs = [c.lines
2312+
for c in ax.containers if getattr(c, has_err, False)][0]
2313+
for el in errs:
2314+
if is_list_like(el):
2315+
lines.extend(el)
2316+
else:
2317+
lines.append(el)
2318+
err_lines = [x for x in lines if x in ax.collections]
2319+
self._check_colors(
2320+
err_lines, linecolors=np.array([expected] * len(err_lines)))
22832321

22842322
# GH 8081
22852323
df = DataFrame(

pandas/tests/plotting/test_misc.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,10 @@ def test_scatter_matrix_axis(self):
103103
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
104104

105105
# GH 5662
106-
expected = ['-2', '-1', '0', '1', '2']
106+
if self.mpl_ge_2_0_0:
107+
expected = ['-2', '0', '2']
108+
else:
109+
expected = ['-2', '-1', '0', '1', '2']
107110
self._check_text_labels(axes0_labels, expected)
108111
self._check_ticks_props(
109112
axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0)
@@ -115,7 +118,10 @@ def test_scatter_matrix_axis(self):
115118
axes = _check_plot_works(scatter_matrix, filterwarnings='always',
116119
frame=df, range_padding=.1)
117120
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
118-
expected = ['-1.2', '-1.0', '-0.8', '-0.6', '-0.4', '-0.2', '0.0']
121+
if self.mpl_ge_2_0_0:
122+
expected = ['-1.0', '-0.5', '0.0']
123+
else:
124+
expected = ['-1.2', '-1.0', '-0.8', '-0.6', '-0.4', '-0.2', '0.0']
119125
self._check_text_labels(axes0_labels, expected)
120126
self._check_ticks_props(
121127
axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0)

pandas/tests/plotting/test_series.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,13 @@ def test_bar_log(self):
218218
expected = np.hstack((1.0e-04, expected, 1.0e+01))
219219

220220
ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='bar')
221-
self.assertEqual(ax.get_ylim(), (0.001, 0.10000000000000001))
221+
ymax = 0.12589254117941673 if self.mpl_ge_2_0_0 else .10000000000000001
222+
self.assertEqual(ax.get_ylim(), (0.001, ymax))
222223
tm.assert_numpy_array_equal(ax.yaxis.get_ticklocs(), expected)
223224
tm.close()
224225

225226
ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='barh')
226-
self.assertEqual(ax.get_xlim(), (0.001, 0.10000000000000001))
227+
self.assertEqual(ax.get_xlim(), (0.001, ymax))
227228
tm.assert_numpy_array_equal(ax.xaxis.get_ticklocs(), expected)
228229

229230
@slow

pandas/tools/plotting.py

+8
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ def _mpl_ge_1_5_0():
141141
except ImportError:
142142
return False
143143

144+
145+
def _mpl_ge_2_0_0():
146+
try:
147+
import matplotlib
148+
return matplotlib.__version__ >= LooseVersion('2.0')
149+
except ImportError:
150+
return False
151+
144152
if _mpl_ge_1_5_0():
145153
# Compat with mp 1.5, which uses cycler.
146154
import cycler

0 commit comments

Comments
 (0)