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

Skip to content

Commit 8d2c16b

Browse files
authored
Merge pull request #17767 from dstansby/bar-hatch
ENH: Allow list of hatches to {bar, barh}
2 parents 3a67529 + 78c4619 commit 8d2c16b

4 files changed

Lines changed: 46 additions & 14 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
A list of hatches can be specified to `~.axes.Axes.bar` and `~.axes.Axes.barh`
2+
------------------------------------------------------------------------------
3+
4+
Similar to some other rectangle properties, it is now possible to hand a list
5+
of hatch styles to `~.axes.Axes.bar` and `~.axes.Axes.barh` in order to create
6+
bars with different hatch styles, e.g.
7+
8+
.. plot::
9+
10+
import matplotlib.pyplot as plt
11+
12+
fig, ax = plt.subplots()
13+
ax.bar([1, 2], [2, 3], hatch=['+', 'o'])
14+
plt.show()

examples/shapes_and_collections/hatch_demo.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,24 @@
66
Hatching (pattern filled polygons) is supported currently in the PS,
77
PDF, SVG and Agg backends only.
88
"""
9+
import numpy as np
910
import matplotlib.pyplot as plt
1011
from matplotlib.patches import Ellipse, Polygon
1112

13+
x = np.arange(1, 5)
14+
y1 = np.arange(1, 5)
15+
y2 = np.ones(y1.shape) * 4
16+
1217
fig, (ax1, ax2, ax3) = plt.subplots(3)
1318

14-
ax1.bar(range(1, 5), range(1, 5), color='red', edgecolor='black', hatch="/")
15-
ax1.bar(range(1, 5), [6] * 4, bottom=range(1, 5),
16-
color='blue', edgecolor='black', hatch='//')
19+
ax1.bar(x, y1, edgecolor='black', hatch="/")
20+
ax1.bar(x, y2, bottom=y1, edgecolor='black', hatch='//')
1721
ax1.set_xticks([1.5, 2.5, 3.5, 4.5])
1822

19-
bars = ax2.bar(range(1, 5), range(1, 5), color='yellow', ecolor='black') + \
20-
ax2.bar(range(1, 5), [6] * 4, bottom=range(1, 5),
21-
color='green', ecolor='black')
23+
ax2.bar(x, y1, edgecolor='black', hatch=['-', '+', 'x', '\\'])
24+
ax2.bar(x, y2, bottom=y1, edgecolor='black', hatch=['*', 'o', 'O', '.'])
2225
ax2.set_xticks([1.5, 2.5, 3.5, 4.5])
2326

24-
patterns = ('-', '+', 'x', '\\', '*', 'o', 'O', '.')
25-
for bar, pattern in zip(bars, patterns):
26-
bar.set_hatch(pattern)
27-
2827
ax3.fill([1, 3, 3, 1], [1, 1, 2, 2], fill=False, hatch='\\')
2928
ax3.add_patch(Ellipse((4, 1.5), 4, 0.5, fill=False, hatch='*'))
3029
ax3.add_patch(Polygon([[0, 0], [4, 1.1], [6, 2.5], [2, 1.4]], closed=True,

lib/matplotlib/axes/_axes.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,7 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
23662366
color = self._get_patches_for_fill.get_next_color()
23672367
edgecolor = kwargs.pop('edgecolor', None)
23682368
linewidth = kwargs.pop('linewidth', None)
2369+
hatch = kwargs.pop('hatch', None)
23692370

23702371
# Because xerr and yerr will be passed to errorbar, most dimension
23712372
# checking and processing will be left to the errorbar method.
@@ -2427,9 +2428,9 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
24272428
if yerr is not None:
24282429
yerr = self._convert_dx(yerr, y0, y, self.convert_yunits)
24292430

2430-
x, height, width, y, linewidth = np.broadcast_arrays(
2431+
x, height, width, y, linewidth, hatch = np.broadcast_arrays(
24312432
# Make args iterable too.
2432-
np.atleast_1d(x), height, width, y, linewidth)
2433+
np.atleast_1d(x), height, width, y, linewidth, hatch)
24332434

24342435
# Now that units have been converted, set the tick locations.
24352436
if orientation == 'vertical':
@@ -2440,6 +2441,7 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
24402441
tick_label_position = y
24412442

24422443
linewidth = itertools.cycle(np.atleast_1d(linewidth))
2444+
hatch = itertools.cycle(np.atleast_1d(hatch))
24432445
color = itertools.chain(itertools.cycle(mcolors.to_rgba_array(color)),
24442446
# Fallback if color == "none".
24452447
itertools.repeat('none'))
@@ -2476,14 +2478,16 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
24762478
bottom = y
24772479

24782480
patches = []
2479-
args = zip(left, bottom, width, height, color, edgecolor, linewidth)
2480-
for l, b, w, h, c, e, lw in args:
2481+
args = zip(left, bottom, width, height, color, edgecolor, linewidth,
2482+
hatch)
2483+
for l, b, w, h, c, e, lw, htch in args:
24812484
r = mpatches.Rectangle(
24822485
xy=(l, b), width=w, height=h,
24832486
facecolor=c,
24842487
edgecolor=e,
24852488
linewidth=lw,
24862489
label='_nolegend_',
2490+
hatch=htch,
24872491
)
24882492
r.update(kwargs)
24892493
r.get_path()._interpolation_steps = 100

lib/matplotlib/tests/test_axes.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,21 @@ def test_bar_pandas_indexed(pd):
15511551
ax.bar(df.x, 1., width=df.width)
15521552

15531553

1554+
@check_figures_equal()
1555+
@pytest.mark.style('default')
1556+
def test_bar_hatches(fig_test, fig_ref):
1557+
ax_test = fig_test.subplots()
1558+
ax_ref = fig_ref.subplots()
1559+
1560+
x = [1, 2]
1561+
y = [2, 3]
1562+
hatches = ['x', 'o']
1563+
for i in range(2):
1564+
ax_ref.bar(x[i], y[i], color='C0', hatch=hatches[i])
1565+
1566+
ax_test.bar(x, y, hatch=hatches)
1567+
1568+
15541569
def test_pandas_minimal_plot(pd):
15551570
# smoke test that series and index objcets do not warn
15561571
x = pd.Series([1, 2], dtype="float64")

0 commit comments

Comments
 (0)