Skip to content

Commit 5452efc

Browse files
authored
Merge pull request matplotlib#27158 from nbarlowATI/main
First attempt for individual hatching styles for stackplot
2 parents 05ea428 + 914b213 commit 5452efc

File tree

5 files changed

+72
-3
lines changed

5 files changed

+72
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
``hatch`` parameter for stackplot
2+
-------------------------------------------
3+
4+
The `~.Axes.stackplot` *hatch* parameter now accepts a list of strings describing hatching styles that will be applied sequentially to the layers in the stack:
5+
6+
.. plot::
7+
:include-source: true
8+
:alt: Two charts, identified as ax1 and ax2, showing "stackplots", i.e. one-dimensional distributions of data stacked on top of one another. The first plot, ax1 has cross-hatching on all slices, having been given a single string as the "hatch" argument. The second plot, ax2 has different styles of hatching on each slice - diagonal hatching in opposite directions on the first two slices, cross-hatching on the third slice, and open circles on the fourth.
9+
10+
import matplotlib.pyplot as plt
11+
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10,5))
12+
13+
cols = 10
14+
rows = 4
15+
data = (
16+
np.reshape(np.arange(0, cols, 1), (1, -1)) ** 2
17+
+ np.reshape(np.arange(0, rows), (-1, 1))
18+
+ np.random.random((rows, cols))*5
19+
)
20+
x = range(data.shape[1])
21+
ax1.stackplot(x, data, hatch="x")
22+
ax2.stackplot(x, data, hatch=["//","\\","x","o"])
23+
24+
ax1.set_title("hatch='x'")
25+
ax2.set_title("hatch=['//','\\\\','x','o']")
26+
27+
plt.show()

lib/matplotlib/pyplot.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3792,12 +3792,15 @@ def spy(
37923792

37933793
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
37943794
@_copy_docstring_and_deprecators(Axes.stackplot)
3795-
def stackplot(x, *args, labels=(), colors=None, baseline="zero", data=None, **kwargs):
3795+
def stackplot(
3796+
x, *args, labels=(), colors=None, hatch=None, baseline="zero", data=None, **kwargs
3797+
):
37963798
return gca().stackplot(
37973799
x,
37983800
*args,
37993801
labels=labels,
38003802
colors=colors,
3803+
hatch=hatch,
38013804
baseline=baseline,
38023805
**({"data": data} if data is not None else {}),
38033806
**kwargs,

lib/matplotlib/stackplot.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717

1818
def stackplot(axes, x, *args,
19-
labels=(), colors=None, baseline='zero',
19+
labels=(), colors=None, hatch=None, baseline='zero',
2020
**kwargs):
2121
"""
2222
Draw a stacked area plot.
@@ -55,6 +55,15 @@ def stackplot(axes, x, *args,
5555
5656
If not specified, the colors from the Axes property cycle will be used.
5757
58+
hatch : list of str, default: None
59+
A sequence of hatching styles. See
60+
:doc:`/gallery/shapes_and_collections/hatch_style_reference`.
61+
The sequence will be cycled through for filling the
62+
stacked areas from bottom to top.
63+
It need not be exactly the same length as the number
64+
of provided *y*, in which case the styles will repeat from the
65+
beginning.
66+
5867
data : indexable object, optional
5968
DATA_PARAMETER_PLACEHOLDER
6069
@@ -76,6 +85,11 @@ def stackplot(axes, x, *args,
7685
else:
7786
colors = (axes._get_lines.get_next_color() for _ in y)
7887

88+
if hatch is None or isinstance(hatch, str):
89+
hatch = itertools.cycle([hatch])
90+
else:
91+
hatch = itertools.cycle(hatch)
92+
7993
# Assume data passed has not been 'stacked', so stack it here.
8094
# We'll need a float buffer for the upcoming calculations.
8195
stack = np.cumsum(y, axis=0, dtype=np.promote_types(y.dtype, np.float32))
@@ -113,7 +127,9 @@ def stackplot(axes, x, *args,
113127

114128
# Color between x = 0 and the first array.
115129
coll = axes.fill_between(x, first_line, stack[0, :],
116-
facecolor=next(colors), label=next(labels, None),
130+
facecolor=next(colors),
131+
hatch=next(hatch),
132+
label=next(labels, None),
117133
**kwargs)
118134
coll.sticky_edges.y[:] = [0]
119135
r = [coll]
@@ -122,6 +138,7 @@ def stackplot(axes, x, *args,
122138
for i in range(len(y) - 1):
123139
r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :],
124140
facecolor=next(colors),
141+
hatch=next(hatch),
125142
label=next(labels, None),
126143
**kwargs))
127144
return r

lib/matplotlib/stackplot.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def stackplot(
1212
*args: ArrayLike,
1313
labels: Iterable[str] = ...,
1414
colors: Iterable[ColorType] | None = ...,
15+
hatch: Iterable[str] | str | None = ...,
1516
baseline: Literal["zero", "sym", "wiggle", "weighted_wiggle"] = ...,
1617
**kwargs
1718
) -> list[PolyCollection]: ...

lib/matplotlib/tests/test_axes.py

+21
Original file line numberDiff line numberDiff line change
@@ -3084,6 +3084,27 @@ def layers(n, m):
30843084
axs[1, 1].stackplot(range(100), d.T, baseline='weighted_wiggle')
30853085

30863086

3087+
@check_figures_equal()
3088+
def test_stackplot_hatching(fig_ref, fig_test):
3089+
x = np.linspace(0, 10, 10)
3090+
y1 = 1.0 * x
3091+
y2 = 2.0 * x + 1
3092+
y3 = 3.0 * x + 2
3093+
# stackplot with different hatching styles (issue #27146)
3094+
ax_test = fig_test.subplots()
3095+
ax_test.stackplot(x, y1, y2, y3, hatch=["x", "//", "\\\\"], colors=["white"])
3096+
ax_test.set_xlim((0, 10))
3097+
ax_test.set_ylim((0, 70))
3098+
# compare with result from hatching each layer individually
3099+
stack_baseline = np.zeros(len(x))
3100+
ax_ref = fig_ref.subplots()
3101+
ax_ref.fill_between(x, stack_baseline, y1, hatch="x", facecolor="white")
3102+
ax_ref.fill_between(x, y1, y1+y2, hatch="//", facecolor="white")
3103+
ax_ref.fill_between(x, y1+y2, y1+y2+y3, hatch="\\\\", facecolor="white")
3104+
ax_ref.set_xlim((0, 10))
3105+
ax_ref.set_ylim((0, 70))
3106+
3107+
30873108
def _bxp_test_helper(
30883109
stats_kwargs={}, transform_stats=lambda s: s, bxp_kwargs={}):
30893110
np.random.seed(937)

0 commit comments

Comments
 (0)