Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ec8f5f7

Browse files
committed
Do deprecation better
1 parent 72131a9 commit ec8f5f7

File tree

5 files changed

+79
-33
lines changed

5 files changed

+79
-33
lines changed

doc/api/api_changes/2017-10-24-DS.rst

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
`StemContainer` now stores `LineCollection`
2+
-------------------------------------------
3+
4+
`StemContainer` objects can now store a `LineCollection` object instead of a
5+
list of `Line2D` objects for stem lines plotted using `ax.stem`. This gives a
6+
very large performance boost to displaying and moving `ax.stem` plots.
7+
8+
This will become the default behaviour in Matplotlib 3.3. To use it now, the
9+
``use_line_collection`` keyword argument to ~`.axes.stem` can be set to
10+
``True``.
11+
12+
Individual line segments can be extracted from the `LineCollection` using
13+
`LineCollection.get_segements()`. See the `LineCollection` documentation for
14+
other methods to retrieve the collection properties.

lib/matplotlib/axes/_axes.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,7 +2524,7 @@ def broken_barh(self, xranges, yrange, **kwargs):
25242524

25252525
@_preprocess_data(replace_all_args=True, label_namer=None)
25262526
def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None,
2527-
bottom=0, label=None):
2527+
bottom=0, label=None, use_line_collection=False):
25282528
"""
25292529
Create a stem plot.
25302530
@@ -2583,6 +2583,12 @@ def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None,
25832583
label : str, optional, default: None
25842584
The label to use for the stems in legends.
25852585
2586+
use_line_collection : bool, optional, default: False
2587+
If ``True``, store and plot the stem lines as a
2588+
~`.collections.LineCollection` instead of individual lines. This
2589+
significantly increases performance, and will become the default
2590+
option in Matplotlib 3.3. If ``False``, defaults to old behaviour.
2591+
25862592
25872593
Returns
25882594
-------
@@ -2665,24 +2671,40 @@ def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None,
26652671
else:
26662672
basestyle, basemarker, basecolor = _process_plot_format(basefmt)
26672673

2674+
# New behaviour in 3.1 is to use a LineCollection for the stemlines
2675+
if use_line_collection:
2676+
stemlines = []
2677+
for thisx, thisy in zip(x, y):
2678+
stemlines.append(((thisx, bottom), (thisx, thisy)))
2679+
stemlines = mcoll.LineCollection(stemlines, linestyles=linestyle,
2680+
colors=linecolor,
2681+
label='_nolegend_')
2682+
self.add_collection(stemlines)
2683+
# Old behaviour is to plot each of the lines individually
2684+
else:
2685+
warnings.warn(
2686+
'In Matplotlib 3.3 individual lines on a stem plot will be '
2687+
'added as a LineCollection instead of individual lines.\n'
2688+
'This significantly improves the performance of a stem plot.\n'
2689+
'To remove this warning and switch to the new behaviour, '
2690+
'set the "use_line_collection" keyword argument to True.')
2691+
stemlines = []
2692+
for thisx, thisy in zip(x, y):
2693+
l, = self.plot([thisx, thisx], [bottom, thisy],
2694+
color=linecolor, linestyle=linestyle,
2695+
marker=linemarker, label="_nolegend_")
2696+
stemlines.append(l)
2697+
26682698
markerline, = self.plot(x, y, color=markercolor, linestyle=markerstyle,
26692699
marker=markermarker, label="_nolegend_")
26702700

2671-
lines = []
2672-
for thisx, thisy in zip(x, y):
2673-
lines.append(((thisx, bottom), (thisx, thisy)))
2674-
stemlines = mcoll.LineCollection(lines, linestyles=linestyle,
2675-
colors=linecolor, label='_nolegend_')
2676-
self.add_collection(stemlines)
2677-
26782701
baseline, = self.plot([np.min(x), np.max(x)], [bottom, bottom],
26792702
color=basecolor, linestyle=basestyle,
26802703
marker=basemarker, label="_nolegend_")
26812704

26822705
stem_container = StemContainer((markerline, stemlines, baseline),
26832706
label=label)
26842707
self.add_container(stem_container)
2685-
26862708
return stem_container
26872709

26882710
@_preprocess_data(replace_names=["x", "explode", "labels", "colors"],

lib/matplotlib/legend_handler.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,10 @@ def create_artists(self, legend, orig_handle,
590590
xdescent, ydescent, width, height, fontsize,
591591
trans):
592592
markerline, stemlines, baseline = orig_handle
593+
# Check to see if the stemcontainer is storing lines as a list or a
594+
# LineCollection. Eventually using a list will be removed, and this
595+
# logic can also be removed.
596+
using_linecoll = isinstance(stemlines, mcoll.LineCollection)
593597

594598
xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
595599
width, height, fontsize)
@@ -604,17 +608,24 @@ def create_artists(self, legend, orig_handle,
604608

605609
leg_stemlines = []
606610

607-
# update_prop() usually takes two Line2D collections;
608-
# override temporarily to copy properties from a LineCollection
609-
orig_update_func = self._update_prop_func
610-
self._update_prop_func = self._copy_collection_props
611-
612-
for thisx, thisy in zip(xdata_marker, ydata):
613-
thisline = Line2D([thisx, thisx], [bottom, thisy])
614-
leg_stemlines.append(thisline)
615-
self.update_prop(thisline, stemlines, legend)
616-
# Reset update_prop_func
617-
self._update_prop_func = orig_update_func
611+
if using_linecoll:
612+
# update_prop() usually takes two Line2D collections;
613+
# override temporarily to copy properties from a LineCollection
614+
orig_update_func = self._update_prop_func
615+
self._update_prop_func = self._copy_collection_props
616+
617+
for thisx, thisy in zip(xdata_marker, ydata):
618+
thisline = Line2D([thisx, thisx], [bottom, thisy])
619+
leg_stemlines.append(thisline)
620+
self.update_prop(thisline, stemlines, legend)
621+
622+
self._update_prop_func = orig_update_func
623+
else:
624+
for thisx, thisy in zip(xdata_marker, ydata):
625+
thisline = Line2D([thisx, thisx], [bottom, thisy])
626+
leg_stemlines.append(thisline)
627+
for lm, m in zip(leg_stemlines, stemlines):
628+
self.update_prop(lm, m, legend)
618629

619630
leg_baseline = Line2D([np.min(xdata), np.max(xdata)],
620631
[bottom, bottom])

lib/matplotlib/tests/test_axes.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,14 +2958,23 @@ def test_hist_stacked_weighted():
29582958
ax.hist((d1, d2), weights=(w1, w2), histtype="stepfilled", stacked=True)
29592959

29602960

2961+
@pytest.mark.parametrize("use_line_collection", [True, False],
2962+
ids=['w/ line collection', 'w/o line collection'])
29612963
@image_comparison(baseline_images=['stem'], extensions=['png'], style='mpl20',
29622964
remove_text=True)
2963-
def test_stem():
2965+
def test_stem(use_line_collection):
29642966
x = np.linspace(0.1, 2 * np.pi, 100)
2967+
args = (x, np.cos(x))
2968+
kwargs = dict(linefmt='C2-', markerfmt='k+', basefmt='C1-.',
2969+
label='Stem', use_line_collection=use_line_collection)
29652970

29662971
fig, ax = plt.subplots()
2967-
ax.stem(x, np.cos(x), linefmt='C2-', markerfmt='k+', basefmt='C1-.',
2968-
label='Stem')
2972+
if use_line_collection:
2973+
ax.stem(*args, **kwargs)
2974+
else:
2975+
with pytest.warns(UserWarning):
2976+
ax.stem(*args, **kwargs)
2977+
29692978
ax.legend()
29702979

29712980

0 commit comments

Comments
 (0)