3

I would like to have a step-wise line plot in Matplotlib. The shape of the line should be similar to this one (see screenshot): Desired shape

This is my current code:

import pandas as pd
from matplotlib import pyplot as plt
%matplotlib inline


prices = [12.05, 17.69, 15.31, 12.75, 17.18, 25.05, 33.19, 38.56, 42.9, 38.29, 37.06, 38.94, 36.36, 39.45, 43.97, 46.14, 50.96, 51.04, 48.85, 45.6, 42.38, 39.83, 33.53, 30.03, 28.69
]


price_data = pd.DataFrame(prices, index=range(0, 25))
fig = plt.figure(linewidth=1, figsize=(7, 5))
ax = price_data.plot.line(ax=plt.gca(), color="green"  )
ax.set_facecolor("white")
ax.set_xlabel("Time of day", fontsize = 14, labelpad=8)
ax.set_ylabel("Price in €/MWh", fontsize = 14,labelpad=8)
ax.set_xlim(0, 24)
ax.set_ylim(0, 60)


plt.xticks(price_data.index, labels=[f'{h:02d}:00' for h in price_data.index], rotation=90)
plt.grid(axis='y', alpha=.4)
plt.tight_layout()
xticks = ['00:00', '01:00', '02:00' , '03:00', '04:00' , '05:00' , '06:00' , '07:00' , '08:00' , 
          '09:00' , '10:00' , '11:00' , '12:00' , '13:00' , '14:00' , '15:00' , '16:00' 
          , '17:00', '18:00', '19:00' , '20:00' , '21:00', '22:00' , '23:00' , '24:00'  ]
xvals = [0, 1*12, 2*12, 3*12, 4*12, 5*12, 6*12, 7*12, 8*12, 9*12, 10*12, 11*12, 12*12, 13*12, 14*12, 15*12, 16*12
        , 17*12, 18*12, 19*12, 20*12, 21*12, 22*12, 23*12, 24*12] 
ax.set(xticks=xvals, xticklabels=xticks)
ax.tick_params(axis='both', which='major', labelsize=14)
ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)
plt.savefig('Prices.png', edgecolor='black', dpi=300, bbox_inches='tight')
plt.show()

And this is my current output (see screenshot): [![

7
  • 1
    What is wind_data? Commented Mar 11, 2020 at 9:38
  • Thanks for your comment Guimoute. This was a mistake by me. It should be price_data. Still the plot looks not as desired Commented Mar 11, 2020 at 9:47
  • 2
    Multiplying all the hours by 12 doesn't make any sense. Just leave out ax.set(xticks=xvals, xticklabels=xticks) because it puts all the ticks on the wrong locations. The ticks are already put correctly via plt.xticks(....). Commented Mar 11, 2020 at 9:51
  • Thanks for your comment JohanC. In the answer below from user10455554 the hours are also multiplied Commented Mar 11, 2020 at 9:56
  • 1
    @PeterBe Do not bother typing sequences yourself. For example, labels=[f'{h:02d}:00' for h in price_data.index] was great. You could do xvals = list(range(0, 25)). Now JohanC is right you don't need xvals or xticks anyway. Commented Mar 11, 2020 at 10:01

2 Answers 2

3

Using @JohanC's great comments, here is a solution.

As he said, get rid of xticks, xvals, etc. You already defined your ticks properly with plt.xticks(price_data.index, labels=[f'{h:02d}:00' for h in price_data.index], rotation=90), plus you don't have to type 24 different values yourself.

To get a step-like plot, you simply need to add the argument drawstyle = "steps-pre" or "steps-post" (or other options found in the documentation) to your plotting function.

from matplotlib import pyplot as plt
%matplotlib inline

prices = [12.05, 17.69, 15.31, 12.75, 17.18, 25.05, 33.19, 38.56, 42.9, 38.29, 37.06, 38.94, 36.36, 39.45, 43.97, 46.14, 50.96, 51.04, 48.85, 45.6, 42.38, 39.83, 33.53, 30.03, 28.69]    
hours = list(range(25)) # [0, 1, 2, ... 22, 23, 24]
labels = [f'{h:02d}:00' for h in hours] # ["00:00", "01:00", ... "23:00", "24:00"]

fig = plt.figure(linewidth=1, figsize=(7, 5))
ax = plt.gca()

ax.plot(hours, prices, color="green", drawstyle="steps-post") # <- drawstyle argument.
ax.set_xlabel("Time of day", fontsize=14, labelpad=8)
ax.set_ylabel("Price in €/MWh", fontsize=14, labelpad=8)
ax.set_xlim(0, 24)
ax.set_ylim(0, 60)    
plt.xticks(hours, labels=labels, rotation=90)
plt.grid(axis='y', alpha=.4)
ax.tick_params(axis='both', which='major', labelsize=14)
# (Optional) ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)
plt.tight_layout() # This must be called last, after all elements (plot and legend) are ready.
plt.savefig('Prices.png', edgecolor='black', dpi=300, bbox_inches='tight')
plt.show()

enter image description here

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

5 Comments

Thanks for your answer Guimoute. How can I get rid of the legend? Just removing "ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)" just leads to the legend placed on the right upper corner
That might be due to how Panda handles things. If we use ax.plot(x, y) and remove ax.legend(...) it does disappear. I'll edit.
Thaks Guimoute for your comment. Unfortunately I get an error when I use your edited code "TypeError: plot got an unexpected keyword argument 'x'"
@PeterBe Ah I guess x= and y= are not even needed actually!
Thanks a lot for your help and effort Guimoute
2

You only need to use the step function on your plot with your x- and y-values like plt.step(xvals, prices) Just add this line after you defined the xvals should give you a good starting point.

For more details see the step plot example:

import pandas as pd
from matplotlib import pyplot as plt

prices = [12.05, 17.69, 15.31, 12.75, 17.18, 25.05, 33.19, 38.56, 42.9, 38.29, 37.06, 38.94, 36.36, 39.45, 43.97, 46.14, 50.96, 51.04, 48.85, 45.6, 42.38, 39.83, 33.53, 30.03, 28.69]

xvals = [0, 1*12, 2*12, 3*12, 4*12, 5*12, 6*12, 7*12, 8*12, 9*12, 10*12, 11*12, 12*12, 13*12, 14*12, 15*12, 16*12, 17*12, 18*12, 19*12, 20*12, 21*12, 22*12, 23*12, 24*12] 

price_data = pd.DataFrame(prices, index=range(0, 25))
fig = plt.figure(linewidth=1, figsize=(7, 5))
ax = price_data.plot.line(ax=plt.gca(), color="green"  )
ax.set_facecolor("white")
ax.set_xlabel("Time of day", fontsize = 14, labelpad=8)
ax.set_ylabel("Price in €/MWh", fontsize = 14,labelpad=8)
ax.set_xlim(0, 288)
ax.set_ylim(0, 60)


plt.xticks(price_data.index, labels=[f'{h:02d}:00' for h in price_data.index], rotation=90)
plt.grid(axis='y', alpha=.4)
plt.tight_layout()
xticks = ['00:00', '01:00', '02:00' , '03:00', '04:00' , '05:00' , '06:00' , '07:00' , '08:00' , 
          '09:00' , '10:00' , '11:00' , '12:00' , '13:00' , '14:00' , '15:00' , '16:00' 
          , '17:00', '18:00', '19:00' , '20:00' , '21:00', '22:00' , '23:00' , '24:00'  ]

plt.step(xvals, prices)
ax.set(xticks=xvals, xticklabels=xticks)
ax.tick_params(axis='both', which='major', labelsize=14)
ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)
plt.savefig('Prices.png', edgecolor='black', dpi=300, bbox_inches='tight')
plt.show()

result

2 Comments

Thanks user10455554 for your answer and your help. The plot looks good. But how can I get rid of the green line and the legend above?
Ok Guimoute was faster, the green line was the plot from pandas.dataframe price_data.plot.line(ax=plt.gca(), color="green" ) I added another line with the matplotlib step function instead of using the drawstyle parameter, which is the better solution.

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.