Reputation: 377
I am working on a task, where I need to calculate time spent on each day and then represent that time using a bar plot, so for this task I used python and able to get time spent on each day, and stored it in a list "time_list", now I don't understand how to plot this using matplotlib function.
The problem is that, this list contains datetime.timedelta class values. Example:
time_list
[datetime.timedelta(0, 23820), datetime.timedelta(0, 27480), datetime.timedelta(0, 28500), datetime.timedelta(0, 24180), datetime.timedelta(0, 27540), datetime.timedelta(0, 28920), datetime.timedelta(0, 28800), datetime.timedelta(0, 29100), datetime.timedelta(0, 29100), datetime.timedelta(0, 24480), datetime.timedelta(0, 27000)]
And these values meaning is as follow:
Total Time Spent on 2 is 6:37:00
Total Time Spent on 3 is 7:38:00
Total Time Spent on 4 is 7:55:00
Total Time Spent on 5 is 6:43:00
Total Time Spent on 8 is 7:39:00
Total Time Spent on 9 is 8:02:00
Total Time Spent on 10 is 8:00:00
Total Time Spent on 11 is 8:05:00
Total Time Spent on 12 is 8:05:00
Total Time Spent on 15 is 6:48:00
Total Time Spent on 16 is 7:30:00
Upvotes: 11
Views: 21870
Reputation: 31
I had similar problem when I wanted to plot the data with a y axis
equal to Timedelta64[ns]
type. I found the easiest solution to handle this issue from this blog : solution. For short, just change the dtype
of your column to .astype('timedelta64[m]')
. You can change to hour, minutes or seconds for your case just by changing the value in a square brackets. It changes the dtype of your y
column to float64
and then you can easily plot the bar graph or plot with normal units and not like nanoseconds
Upvotes: 1
Reputation: 339795
While matplotlib can in principle handle datetime objects, the bar plot cannot interprete them directly. So one may add an arbitrary date to the timedeltas and convert to numbers using matplotlib.dates.date2num()
. Then using a DateFormatter
enables nice ticklabels.
import numpy as np
import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
days = [2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16]
time_list = [datetime.timedelta(0, 23820), datetime.timedelta(0, 27480),
datetime.timedelta(0, 28500), datetime.timedelta(0, 24180),
datetime.timedelta(0, 27540), datetime.timedelta(0, 28920),
datetime.timedelta(0, 28800), datetime.timedelta(0, 29100),
datetime.timedelta(0, 29100), datetime.timedelta(0, 24480),
datetime.timedelta(0, 27000)]
# specify a date to use for the times
zero = datetime.datetime(2018,1,1)
time = [zero + t for t in time_list]
# convert datetimes to numbers
zero = mdates.date2num(zero)
time = [t-zero for t in mdates.date2num(time)]
f = plt.figure()
ax = f.add_subplot(1,1,1)
ax.bar(days, time, bottom=zero)
ax.yaxis_date()
ax.yaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
# add 10% margin on top (since ax.margins seems to not work here)
ylim = ax.get_ylim()
ax.set_ylim(None, ylim[1]+0.1*np.diff(ylim))
plt.show()
Upvotes: 6
Reputation: 2170
I don't think you can directly plot timedelta
in Matplotlib, but since you already have the number of seconds, you can define a custom tick format that converts seconds to hours and minutes.
from matplotlib.ticker import FuncFormatter
def format_func(x, pos):
hours = int(x//3600)
minutes = int((x%3600)//60)
seconds = int(x%60)
return "{:d}:{:02d}".format(hours, minutes)
# return "{:d}:{:02d}:{:02d}".format(hours, minutes, seconds)
formatter = FuncFormatter(format_func)
Then, you can set the tick formatter for the y-axis.
Here's an example using a bar
.
labels = [2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16]
seconds = [i.seconds for i in time_list]
f = plt.figure()
ax = f.add_subplot(1,1,1)
ax.bar(labels, seconds)
ax.yaxis.set_major_formatter(formatter)
# this locates y-ticks at the hours
ax.yaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=3600))
# this ensures each bar has a 'date' label
ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=1))
Upvotes: 14