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

Skip to content

Commit 67c15ec

Browse files
committed
feat: Add histline tests + cleanup
1 parent 467683d commit 67c15ec

File tree

6 files changed

+717
-61
lines changed

6 files changed

+717
-61
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6871,18 +6871,52 @@ def hist(self, x, bins=None, range=None, density=False, weights=None,
68716871
else "List[Polygon]")
68726872
return tops, bins, cbook.silent_list(patch_type, patches)
68736873

6874+
@_preprocess_data()
68746875
def histline(self, vals, bins=None, *,
6875-
orientation='horizontal', baseline=0, fill=False, **kwargs):
6876+
orientation='vertical', baseline=0, fill=False, **kwargs):
6877+
"""
6878+
A histogram-like line or filled plot.
68766879
6877-
_color = self._get_lines.get_next_color()
6878-
if not fill:
6879-
kwargs.setdefault('edgecolor', _color)
6880+
Parameters
6881+
----------
6882+
vals : array
6883+
An array of y-values.
6884+
6885+
bins : array, default: ``range(len(vals)+1)``
6886+
A array of x-values, with ``len(bins) == len(vals) + 1``,
6887+
between which the curve takes on vals values.
6888+
6889+
orientation : {'vertical', 'horizontal'}, default: 'vertical'
6890+
6891+
baseline : float or None, default: 0
6892+
Determines starting value of the bounding edges or when
6893+
"fill" == True, position of lower edge.
6894+
6895+
fill : bool, default: False
6896+
6897+
Returns
6898+
-------
6899+
patch : `.StepPatch`
6900+
6901+
Other Parameters
6902+
----------------
6903+
**kwargs
6904+
`~matplotlib.patches.Patch` properties
6905+
6906+
"""
6907+
6908+
if 'color' in kwargs:
6909+
_color = kwargs.pop('color')
68806910
else:
6911+
_color = self._get_lines.get_next_color()
6912+
if fill:
68816913
kwargs.setdefault('edgecolor', 'none')
68826914
kwargs.setdefault('facecolor', _color)
6915+
else:
6916+
kwargs.setdefault('edgecolor', _color)
68836917

68846918
if bins is None:
6885-
bins = np.arange(len(vals)+1)
6919+
bins = np.arange(len(vals) + 1)
68866920

68876921
patch = mpatches.StepPatch(vals,
68886922
bins,
@@ -6891,18 +6925,15 @@ def histline(self, vals, bins=None, *,
68916925
fill=fill,
68926926
**kwargs)
68936927
self.add_patch(patch)
6894-
68956928
if baseline is None:
68966929
baseline = 0
6897-
if orientation == 'horizontal':
6930+
if orientation == 'vertical':
68986931
patch.sticky_edges.y.append(baseline)
68996932
else:
69006933
patch.sticky_edges.x.append(baseline)
6901-
69026934
self._request_autoscale_view()
69036935
return patch
69046936

6905-
69066937
@_preprocess_data(replace_names=["x", "y", "weights"])
69076938
@docstring.dedent_interpd
69086939
def hist2d(self, x, y, bins=10, range=None, density=False, weights=None,

lib/matplotlib/legend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ def draw(self, renderer):
624624
ErrorbarContainer: legend_handler.HandlerErrorbar(),
625625
Line2D: legend_handler.HandlerLine2D(),
626626
Patch: legend_handler.HandlerPatch(),
627-
StepPatch: legend_handler.HandlerLinePatch(),
627+
StepPatch: legend_handler.HandlerStepPatch(),
628628
LineCollection: legend_handler.HandlerLineCollection(),
629629
RegularPolyCollection: legend_handler.HandlerRegularPolyCollection(),
630630
CircleCollection: legend_handler.HandlerCircleCollection(),

lib/matplotlib/legend_handler.py

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -302,44 +302,24 @@ def create_artists(self, legend, orig_handle,
302302
return [p]
303303

304304

305-
class HandlerLinePatch(HandlerBase):
305+
class HandlerStepPatch(HandlerBase):
306306
"""
307-
Handler for `.HistLine` instances.
307+
Handler for `.StepPatch` instances.
308308
"""
309-
def __init__(self, patch_func=None, **kw):
309+
def __init__(self, **kw):
310310
"""
311-
Parameters
312-
----------
313-
patch_func : callable, optional
314-
The function that creates the legend key artist.
315-
*patch_func* should have the signature::
316-
317-
def patch_func(legend=legend, orig_handle=orig_handle,
318-
xdescent=xdescent, ydescent=ydescent,
319-
width=width, height=height, fontsize=fontsize)
320-
321-
Subsequently the created artist will have its ``update_prop``
322-
method called and the appropriate transform will be applied.
323-
324-
Notes
325-
-----
326311
Any other keyword arguments are given to `HandlerBase`.
327312
"""
328313
super().__init__(**kw)
329-
self._patch_func = patch_func
330314

331315
def _create_patch(self, legend, orig_handle,
332316
xdescent, ydescent, width, height, fontsize):
333-
if self._patch_func is None:
334-
p = Rectangle(xy=(-xdescent, -ydescent),
335-
color=orig_handle.get_facecolor(),
336-
width=width, height=height)
337-
else:
338-
p = self._patch_func(legend=legend, orig_handle=orig_handle,
339-
xdescent=xdescent, ydescent=ydescent,
340-
width=width, height=height, fontsize=fontsize)
317+
p = Rectangle(xy=(-xdescent, -ydescent),
318+
color=orig_handle.get_facecolor(),
319+
width=width, height=height)
341320
return p
342321

322+
# Unfilled StepPatch should show as a line
343323
def _create_line(self, legend, orig_handle,
344324
xdescent, ydescent, width, height, fontsize):
345325

@@ -356,15 +336,14 @@ def _create_line(self, legend, orig_handle,
356336

357337
def create_artists(self, legend, orig_handle,
358338
xdescent, ydescent, width, height, fontsize, trans):
359-
if orig_handle.get_fill():
339+
if orig_handle.get_fill() or (orig_handle.get_hatch() is not None):
360340
p = self._create_patch(legend, orig_handle,
361341
xdescent, ydescent, width, height, fontsize)
362342
self.update_prop(p, orig_handle, legend)
363343
else:
364344
p = self._create_line(legend, orig_handle,
365345
xdescent, ydescent, width, height, fontsize)
366346
p.set_transform(trans)
367-
368347
return [p]
369348

370349

lib/matplotlib/patches.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -990,72 +990,71 @@ def set_path(self, path):
990990

991991

992992
class StepPatch(PathPatch):
993-
"""A stepline path patch."""
993+
"""An unclosed stepline path patch."""
994994

995995
@docstring.dedent_interpd
996-
def __init__(self, vals, bins=None, *,
996+
def __init__(self, vals, edges, *,
997997
orientation='horizontal', baseline=0, **kwargs):
998998
"""
999999
Parameters
10001000
----------
1001-
vals : array, len N
1001+
vals : array
10021002
An array of y-values.
10031003
1004-
bins : array, len N+1
1005-
A array of x-values, between which the curve takes on
1006-
vals values.
1004+
edges : array
1005+
A array of x-value edges, with ``len(edges) == len(vals) + 1``,
1006+
between which the curve takes on vals values.
10071007
10081008
orientation : {'vertical', 'horizontal'}, default: 'vertical'
10091009
10101010
baseline : float or None, default: 0
10111011
Determines starting value of the bounding edges or when
10121012
"fill" == True, position of lower edge.
10131013
1014-
**kwargs
1015-
`Patch` properties:
1014+
Other valid keyword arguments are:
10161015
1017-
%(Patch)s
1016+
%(Patch)s
10181017
"""
10191018
self.baseline = baseline
10201019
self.orientation = orientation
1021-
self._bins = bins
1022-
self._vals = vals
1020+
self._edges = np.asarray(edges)
1021+
self._vals = np.asarray(vals)
10231022
verts, codes = self._update_data()
10241023
path = Path(verts, codes)
10251024
super().__init__(path, **kwargs)
10261025

10271026
def _update_data(self):
1028-
if self._bins.size - 1 != self._vals.size:
1029-
raise ValueError('the length of the bins is wrong')
1027+
if self._edges.size - 1 != self._vals.size:
1028+
raise ValueError('Size mismatch between "vals" and "edges"')
10301029
verts, codes = [], []
10311030
for idx0, idx1 in cbook.contiguous_regions(~np.isnan(self._vals)):
1032-
x = np.vstack((self._bins[idx0:idx1+1],
1033-
self._bins[idx0:idx1+1])).T.flatten()
1031+
x = np.vstack((self._edges[idx0:idx1+1],
1032+
self._edges[idx0:idx1+1])).T.flatten()
10341033
y = np.vstack((self._vals[idx0:idx1],
10351034
self._vals[idx0:idx1])).T.flatten()
10361035
if self.baseline is not None:
10371036
y = np.hstack((self.baseline, y, self.baseline))
10381037
else:
10391038
y = np.hstack((y[0], y, y[-1]))
1040-
if self.orientation == 'horizontal':
1039+
if self.orientation == 'vertical':
10411040
xy = np.vstack([x, y]).T
10421041
else:
10431042
xy = np.vstack([y, x]).T
10441043
verts.append(xy)
10451044
codes.append(np.array([Path.MOVETO] + [Path.LINETO]*(len(xy)-1)))
10461045
return np.vstack(verts), np.hstack(codes)
10471046

1048-
def set_bins(self, bins):
1049-
self._bins = bins
1047+
def set_edges(self, edges):
1048+
self._edges = np.asarray(edges)
10501049
self._update_data()
10511050

10521051
def set_vals(self, vals):
1053-
self._vals = vals
1052+
self._vals = np.asarray(vals)
10541053
self._update_data()
10551054

1056-
def set_vals_bins(self, vals, bins):
1057-
self._vals = vals
1058-
self._bins = bins
1055+
def set_vals_edges(self, vals, edges):
1056+
self._vals = np.asarray(vals)
1057+
self._edegs = np.asarray(edges)
10591058
self._update_data()
10601059

10611060

0 commit comments

Comments
 (0)