xpress_embedo
xpress_embedo

Reputation: 377

Plot datetime.timedelta

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

Answers (3)

ArKey
ArKey

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

ImportanceOfBeingErnest
ImportanceOfBeingErnest

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()

enter image description here

Upvotes: 6

Phil
Phil

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))

Example Bar Graph

Upvotes: 14

Related Questions