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

Skip to content

Commit b465911

Browse files
committed
feat: StepPatch to take array as baseline
1 parent 85f6908 commit b465911

File tree

5 files changed

+53
-28
lines changed

5 files changed

+53
-28
lines changed

examples/lines_bars_and_markers/stairs_demo.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343
ax.legend()
4444
plt.show()
4545

46+
#############################################################################
47+
# *baseline* can take an array to allow for stacked histogram plots
48+
49+
A = np.tile([1, 2, 3], (3, 1)) * np.arange(1, 4).reshape(-1, 1)
50+
A = np.vstack([np.zeros(3), A])
51+
52+
for i in range(3):
53+
plt.stairs(A[i+1], baseline=A[i], fill=True)
54+
4655
#############################################################################
4756
# Comparison of `.pyplot.step` and `.pyplot.stairs`
4857
# -------------------------------------------------

lib/matplotlib/axes/_axes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6744,8 +6744,8 @@ def stairs(self, values, edges=None, *,
67446744
The direction of the steps. Vertical means that *values* are along
67456745
the y-axis, and edges are along the x-axis.
67466746
6747-
baseline : float or None, default: 0
6748-
Determines starting value of the bounding edges or when
6747+
baseline : float, array-like or None, default: 0
6748+
Determines bottom value of the bounding edges or when
67496749
``fill=True``, position of lower edge.
67506750
67516751
fill : bool, default: False
@@ -6775,8 +6775,8 @@ def stairs(self, values, edges=None, *,
67756775
if edges is None:
67766776
edges = np.arange(len(values) + 1)
67776777

6778-
edges, values = self._process_unit_info(
6779-
[("x", edges), ("y", values)], kwargs)
6778+
edges, values, baseline = self._process_unit_info(
6779+
[("x", edges), ("y", values), ("y", baseline)], kwargs)
67806780

67816781
patch = mpatches.StepPatch(values,
67826782
edges,
@@ -6788,9 +6788,9 @@ def stairs(self, values, edges=None, *,
67886788
if baseline is None:
67896789
baseline = 0
67906790
if orientation == 'vertical':
6791-
patch.sticky_edges.y.append(baseline)
6791+
patch.sticky_edges.y.append(np.min(baseline))
67926792
else:
6793-
patch.sticky_edges.x.append(baseline)
6793+
patch.sticky_edges.x.append(np.min(baseline))
67946794
self._request_autoscale_view()
67956795
return patch
67966796

lib/matplotlib/patches.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -942,18 +942,18 @@ def __init__(self, values, edges, *,
942942
The direction of the steps. Vertical means that *values* are along
943943
the y-axis, and edges are along the x-axis.
944944
945-
baseline : float or None, default: 0
946-
Determines starting value of the bounding edges or when
945+
baseline : float, 1D array-like or None, default: 0
946+
Determines bottom value of the bounding edges or when
947947
``fill=True``, position of lower edge.
948948
949949
Other valid keyword arguments are:
950950
951951
%(Patch)s
952952
"""
953-
self.baseline = baseline
954953
self.orientation = orientation
955954
self._edges = np.asarray(edges)
956955
self._values = np.asarray(values)
956+
self._baseline = np.asarray(baseline) if baseline is not None else None
957957
self._update_path()
958958
super().__init__(self._path, **kwargs)
959959

@@ -966,13 +966,24 @@ def _update_path(self):
966966
f"`len(values) = {self._values.size}` and "
967967
f"`len(edges) = {self._edges.size}`.")
968968
verts, codes = [], []
969-
for idx0, idx1 in cbook.contiguous_regions(~np.isnan(self._values)):
969+
970+
_nan_mask = np.isnan(self._values)
971+
if self._baseline is not None:
972+
_nan_mask |= np.isnan(self._baseline)
973+
for idx0, idx1 in cbook.contiguous_regions(~_nan_mask):
970974
x = np.repeat(self._edges[idx0:idx1+1], 2)
971975
y = np.repeat(self._values[idx0:idx1], 2)
972-
if self.baseline is not None:
973-
y = np.hstack((self.baseline, y, self.baseline))
974-
else:
976+
if self._baseline is None:
975977
y = np.hstack((y[0], y, y[-1]))
978+
elif self._baseline.ndim == 0: # single baseline value
979+
y = np.hstack((self._baseline, y, self._baseline))
980+
elif self._baseline.ndim == 1: # baseline array
981+
base = np.repeat(self._baseline[idx0:idx1], 2)[::-1]
982+
x = np.concatenate([x, x[::-1]])
983+
y = np.concatenate([np.hstack((base[-1], y, base[0],
984+
base[0], base, base[-1]))])
985+
else: # no baseline
986+
raise ValueError('Invalid `baseline` specified')
976987
if self.orientation == 'vertical':
977988
xy = np.column_stack([x, y])
978989
else:
@@ -982,23 +993,26 @@ def _update_path(self):
982993
self._path = Path(np.vstack(verts), np.hstack(codes))
983994

984995
def get_data(self):
985-
"""Get `.StepPatch` values and edges."""
986-
return self._values, self._edges
996+
"""Get `.StepPatch` values, edges and baseline."""
997+
return self._values, self._edges, self._baseline
987998

988-
def set_data(self, values, edges=None):
999+
def set_data(self, values, edges=None, baseline=None):
9891000
"""
990-
Set `.StepPatch` values and optionally edges.
1001+
Set `.StepPatch` values and optionally edges and baseline.
9911002
9921003
Parameters
9931004
----------
9941005
values : 1D array-like or None
9951006
Will not update values, if passing None
9961007
edges : 1D array-like, optional
1008+
baseline : float, 1D array-like or None
9971009
"""
9981010
if values is not None:
9991011
self._values = np.asarray(values)
10001012
if edges is not None:
10011013
self._edges = np.asarray(edges)
1014+
if baseline is not None:
1015+
self._baseline = np.asarray(baseline)
10021016
self._update_path()
10031017
self.stale = True
10041018

@@ -1010,7 +1024,7 @@ def set_values(self, values):
10101024
----------
10111025
values : 1D array-like
10121026
"""
1013-
self.set_data(values, edges=None)
1027+
self.set_data(values, edges=None, baseline=None)
10141028

10151029
def set_edges(self, edges):
10161030
"""
@@ -1020,23 +1034,21 @@ def set_edges(self, edges):
10201034
----------
10211035
edges : 1D array-like
10221036
"""
1023-
self.set_data(None, edges=edges)
1037+
self.set_data(None, edges=edges, baseline=None)
10241038

10251039
def get_baseline(self):
1026-
"""Get `.StepPatch` baseline value."""
1027-
return self.baseline
1040+
"""Get `.StepPatch` baseline."""
1041+
return self._baseline
10281042

10291043
def set_baseline(self, baseline):
10301044
"""
1031-
Set `.StepPatch` baseline value.
1045+
Set `.StepPatch` baseline.
10321046
10331047
Parameters
10341048
----------
1035-
baseline : float or None
1049+
baseline : float, array-like or None, default: 0
10361050
"""
1037-
self.baseline = baseline
1038-
self._update_path()
1039-
self.stale = True
1051+
self.set_data(None, edges=None, baseline=baseline)
10401052

10411053

10421054
class Polygon(Patch):

lib/matplotlib/tests/test_axes.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1935,10 +1935,14 @@ def test_stairs_options():
19351935
ax.stairs(yn, x, color='orange', ls='--', lw=2, label="C")
19361936
ax.stairs(yn/3, x*3-2, ls='--', lw=2, baseline=0.5,
19371937
orientation='horizontal', label="D")
1938-
ax.stairs(y[::-1]*3+12, x, color='red', ls='--', lw=2, baseline=None,
1938+
ax.stairs(y[::-1]*3+13, x-1, color='red', ls='--', lw=2, baseline=None,
19391939
label="E")
1940+
ax.stairs(y[::-1]*3+14, x, baseline=26,
1941+
color='purple', ls='--', lw=2, label="F")
1942+
ax.stairs(yn[::-1]*3+15, x+1, baseline=np.linspace(27, 25, len(y)),
1943+
color='blue', ls='--', lw=2, label="G", fill=True)
19401944
ax.stairs(y[:-1][::-1]*2+11, x[:-1]+0.5, color='black', ls='--', lw=2,
1941-
baseline=12, hatch='//', label="F")
1945+
baseline=12, hatch='//', label="H")
19421946
ax.legend(loc=0)
19431947

19441948

0 commit comments

Comments
 (0)