0

I have a range of values for every hour of year. Which means there are 24 x 365 = 8760 values. I want to plot this information neatly with matplotlib, with x-axis showing January, February...... Here is my current code:

from matplotlib import pyplot as plt

plt.plot(x_data,y_data,label=str("Plot"))
plt.xticks(rotation=45)
plt.xlabel("Time")
plt.ylabel("Y axis values")
plt.title("Y axis values vs Time")
plt.legend(loc='upper right')
axes = plt.gca()
axes.set_ylim([0,some_value * 3])
plt.show() 

x_data is a list containing dates in datetime format. y_data contains values corresponding to the values in x_data. How can I get the plot neatly done with months on the X axis? An example:

enter image description here

Vijay47
  • 337
  • 5
  • 13

1 Answers1

0

You could create a scatter plot with horizontal lines as markers. The month is extracted by using the datetime module. In case the dates are not ordered, the plot sorts both lists first according to the date:

#creating a toy dataset for one year, random data points within month-specific limits
from datetime import date, timedelta
import random
x_data = [date(2017, 1, 1) + timedelta(days = i) for i in range(365)]
random.shuffle(x_data)
y_data = [random.randint(50 * (i.month - 1), 50 * i.month) for i in x_data]

#the actual plot starts here
from matplotlib import pyplot as plt
#get a scatter plot with horizontal markers for each data point
#in case the dates are not ordered, sort first the dates and the y values accordingly 
plt.scatter([day.strftime("%b") for day in sorted(x_data)], [y for _xsorted, y in  sorted(zip(x_data, y_data))], marker = "_", s = 900)
plt.show()

Output
enter image description here

The disadvantage is obviously that the lines have a fixed length. Also, if a month doesn't have a data point, it will not appear in the graph.

Edit 1:
You could also use Axes.hlines, as seen here.
This has the advantage, that the line length changes with the window size. And you don't have to pre-sort the lists, because each start and end point is calculated separately. The toy dataset is created as above.

from matplotlib import pyplot as plt
#prepare the axis with categories Jan to Dec
x_ax = [date(2017, 1, 1) + timedelta(days = 31 * i) for i in range(12)]
#create invisible bar chart to retrieve start and end points from automatically generated bars
Bars = plt.bar([month.strftime("%b") for month in x_ax], [month.month for month in x_ax], align = "center", alpha = 0)
start_1_12 = [plt.getp(item, "x") for item in Bars]
end_1_12   = [plt.getp(item, "x") + plt.getp(item, "width") for item in Bars]
#retrieve start and end point for each data point line according to its month
x_start = [start_1_12[day.month - 1] for day in x_data]
x_end = [end_1_12[day.month - 1] for day in x_data]

#plot hlines for all data points
plt.hlines(y_data, x_start, x_end, colors = "blue")
plt.show()

Output enter image description here

Edit 2:
Now your description of the problem is totally different from what you show in your question. You want a simple line plot with specific axis formatting. This can be found easily in the matplotlib documentation and all over SO. An example, how to achieve this with the above created toy dataset would be:

import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, MonthLocator

ax = plt.subplot(111)
ax.plot([day for day in sorted(x_data)], [y for _xsorted, y in  sorted(zip(x_data, y_data))], "r.-")
ax.xaxis.set_major_locator(MonthLocator(bymonthday=15))
ax.xaxis.set_minor_locator(MonthLocator())
ax.xaxis.set_major_formatter(DateFormatter("%B"))
plt.show()

Output enter image description here

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • Thanks for the detailed reply. Let me check – Vijay47 Apr 30 '18 at 17:51
  • The first one does the job, but as you said, the plot changes when the graph is resized. The 2nd one generates bars, but I need line graph. – Vijay47 Apr 30 '18 at 18:12
  • I need a normal plot instead of a scatter plot, but the x axis have months. – Vijay47 Apr 30 '18 at 18:28
  • It is impossible that the second version generates bars. It uses `plt.hlines`, which, as the name implies, creates horizontal lines. And what exactly is "a normal plot"? This graph replicates, what you have shown in your question, so it is difficult to understand, how your desired output differs. Maybe part of the problem is that you haven't provided a sample input. – Mr. T Apr 30 '18 at 20:25
  • I have a list of values for each hour of an year. So the plot will be a continuous line instead of bars. – Vijay47 May 01 '18 at 05:51
  • 1) There are no bars. 2) This is totally different from what your picture shows in the question. Seemingly, you want a line graph. – Mr. T May 01 '18 at 07:42