44import math
55from numbers import Number
66import textwrap
7+ from collections import namedtuple
78
89import numpy as np
910
@@ -926,7 +927,8 @@ class StepPatch(PathPatch):
926927 """
927928 A path patch describing a stepwise constant function.
928929
929- The path is unclosed. It starts and stops at baseline.
930+ By default the path is not closed and starts and stops at
931+ baseline value.
930932 """
931933
932934 _edge_default = False
@@ -945,21 +947,23 @@ def __init__(self, values, edges, *,
945947 between which the curve takes on vals values.
946948
947949 orientation : {'vertical', 'horizontal'}, default: 'vertical'
948- The direction of the steps. Vertical means that *values* are along
949- the y-axis, and edges are along the x-axis.
950+ The direction of the steps. Vertical means that *values* are
951+ along the y-axis, and edges are along the x-axis.
950952
951- baseline : float or None, default: 0
952- Determines starting value of the bounding edges or when
953- ``fill=True``, position of lower edge.
953+ baseline : float, array-like or None, default: 0
954+ The bottom value of the bounding edges or when
955+ ``fill=True``, position of lower edge. If *fill* is
956+ True or an array is passed to *baseline*, a closed
957+ path is drawn.
954958
955959 Other valid keyword arguments are:
956960
957961 %(Patch)s
958962 """
959- self .baseline = baseline
960963 self .orientation = orientation
961964 self ._edges = np .asarray (edges )
962965 self ._values = np .asarray (values )
966+ self ._baseline = np .asarray (baseline ) if baseline is not None else None
963967 self ._update_path ()
964968 super ().__init__ (self ._path , ** kwargs )
965969
@@ -972,13 +976,24 @@ def _update_path(self):
972976 f"`len(values) = { self ._values .size } ` and "
973977 f"`len(edges) = { self ._edges .size } `." )
974978 verts , codes = [], []
975- for idx0 , idx1 in cbook .contiguous_regions (~ np .isnan (self ._values )):
979+
980+ _nan_mask = np .isnan (self ._values )
981+ if self ._baseline is not None :
982+ _nan_mask |= np .isnan (self ._baseline )
983+ for idx0 , idx1 in cbook .contiguous_regions (~ _nan_mask ):
976984 x = np .repeat (self ._edges [idx0 :idx1 + 1 ], 2 )
977985 y = np .repeat (self ._values [idx0 :idx1 ], 2 )
978- if self .baseline is not None :
979- y = np .hstack ((self .baseline , y , self .baseline ))
980- else :
986+ if self ._baseline is None :
981987 y = np .hstack ((y [0 ], y , y [- 1 ]))
988+ elif self ._baseline .ndim == 0 : # single baseline value
989+ y = np .hstack ((self ._baseline , y , self ._baseline ))
990+ elif self ._baseline .ndim == 1 : # baseline array
991+ base = np .repeat (self ._baseline [idx0 :idx1 ], 2 )[::- 1 ]
992+ x = np .concatenate ([x , x [::- 1 ]])
993+ y = np .concatenate ([np .hstack ((base [- 1 ], y , base [0 ],
994+ base [0 ], base , base [- 1 ]))])
995+ else : # no baseline
996+ raise ValueError ('Invalid `baseline` specified' )
982997 if self .orientation == 'vertical' :
983998 xy = np .column_stack ([x , y ])
984999 else :
@@ -988,59 +1003,29 @@ def _update_path(self):
9881003 self ._path = Path (np .vstack (verts ), np .hstack (codes ))
9891004
9901005 def get_data (self ):
991- """Get `.StepPatch` values and edges."""
992- return self ._values , self ._edges
1006+ """Get `.StepPatch` values, edges and baseline as namedtuple."""
1007+ StairData = namedtuple ('StairData' , 'values edges baseline' )
1008+ return StairData (self ._values , self ._edges , self ._baseline )
9931009
994- def set_data (self , values , edges = None ):
1010+ def set_data (self , values = None , edges = None , baseline = None ):
9951011 """
996- Set `.StepPatch` values and optionally edges .
1012+ Set `.StepPatch` values, edges and baseline .
9971013
9981014 Parameters
9991015 ----------
10001016 values : 1D array-like or None
10011017 Will not update values, if passing None
10021018 edges : 1D array-like, optional
1019+ baseline : float, 1D array-like or None
10031020 """
1021+ if values is None and edges is None and baseline is None :
1022+ raise ValueError ("Must set *values*, *edges* or *baseline*." )
10041023 if values is not None :
10051024 self ._values = np .asarray (values )
10061025 if edges is not None :
10071026 self ._edges = np .asarray (edges )
1008- self ._update_path ()
1009- self .stale = True
1010-
1011- def set_values (self , values ):
1012- """
1013- Set `.StepPatch` values.
1014-
1015- Parameters
1016- ----------
1017- values : 1D array-like
1018- """
1019- self .set_data (values , edges = None )
1020-
1021- def set_edges (self , edges ):
1022- """
1023- Set `.StepPatch` edges.
1024-
1025- Parameters
1026- ----------
1027- edges : 1D array-like
1028- """
1029- self .set_data (None , edges = edges )
1030-
1031- def get_baseline (self ):
1032- """Get `.StepPatch` baseline value."""
1033- return self .baseline
1034-
1035- def set_baseline (self , baseline ):
1036- """
1037- Set `.StepPatch` baseline value.
1038-
1039- Parameters
1040- ----------
1041- baseline : float or None
1042- """
1043- self .baseline = baseline
1027+ if baseline is not None :
1028+ self ._baseline = np .asarray (baseline )
10441029 self ._update_path ()
10451030 self .stale = True
10461031
0 commit comments