Skip to content

Commit ed12550

Browse files
authored
Merge pull request #30226 from timhoffm/barcontainer_props
ENH: Add properties bottoms, tops, and position_centers to BarContainer
2 parents d3d59e8 + ac87a72 commit ed12550

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
``BarContainer`` properties
2+
---------------------------
3+
`.BarContainer` gained new properties to easily access coordinates of the bars:
4+
5+
- `~.BarContainer.bottoms`
6+
- `~.BarContainer.tops`
7+
- `~.BarContainer.position_centers`

lib/matplotlib/container.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,48 @@ def __init__(self, patches, errorbar=None, *, datavalues=None,
7373
self.orientation = orientation
7474
super().__init__(patches, **kwargs)
7575

76+
@property
77+
def bottoms(self):
78+
"""
79+
Return the values at the lower end of the bars.
80+
81+
.. versionadded:: 3.11
82+
"""
83+
if self.orientation == 'vertical':
84+
return [p.get_y() for p in self.patches]
85+
elif self.orientation == 'horizontal':
86+
return [p.get_x() for p in self.patches]
87+
else:
88+
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
89+
90+
@property
91+
def tops(self):
92+
"""
93+
Return the values at the upper end of the bars.
94+
95+
.. versionadded:: 3.11
96+
"""
97+
if self.orientation == 'vertical':
98+
return [p.get_y() + p.get_height() for p in self.patches]
99+
elif self.orientation == 'horizontal':
100+
return [p.get_x() + p.get_width() for p in self.patches]
101+
else:
102+
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
103+
104+
@property
105+
def position_centers(self):
106+
"""
107+
Return the centers of bar positions.
108+
109+
.. versionadded:: 3.11
110+
"""
111+
if self.orientation == 'vertical':
112+
return [p.get_x() + p.get_width() / 2 for p in self.patches]
113+
elif self.orientation == 'horizontal':
114+
return [p.get_y() + p.get_height() / 2 for p in self.patches]
115+
else:
116+
raise ValueError("orientation must be 'vertical' or 'horizontal'.")
117+
76118

77119
class ErrorbarContainer(Container):
78120
"""

lib/matplotlib/container.pyi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ class BarContainer(Container):
3232
orientation: Literal["vertical", "horizontal"] | None = ...,
3333
**kwargs
3434
) -> None: ...
35+
@property
36+
def bottoms(self) -> list[float]: ...
37+
@property
38+
def tops(self) -> list[float]: ...
39+
@property
40+
def position_centers(self) -> list[float]: ...
3541

3642
class ErrorbarContainer(Container):
3743
lines: tuple[Line2D, tuple[Line2D, ...], tuple[LineCollection, ...]]

lib/matplotlib/tests/test_container.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
from numpy.testing import assert_array_equal
23
import matplotlib.pyplot as plt
34

45

@@ -35,3 +36,20 @@ def test_nonstring_label():
3536
# Test for #26824
3637
plt.bar(np.arange(10), np.random.rand(10), label=1)
3738
plt.legend()
39+
40+
41+
def test_barcontainer_position_centers__bottoms__tops():
42+
fig, ax = plt.subplots()
43+
pos = [1, 2, 4]
44+
bottoms = np.array([1, 5, 3])
45+
heights = np.array([2, 3, 4])
46+
47+
container = ax.bar(pos, heights, bottom=bottoms)
48+
assert_array_equal(container.position_centers, pos)
49+
assert_array_equal(container.bottoms, bottoms)
50+
assert_array_equal(container.tops, bottoms + heights)
51+
52+
container = ax.barh(pos, heights, left=bottoms)
53+
assert_array_equal(container.position_centers, pos)
54+
assert_array_equal(container.bottoms, bottoms)
55+
assert_array_equal(container.tops, bottoms + heights)

0 commit comments

Comments
 (0)