46

This should be easy but I have just started toying with matplotlib and python. I can do a line or a scatter plot but i am not sure how to do a simple step function. Any help is much appreciated.

x = 1,2,3,4
y = 0.002871972681775004, 0.00514787917410944, 0.00863476098280219, 0.012003316194034325
2
  • What do you mean by a step function? Like a histogram? Commented Jan 19, 2012 at 5:14
  • @wim en.wikipedia.org/wiki/Step_function Commented Jan 8, 2017 at 6:43

6 Answers 6

72

It seems like you want step.

E.g.

import matplotlib.pyplot as plt

x = [1,2,3,4] 
y = [0.002871972681775004, 0.00514787917410944, 
     0.00863476098280219, 0.012003316194034325]

plt.step(x, y)
plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

Well, if you don't want any vertical lines, have a look at plt.hlines. E.g. plt.hlines(y, range(1,5), range(2,6))
@Joe Kington: Sorry for the year-later comment. I'm a bit confused by this. Shouldn't the graph show 0.0028 between 1 and 2 and then jump to 0.051 at 2, and so on? It looks like step uses the next value along. (I'm thinking of a timeseries step, where the value is a at t0 and remains a until t1 when it changes to b and so on.) Is there a way to make step() behave in this way.
To answer my comment above, I've found that you can add the where='post' parameter to the step function. So in the example above, it would be: plt.step(x, y, where='post')
@JoeKington how to proceed if I would be given the bounds? I think that 1,2,3,4 are the reference points in your case
26

If you have non-uniformly spaced data points, you can use the drawstyle keyword argument for plot:

x = [1,2.5,3.5,4] 
y = [0.002871972681775004, 0.00514787917410944, 
     0.00863476098280219, 0.012003316194034325]

plt.plot(x, y, drawstyle='steps-pre')

Also available are steps-mid and steps-post.

2 Comments

Great. I used this for something else. Simple and precise.
drawstyle documentation link. "‘steps’ is equivalent to ‘steps-pre’ and is maintained for backward-compatibility."
6

New in matplotlib 3.4.0

There is a new plt.stairs method to complement plt.step:

plt.stairs and the underlying StepPatch provide a cleaner interface for plotting stepwise constant functions for the common case that you know the step edges.

This supersedes many use cases of plt.step, for instance when plotting the output of np.histogram.

Check out the official matplotlib gallery for how to use plt.stairs and StepPatch.


When to use plt.step vs plt.stairs

  • Use the original plt.step if you have reference points. Here the steps are anchored at [1,2,3,4] and extended to the left:

    plt.step(x=[1,2,3,4], y=[20,40,60,30])
    
  • Use the new plt.stairs if you have edges. The previous [1,2,3,4] step points correspond to [1,1,2,3,4] stair edges:

    plt.stairs(values=[20,40,60,30], edges=[1,1,2,3,4])
    

plt.step vs plt.stairs


Using plt.stairs with np.histogram

Since np.histogram returns edges, it works directly with plt.stairs:

data = np.random.normal(5, 3, 3000)
bins = np.linspace(0, 10, 20)
hist, edges = np.histogram(data, bins)

plt.stairs(hist, edges)

plt.stairs with np.histogram

1 Comment

is it possible to emulate the plt.stairs(). My version of matplotlib does not contain it. I have also a bunch of code for python 2.7, so migrating is not that easy.
2

I think you want pylab.bar(x,y,width=1) or equally pyplot's bar method. if not checkout the gallery for the many styles of plots you can do. Each image comes with example code showing you how to make it using matplotlib.

Comments

2

Draw two lines, one at y=0, and one at y=1, cutting off at whatever x your step function is for.

e.g. if you want to step from 0 to 1 at x=2.3 and plot from x=0 to x=5:

import matplotlib.pyplot as plt
#                                 _
# if you want the vertical line _|
plt.plot([0,2.3,2.3,5],[0,0,1,1])
#
# OR:
#                                       _
# if you don't want the vertical line _
#plt.plot([0,2.3],[0,0],[2.3,5],[1,1])

# now change the y axis so we can actually see the line
plt.ylim(-0.1,1.1)

plt.show()

1 Comment

Is it possible to use bin boundaries, like the plt.stairs([1,2,3,4,5,6],[0,1,2,3,4,5,6]) , i.e between 0 and 1 the value is 1, between 1 & 2 is 2 etc. the step plot function refers (in my opinion) to midpoints, not to edges. The problem for me, is that stairs does not exist in python2
0

In case someone just wants to stepify some data rather than actually plot it:

def get_x_y_steps(x, y, where="post"):
    if where == "post":
        x_step = [x[0]] + [_x for tup in zip(x, x)[1:] for _x in tup]
        y_step = [_y for tup in zip(y, y)[:-1] for _y in tup] + [y[-1]]
    elif where == "pre":
        x_step = [_x for tup in zip(x, x)[:-1] for _x in tup] + [x[-1]]
        y_step = [y[0]] + [_y for tup in zip(y, y)[1:] for _y in tup]
    return x_step, y_step

2 Comments

Have been looking without success for an inbuilt function. Thanks! I had an issue (due to version?): TypeError: 'zip' object is not subscriptable. I'm using Python 3.5. The function works after I change all zip for list(zip(...)).
@daniel Thanks for noting that! I wrote the code for python 2, so that explains the error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.