You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
add drawstyle option to fill_between function #643
I notice lines have a drawstyle, but patches do not. In short, to implement this functionality, I believe one would want to implement drawstyles on patches.
I don't think it's needed to implement drawstyles on patches (this is probably not well defined anyway). One should rather get back the x,y coordinates of the step-lines (i.e [x0,x1,x1,x2,x2,...],[y0,y0,y1,y1,y2,...]) and give it to fill_between.
Hello,
I am the one who wrote the request linked in the original post, and I still frequently run into situations where it would be handy to have. I see a few feature requests here that have not been active for half a year or so, how should we interpret this?
I think what would need to be done is a MEP describing exactly what a drawstyle would mean for a Patch object. I am not familiar enough with what exactly a drawstyle means (as opposed to a linestyle). Should it also be included for Polygons? What about Collections? These things need to be worked out prior to adding the top-level feature to fill_between.
I don't think drawstyles on all patches makes sense (on an ellipse? what would that mean?). However, it may make sense to have a "FilledLine" class that inherits from line, except is filled above or below (maybe left or right as well). This would then get all of the features of Line.
Maybe go a different route and add a drawstyle keyword to the function rather than the object, and return a simple Patch object? The cost would of course be that you couldn't easily change from filled-steps to normal fill-between, but at least it would make it relatively simple to create said filled step plot. At least in my case, having the simple functionality is really all that matters.
I made a little convenience function that works in most cases - it's primitive but gets the work done, and that is what I care about right now. https://gist.github.com/thriveth/8352565
@thriveth What cases does that method not work in?
Copied the code (with minor edit to fix return value) from the linked just below just in case.
def fill_between_steps(x, y1, y2=0, h_align='mid', ax=None, **kwargs):
''' Fills a hole in matplotlib: Fill_between for step plots.
Parameters :
------------
x : array-like
Array/vector of index values. These are assumed to be equally-spaced.
If not, the result will probably look weird...
y1 : array-like
Array/vector of values to be filled under.
y2 : array-Like
Array/vector or bottom values for filled area. Default is 0.
**kwargs will be passed to the matplotlib fill_between() function.
'''
# If no Axes opject given, grab the current one:
if ax is None:
ax = plt.gca()
# First, duplicate the x values
xx = x.repeat(2)[1:]
# Now: the average x binwidth
xstep = (x[1:] - x[:-1]).mean()
# Now: add one step at end of row.
xx = sp.append(xx, xx.max() + xstep)
# Make it possible to change step alignment.
if h_align == 'mid':
xx -= xstep / 2.
elif h_align == 'right':
xx -= xstep
# Also, duplicate each y coordinate in both arrays
y1 = y1.repeat(2)
if type(y2) == sp.ndarray:
y2 = y2.repeat(2)
# now to the plotting part:
return ax.fill_between(xx, y1, y2=y2, **kwargs)
@tacaswell For one thing, it only works for evenly spaced data points. I suspect it should be possible to extend so it would work for unevenly spaced data too but I haven\t had any need for it so far so I have not looked into it.
My workaround for this uses PathPatch which has the ability to handle nonuniform steps - also the potential to create a collection which allows the blending of alphas (needed when rasterizing for use in eps figures). Here is a quick and dirty example. One could change y0 to an array and have the points iterate backwards to complete the path if you really wanted fill between two "curves" and not just fill between the data and a constant value.
When creating these plots, I typically use the keyword "polygon" for drawstyle. This might be the word you are looking for here, or it might be too general since all the angles are 90 degrees.
Turns out, my function was fairly simple to generalize to unevenly spaced data. I have updated the gist and include the code below.
deffill_between_steps(x, y1, y2=0, h_align='mid', ax=None, **kwargs):
''' Fills a hole in matplotlib: fill_between for step plots. Parameters : ------------ x : array-like Array/vector of index values. These are assumed to be equally-spaced. If not, the result will probably look weird... y1 : array-like Array/vector of values to be filled under. y2 : array-Like Array/vector or bottom values for filled area. Default is 0. **kwargs will be passed to the matplotlib fill_between() function. '''# If no Axes opject given, grab the current one:ifaxisNone:
ax=plt.gca()
# First, duplicate the x valuesxx=x.repeat(2)[1:]
# Now: the average x binwidthxstep=sp.repeat((x[1:] -x[:-1]), 2)
xstep=sp.concatenate(([xstep[0]], xstep, [xstep[-1]]))
# Now: add one step at end of row.xx=sp.append(xx, xx.max() +xstep[-1])
# Make it possible to chenge step alignment.ifh_align=='mid':
xx-=xstep/2.elifh_align=='right':
xx-=xstep# Also, duplicate each y coordinate in both arraysy1=y1.repeat(2)#[:-1]iftype(y2) ==sp.ndarray:
y2=y2.repeat(2)#[:-1]# now to the plotting part:ax.fill_between(xx, y1, y2=y2, **kwargs)
returnax
This still takes all the samme keywords as fill_between.
Here is an example, with a plot of the lower data in orange with drawstyle='steps-mid' set, they match very nicely.
Here is a more complete solution which deals with all of the stepping methods of
deffill_between_steps(ax, x, y1, y2=0, step_where='pre', **kwargs):
''' fill between a step plot and Parameters ---------- ax : Axes The axes to draw to x : array-like Array/vector of index values. y1 : array-like or float Array/vector of values to be filled under. y2 : array-Like or float, optional Array/vector or bottom values for filled area. Default is 0. step_where : {'pre', 'post', 'mid'} where the step happens, same meanings as for `step` **kwargs will be passed to the matplotlib fill_between() function. Returns ------- ret : PolyCollection The added artist '''ifstep_wherenotin {'pre', 'post', 'mid'}:
raiseValueError("where must be one of {{'pre', 'post', 'mid'}} ""You passed in {wh}".format(wh=step_where))
# make sure y values are up-converted to arrays ifnp.isscalar(y1):
y1=np.ones_like(x) *y1ifnp.isscalar(y2):
y2=np.ones_like(x) *y2# temporary array for up-converting the values to step corners# 3 x 2N - 1 array vertices=np.vstack((x, y1, y2))
# this logic is lifted from lines.py# this should probably be centralized someplaceifstep_where=='pre':
steps=ma.zeros((3, 2*len(x) -1), np.float)
steps[0, 0::2], steps[0, 1::2] =vertices[0, :], vertices[0, :-1]
steps[1:, 0::2], steps[1:, 1:-1:2] =vertices[1:, :], vertices[1:, 1:]
elifstep_where=='post':
steps=ma.zeros((3, 2*len(x) -1), np.float)
steps[0, ::2], steps[0, 1:-1:2] =vertices[0, :], vertices[0, 1:]
steps[1:, 0::2], steps[1:, 1::2] =vertices[1:, :], vertices[1:, :-1]
elifstep_where=='mid':
steps=ma.zeros((3, 2*len(x)), np.float)
steps[0, 1:-1:2] =0.5* (vertices[0, :-1] +vertices[0, 1:])
steps[0, 2::2] =0.5* (vertices[0, :-1] +vertices[0, 1:])
steps[0, 0] =vertices[0, 0]
steps[0, -1] =vertices[0, -1]
steps[1:, 0::2], steps[1:, 1::2] =vertices[1:, :], vertices[1:, :]
else:
raiseRuntimeError("should never hit end of if-elif block for validated input")
# un-packxx, yy1, yy2=steps# now to the plotting part:returnax.fill_between(xx, yy1, y2=yy2, **kwargs)
fig, ax_list=plt. subplots(3, 1)
x=y=np.arange(5)
forax, whereinzip(ax_list, ['pre', 'post', 'mid']):
ax.step(x, y, where=where, color='r', zorder=5, lw=5)
fill_between_steps(ax, x, y, 0, step_where=where)
I will get around to putting this in a PR eventually
This would be a very nice addition, @tacaswell do you think this would be implemented soon? I've written something similar myself (and step style is more or less required in my field, so I'm sure quite a few others have as well), but it would be great to see a standard solution.
I would just use the function above for now. The only hold up is I am not sure if this should be it's own function step_fill_between or as a flag in the current fill_between.
Great solution @tacaswell. I would additionally request the ability to specify N+1 step edges for N step values. Currently I am using your solution by plotting the first bin with step_where='post', then the remaining bins with step_where='pre'. Also, the poly collection that is specified by fill_between does not support legend(), which is unfortunate.
Activity
astrofrog commentedon Jul 8, 2012
+1
pelson commentedon Sep 2, 2012
I notice lines have a drawstyle, but patches do not. In short, to implement this functionality, I believe one would want to implement drawstyles on patches.
ycopin commentedon Oct 8, 2012
+1
I don't think it's needed to implement drawstyles on patches (this is probably not well defined anyway). One should rather get back the x,y coordinates of the step-lines (i.e [x0,x1,x1,x2,x2,...],[y0,y0,y1,y1,y2,...]) and give it to
fill_between.thriveth commentedon Sep 25, 2013
Hello,
I am the one who wrote the request linked in the original post, and I still frequently run into situations where it would be handy to have. I see a few feature requests here that have not been active for half a year or so, how should we interpret this?
WeatherGod commentedon Oct 1, 2013
I think what would need to be done is a MEP describing exactly what a drawstyle would mean for a Patch object. I am not familiar enough with what exactly a drawstyle means (as opposed to a linestyle). Should it also be included for Polygons? What about Collections? These things need to be worked out prior to adding the top-level feature to fill_between.
mdboom commentedon Oct 1, 2013
I don't think drawstyles on all patches makes sense (on an ellipse? what would that mean?). However, it may make sense to have a "FilledLine" class that inherits from line, except is filled above or below (maybe left or right as well). This would then get all of the features of Line.
thriveth commentedon Oct 1, 2013
Maybe go a different route and add a
drawstylekeyword to the function rather than the object, and return a simple Patch object? The cost would of course be that you couldn't easily change from filled-steps to normal fill-between, but at least it would make it relatively simple to create said filled step plot. At least in my case, having the simple functionality is really all that matters.thriveth commentedon Jan 10, 2014
Any news about this?
I made a little convenience function that works in most cases - it's primitive but gets the work done, and that is what I care about right now. https://gist.github.com/thriveth/8352565

tacaswell commentedon Aug 18, 2014
@thriveth What cases does that method not work in?
Copied the code (with minor edit to fix return value) from the linked just below just in case.
thriveth commentedon Aug 25, 2014
@tacaswell I don't know if there are any, I just haven't tested it thoroughly. But I am using that method extensively in my current work.
thriveth commentedon Aug 25, 2014
@tacaswell For one thing, it only works for evenly spaced data points. I suspect it should be possible to extend so it would work for unevenly spaced data too but I haven\t had any need for it so far so I have not looked into it.
theodoregoetz commentedon Sep 4, 2014
My workaround for this uses PathPatch which has the ability to handle nonuniform steps - also the potential to create a collection which allows the blending of alphas (needed when rasterizing for use in eps figures). Here is a quick and dirty example. One could change y0 to an array and have the points iterate backwards to complete the path if you really wanted fill between two "curves" and not just fill between the data and a constant value.
When creating these plots, I typically use the keyword "polygon" for drawstyle. This might be the word you are looking for here, or it might be too general since all the angles are 90 degrees.
theodoregoetz commentedon Sep 4, 2014
For completeness, here is an example for the fill_between two curves case:
thriveth commentedon Sep 5, 2014
Turns out, my function was fairly simple to generalize to unevenly spaced data. I have updated the gist and include the code below.
This still takes all the samme keywords as fill_between.
Here is an example, with a plot of the lower data in orange with

drawstyle='steps-mid'set, they match very nicely.tacaswell commentedon Nov 20, 2014
Here is a more complete solution which deals with all of the stepping methods of
I will get around to putting this in a PR eventually
dguest commentedon May 10, 2015
This would be a very nice addition, @tacaswell do you think this would be implemented soon? I've written something similar myself (and step style is more or less required in my field, so I'm sure quite a few others have as well), but it would be great to see a standard solution.
tacaswell commentedon May 11, 2015
I would just use the function above for now. The only hold up is I am not sure if this should be it's own function
step_fill_betweenor as a flag in the currentfill_between.efiring commentedon May 11, 2015
I would vote for an additional kwarg in fill_between, and presumably in fill_betweenx as well.
ENH : add step_where kwarg to fill_between{x}
ENH : add step_where kwarg to fill_between{x}
ENH : add step_where kwarg to fill_between{x}
ENH : add step_where kwarg to fill_between{x}
pollackscience commentedon Nov 12, 2015
Great solution @tacaswell. I would additionally request the ability to specify N+1 step edges for N step values. Currently I am using your solution by plotting the first bin with
step_where='post', then the remaining bins withstep_where='pre'. Also, the poly collection that is specified byfill_betweendoes not supportlegend(), which is unfortunate.