Skip to content

Commit f920bf2

Browse files
committed
Merge pull request pandas-dev#11145 from TomAugspurger/mpl15
COMPAT: Support for MPL 1.5
2 parents 597aa42 + bdd51ec commit f920bf2

File tree

8 files changed

+256
-104
lines changed

8 files changed

+256
-104
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

ci/requirements-3.4.run

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ beautiful-soup
1111
scipy
1212
numexpr
1313
pytables
14-
matplotlib=1.3.1
1514
lxml
1615
sqlalchemy
1716
bottleneck

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

+142-68
Large diffs are not rendered by default.

pandas/tests/test_graphics_others.py

+32-25
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,22 @@ def test_plot_fails_when_ax_differs_from_figure(self):
161161
@slow
162162
def test_autocorrelation_plot(self):
163163
from pandas.tools.plotting import autocorrelation_plot
164-
_check_plot_works(autocorrelation_plot, self.ts)
165-
_check_plot_works(autocorrelation_plot, self.ts.values)
164+
_check_plot_works(autocorrelation_plot, series=self.ts)
165+
_check_plot_works(autocorrelation_plot, series=self.ts.values)
166166

167167
ax = autocorrelation_plot(self.ts, label='Test')
168168
self._check_legend_labels(ax, labels=['Test'])
169169

170170
@slow
171171
def test_lag_plot(self):
172172
from pandas.tools.plotting import lag_plot
173-
_check_plot_works(lag_plot, self.ts)
174-
_check_plot_works(lag_plot, self.ts, lag=5)
173+
_check_plot_works(lag_plot, series=self.ts)
174+
_check_plot_works(lag_plot, series=self.ts, lag=5)
175175

176176
@slow
177177
def test_bootstrap_plot(self):
178178
from pandas.tools.plotting import bootstrap_plot
179-
_check_plot_works(bootstrap_plot, self.ts, size=10)
179+
_check_plot_works(bootstrap_plot, series=self.ts, size=10)
180180

181181

182182
@tm.mplskip
@@ -210,7 +210,7 @@ def test_boxplot_legacy(self):
210210
_check_plot_works(df.boxplot, column='one', by=['indic', 'indic2'])
211211
_check_plot_works(df.boxplot, by='indic')
212212
_check_plot_works(df.boxplot, by=['indic', 'indic2'])
213-
_check_plot_works(plotting.boxplot, df['one'], return_type='dict')
213+
_check_plot_works(plotting.boxplot, data=df['one'], return_type='dict')
214214
_check_plot_works(df.boxplot, notch=1, return_type='dict')
215215
_check_plot_works(df.boxplot, by='indic', notch=1)
216216

@@ -304,6 +304,7 @@ def test_boxplot_empty_column(self):
304304

305305
@slow
306306
def test_hist_df_legacy(self):
307+
from matplotlib.patches import Rectangle
307308
_check_plot_works(self.hist_df.hist)
308309

309310
# make sure layout is handled
@@ -347,7 +348,8 @@ def test_hist_df_legacy(self):
347348
# make sure kwargs to hist are handled
348349
ax = ser.hist(normed=True, cumulative=True, bins=4)
349350
# height of last bin (index 5) must be 1.0
350-
self.assertAlmostEqual(ax.get_children()[5].get_height(), 1.0)
351+
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
352+
self.assertAlmostEqual(rects[-1].get_height(), 1.0)
351353

352354
tm.close()
353355
ax = ser.hist(log=True)
@@ -413,9 +415,9 @@ def scat(**kwds):
413415
def scat2(x, y, by=None, ax=None, figsize=None):
414416
return plotting.scatter_plot(df, x, y, by, ax, figsize=None)
415417

416-
_check_plot_works(scat2, 0, 1)
418+
_check_plot_works(scat2, x=0, y=1)
417419
grouper = Series(np.repeat([1, 2, 3, 4, 5], 20), df.index)
418-
_check_plot_works(scat2, 0, 1, by=grouper)
420+
_check_plot_works(scat2, x=0, y=1, by=grouper)
419421

420422
def test_scatter_matrix_axis(self):
421423
tm._skip_if_no_scipy()
@@ -424,15 +426,17 @@ def test_scatter_matrix_axis(self):
424426
with tm.RNGContext(42):
425427
df = DataFrame(randn(100, 3))
426428

427-
axes = _check_plot_works(scatter_matrix, df, range_padding=.1)
429+
axes = _check_plot_works(scatter_matrix, filterwarnings='always', frame=df,
430+
range_padding=.1)
428431
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
429432
# GH 5662
430433
expected = ['-2', '-1', '0', '1', '2']
431434
self._check_text_labels(axes0_labels, expected)
432435
self._check_ticks_props(axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0)
433436

434437
df[0] = ((df[0] - 2) / 3)
435-
axes = _check_plot_works(scatter_matrix, df, range_padding=.1)
438+
axes = _check_plot_works(scatter_matrix, filterwarnings='always', frame=df,
439+
range_padding=.1)
436440
axes0_labels = axes[0][0].yaxis.get_majorticklabels()
437441
expected = ['-1.2', '-1.0', '-0.8', '-0.6', '-0.4', '-0.2', '0.0']
438442
self._check_text_labels(axes0_labels, expected)
@@ -445,17 +449,17 @@ def test_andrews_curves(self):
445449

446450
df = self.iris
447451

448-
_check_plot_works(andrews_curves, df, 'Name')
452+
_check_plot_works(andrews_curves, frame=df, class_column='Name')
449453

450454
rgba = ('#556270', '#4ECDC4', '#C7F464')
451-
ax = _check_plot_works(andrews_curves, df, 'Name', color=rgba)
455+
ax = _check_plot_works(andrews_curves, frame=df, class_column='Name', color=rgba)
452456
self._check_colors(ax.get_lines()[:10], linecolors=rgba, mapping=df['Name'][:10])
453457

454458
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
455-
ax = _check_plot_works(andrews_curves, df, 'Name', color=cnames)
459+
ax = _check_plot_works(andrews_curves, frame=df, class_column='Name', color=cnames)
456460
self._check_colors(ax.get_lines()[:10], linecolors=cnames, mapping=df['Name'][:10])
457461

458-
ax = _check_plot_works(andrews_curves, df, 'Name', colormap=cm.jet)
462+
ax = _check_plot_works(andrews_curves, frame=df, class_column='Name', colormap=cm.jet)
459463
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
460464
self._check_colors(ax.get_lines()[:10], linecolors=cmaps, mapping=df['Name'][:10])
461465

@@ -478,23 +482,23 @@ def test_parallel_coordinates(self):
478482

479483
df = self.iris
480484

481-
ax = _check_plot_works(parallel_coordinates, df, 'Name')
485+
ax = _check_plot_works(parallel_coordinates, frame=df, class_column='Name')
482486
nlines = len(ax.get_lines())
483487
nxticks = len(ax.xaxis.get_ticklabels())
484488

485489
rgba = ('#556270', '#4ECDC4', '#C7F464')
486-
ax = _check_plot_works(parallel_coordinates, df, 'Name', color=rgba)
490+
ax = _check_plot_works(parallel_coordinates, frame=df, class_column='Name', color=rgba)
487491
self._check_colors(ax.get_lines()[:10], linecolors=rgba, mapping=df['Name'][:10])
488492

489493
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
490-
ax = _check_plot_works(parallel_coordinates, df, 'Name', color=cnames)
494+
ax = _check_plot_works(parallel_coordinates, frame=df, class_column='Name', color=cnames)
491495
self._check_colors(ax.get_lines()[:10], linecolors=cnames, mapping=df['Name'][:10])
492496

493-
ax = _check_plot_works(parallel_coordinates, df, 'Name', colormap=cm.jet)
497+
ax = _check_plot_works(parallel_coordinates, frame=df, class_column='Name', colormap=cm.jet)
494498
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
495499
self._check_colors(ax.get_lines()[:10], linecolors=cmaps, mapping=df['Name'][:10])
496500

497-
ax = _check_plot_works(parallel_coordinates, df, 'Name', axvlines=False)
501+
ax = _check_plot_works(parallel_coordinates, frame=df, class_column='Name', axvlines=False)
498502
assert len(ax.get_lines()) == (nlines - nxticks)
499503

500504
colors = ['b', 'g', 'r']
@@ -517,20 +521,20 @@ def test_radviz(self):
517521
from matplotlib import cm
518522

519523
df = self.iris
520-
_check_plot_works(radviz, df, 'Name')
524+
_check_plot_works(radviz, frame=df, class_column='Name')
521525

522526
rgba = ('#556270', '#4ECDC4', '#C7F464')
523-
ax = _check_plot_works(radviz, df, 'Name', color=rgba)
527+
ax = _check_plot_works(radviz, frame=df, class_column='Name', color=rgba)
524528
# skip Circle drawn as ticks
525529
patches = [p for p in ax.patches[:20] if p.get_label() != '']
526530
self._check_colors(patches[:10], facecolors=rgba, mapping=df['Name'][:10])
527531

528532
cnames = ['dodgerblue', 'aquamarine', 'seagreen']
529-
_check_plot_works(radviz, df, 'Name', color=cnames)
533+
_check_plot_works(radviz, frame=df, class_column='Name', color=cnames)
530534
patches = [p for p in ax.patches[:20] if p.get_label() != '']
531535
self._check_colors(patches, facecolors=cnames, mapping=df['Name'][:10])
532536

533-
_check_plot_works(radviz, df, 'Name', colormap=cm.jet)
537+
_check_plot_works(radviz, frame=df, class_column='Name', colormap=cm.jet)
534538
cmaps = lmap(cm.jet, np.linspace(0, 1, df['Name'].nunique()))
535539
patches = [p for p in ax.patches[:20] if p.get_label() != '']
536540
self._check_colors(patches, facecolors=cmaps, mapping=df['Name'][:10])
@@ -607,6 +611,8 @@ def test_grouped_plot_fignums(self):
607611

608612
@slow
609613
def test_grouped_hist_legacy(self):
614+
from matplotlib.patches import Rectangle
615+
610616
df = DataFrame(randn(500, 2), columns=['A', 'B'])
611617
df['C'] = np.random.randint(0, 4, 500)
612618
df['D'] = ['X'] * 500
@@ -633,7 +639,8 @@ def test_grouped_hist_legacy(self):
633639
xlabelsize=xf, xrot=xrot, ylabelsize=yf, yrot=yrot)
634640
# height of last bin (index 5) must be 1.0
635641
for ax in axes.ravel():
636-
height = ax.get_children()[5].get_height()
642+
rects = [x for x in ax.get_children() if isinstance(x, Rectangle)]
643+
height = rects[-1].get_height()
637644
self.assertAlmostEqual(height, 1.0)
638645
self._check_ticks_props(axes, xlabelsize=xf, xrot=xrot,
639646
ylabelsize=yf, yrot=yrot)

pandas/tools/plotting.py

+68-10
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
from pandas.compat import range, lrange, lmap, map, zip, string_types
2525
import pandas.compat as compat
2626
from pandas.util.decorators import Appender
27-
2827
try: # mpl optional
2928
import pandas.tseries.converter as conv
3029
conv.register() # needs to override so set_xlim works with str/number
3130
except ImportError:
3231
pass
3332

33+
3434
# Extracted from https://gist.github.com/huyng/816622
3535
# this is the rcParams set when setting display.with_mpl_style
3636
# to True.
@@ -97,6 +97,48 @@
9797
'ytick.minor.size': 0.0
9898
}
9999

100+
101+
def _mpl_le_1_2_1():
102+
try:
103+
import matplotlib as mpl
104+
return (str(mpl.__version__) <= LooseVersion('1.2.1') and
105+
str(mpl.__version__)[0] != '0')
106+
except ImportError:
107+
return False
108+
109+
def _mpl_ge_1_3_1():
110+
try:
111+
import matplotlib
112+
# The or v[0] == '0' is because their versioneer is
113+
# messed up on dev
114+
return (matplotlib.__version__ >= LooseVersion('1.3.1')
115+
or matplotlib.__version__[0] == '0')
116+
except ImportError:
117+
return False
118+
119+
def _mpl_ge_1_4_0():
120+
try:
121+
import matplotlib
122+
return (matplotlib.__version__ >= LooseVersion('1.4')
123+
or matplotlib.__version__[0] == '0')
124+
except ImportError:
125+
return False
126+
127+
def _mpl_ge_1_5_0():
128+
try:
129+
import matplotlib
130+
return (matplotlib.__version__ >= LooseVersion('1.5')
131+
or matplotlib.__version__[0] == '0')
132+
except ImportError:
133+
return False
134+
135+
if _mpl_ge_1_5_0():
136+
# Compat with mp 1.5, which uses cycler.
137+
import cycler
138+
colors = mpl_stylesheet.pop('axes.color_cycle')
139+
mpl_stylesheet['axes.prop_cycle'] = cycler.cycler('color_cycle', colors)
140+
141+
100142
def _get_standard_kind(kind):
101143
return {'density': 'kde'}.get(kind, kind)
102144

@@ -784,7 +826,6 @@ def _kind(self):
784826
_layout_type = 'vertical'
785827
_default_rot = 0
786828
orientation = None
787-
788829
_pop_attributes = ['label', 'style', 'logy', 'logx', 'loglog',
789830
'mark_right', 'stacked']
790831
_attr_defaults = {'logy': False, 'logx': False, 'loglog': False,
@@ -973,8 +1014,9 @@ def _maybe_right_yaxis(self, ax, axes_num):
9731014
else:
9741015
# otherwise, create twin axes
9751016
orig_ax, new_ax = ax, ax.twinx()
976-
new_ax._get_lines.color_cycle = orig_ax._get_lines.color_cycle
977-
1017+
# TODO: use Matplotlib public API when available
1018+
new_ax._get_lines = orig_ax._get_lines
1019+
new_ax._get_patches_for_fill = orig_ax._get_patches_for_fill
9781020
orig_ax.right_ax, new_ax.left_ax = new_ax, orig_ax
9791021

9801022
if not self._has_plotted_object(orig_ax): # no data on left y
@@ -1197,6 +1239,14 @@ def plt(self):
11971239
import matplotlib.pyplot as plt
11981240
return plt
11991241

1242+
@staticmethod
1243+
def mpl_ge_1_3_1():
1244+
return _mpl_ge_1_3_1()
1245+
1246+
@staticmethod
1247+
def mpl_ge_1_5_0():
1248+
return _mpl_ge_1_5_0()
1249+
12001250
_need_to_set_index = False
12011251

12021252
def _get_xticks(self, convert_period=False):
@@ -1474,9 +1524,6 @@ def __init__(self, data, x, y, s=None, c=None, **kwargs):
14741524
self.c = c
14751525

14761526
def _make_plot(self):
1477-
import matplotlib as mpl
1478-
mpl_ge_1_3_1 = str(mpl.__version__) >= LooseVersion('1.3.1')
1479-
14801527
x, y, c, data = self.x, self.y, self.c, self.data
14811528
ax = self.axes[0]
14821529

@@ -1488,9 +1535,13 @@ def _make_plot(self):
14881535
# pandas uses colormap, matplotlib uses cmap.
14891536
cmap = self.colormap or 'Greys'
14901537
cmap = self.plt.cm.get_cmap(cmap)
1491-
1492-
if c is None:
1538+
color = self.kwds.pop("color", None)
1539+
if c is not None and color is not None:
1540+
raise TypeError('Specify exactly one of `c` and `color`')
1541+
elif c is None and color is None:
14931542
c_values = self.plt.rcParams['patch.facecolor']
1543+
elif color is not None:
1544+
c_values = color
14941545
elif c_is_column:
14951546
c_values = self.data[c].values
14961547
else:
@@ -1505,7 +1556,7 @@ def _make_plot(self):
15051556
if cb:
15061557
img = ax.collections[0]
15071558
kws = dict(ax=ax)
1508-
if mpl_ge_1_3_1:
1559+
if self.mpl_ge_1_3_1():
15091560
kws['label'] = c if c_is_column else ''
15101561
self.fig.colorbar(img, **kws)
15111562

@@ -1636,6 +1687,11 @@ def _ts_plot(cls, ax, x, data, style=None, **kwds):
16361687

16371688
# Set ax with freq info
16381689
_decorate_axes(ax, freq, kwds)
1690+
# digging deeper
1691+
if hasattr(ax, 'left_ax'):
1692+
_decorate_axes(ax.left_ax, freq, kwds)
1693+
if hasattr(ax, 'right_ax'):
1694+
_decorate_axes(ax.right_ax, freq, kwds)
16391695
ax._plot_data.append((data, cls._kind, kwds))
16401696

16411697
lines = cls._plot(ax, data.index, data.values, style=style, **kwds)
@@ -1743,6 +1799,8 @@ def _plot(cls, ax, x, y, style=None, column_num=None,
17431799
if not 'color' in kwds:
17441800
kwds['color'] = lines[0].get_color()
17451801

1802+
if cls.mpl_ge_1_5_0(): # mpl 1.5 added real support for poly legends
1803+
kwds.pop('label')
17461804
ax.fill_between(xdata, start, y_values, **kwds)
17471805
cls._update_stacker(ax, stacking_id, y)
17481806
return lines

pandas/tseries/tests/test_plotting.py

+4
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ def test_gaps(self):
483483
ts[5:25] = np.nan
484484
ax = ts.plot()
485485
lines = ax.get_lines()
486+
tm._skip_if_mpl_1_5()
486487
self.assertEqual(len(lines), 1)
487488
l = lines[0]
488489
data = l.get_xydata()
@@ -532,6 +533,9 @@ def test_gap_upsample(self):
532533
self.assertEqual(len(ax.right_ax.get_lines()), 1)
533534
l = lines[0]
534535
data = l.get_xydata()
536+
537+
tm._skip_if_mpl_1_5()
538+
535539
tm.assertIsInstance(data, np.ma.core.MaskedArray)
536540
mask = data.mask
537541
self.assertTrue(mask[5:25, 1].all())

pandas/util/testing.py

+8
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ def setUpClass(cls):
196196
return cls
197197

198198

199+
def _skip_if_mpl_1_5():
200+
import matplotlib
201+
v = matplotlib.__version__
202+
if v > LooseVersion('1.4.3') or v[0] == '0':
203+
import nose
204+
raise nose.SkipTest("matplotlib 1.5")
205+
206+
199207
def _skip_if_no_scipy():
200208
try:
201209
import scipy.stats

0 commit comments

Comments
 (0)