Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Plot Time Stamps HH:MM on Python Matplotlib "Clock" Polar Plot

I am trying to plot mammalian feeding data on time points on a polar plot. In the example below, there is only one day, but each day will eventually be plotted on the same graph (via different axes). I currently have all of the aesthetics worked out, but my data is not graphing correctly. How do I get the hours to plot correctly?

I assume that the solution will likely have to do with pd.datetime and np.deg2rad, but I have not found the correct combo.

I am importing my data from csv, and filtering each day based on the date as follows:

#Filtered portion:
Day1 = df[df.Day == '5/22']

This gives me the following data:

    Day   Time  Feeding_Quality    Feed_Num
0  5/22  16:15            G        2
1  5/22  19:50            G        2
2  5/22  20:15            G        2
3  5/22  21:00            F        1
4  5/22  23:30            G        2

Here is the code:

fig = plt.figure(figsize=(7,7))

ax = plt.subplot(111, projection = 'polar')

ax.bar(Day1['Time'], Day1['Feed_Num'], width = 0.1, alpha=0.3, color='red', label='Day 1')

# Make the labels go clockwise
ax.set_theta_direction(-1)

#Place Zero at Top
ax.set_theta_offset(np.pi/2)

#Set the circumference ticks
ax.set_xticks(np.linspace(0, 2*np.pi, 24, endpoint=False))

# set the label names
ticks = ['12 AM', '1 AM', '2 AM', '3 AM', '4 AM', '5 AM', '6 AM', '7 AM','8 AM','9 AM','10 AM','11 AM','12 PM', '1 PM', '2 PM', '3 PM', '4 PM',  '5 PM', '6 PM', '7 PM', '8 PM', '9 PM', '10 PM', '11 PM' ]
ax.set_xticklabels(ticks)

# suppress the radial labels
plt.setp(ax.get_yticklabels(), visible=False)

#Bars to the wall
plt.ylim(0,2)

plt.legend(bbox_to_anchor=(1,0), fancybox=True, shadow=True)
plt.show()

As you can assume from the data, all bars plotted would be in the afternoon, but as you can see from the graph output, the data is all over the place.

polar clock plot

like image 957
dancassin Avatar asked Aug 22 '26 16:08

dancassin


1 Answers

import numpy as np
from matplotlib import pyplot as plt
import datetime
df = pd.DataFrame({'Day': {0: '5/22', 1: '5/22', 2: '5/22', 3: '5/22', 4: '5/22'},
                   'Time': {0: '16:15', 1: '19:50', 2: '20:15', 3: '21:00', 4: '23:30'},
                   'Feeding_Quality': {0: 'G', 1: 'G', 2: 'G', 3: 'F', 4: 'G'},
                   'Feed_Num': {0: 2, 1: 2, 2: 2, 3: 1, 4: 2}})

Create a series of datetime.datetime objects from the 'Time' column; transform that into percentages of 24 hours; transform that into radians.

xs = pd.to_datetime(df['Time'],format= '%H:%M' )
xs = xs - datetime.datetime.strptime('00:00:00', '%H:%M:%S')
xs = xs.dt.seconds / (24 * 3600)
xs = xs * 2 * np.pi

Use that as the x values for the plot

fig = plt.figure(figsize=(7,7))
ax = plt.subplot(111, projection = 'polar')
ax.bar(xs, df['Feed_Num'], width = 0.1, alpha=0.3, color='red', label='Day 1')

# Make the labels go clockwise
ax.set_theta_direction(-1)

#Place Zero at Top
ax.set_theta_offset(np.pi/2)

#Set the circumference ticks
ax.set_xticks(np.linspace(0, 2*np.pi, 24, endpoint=False))

# set the label names
ticks = ['12 AM', '1 AM', '2 AM', '3 AM', '4 AM', '5 AM', '6 AM', '7 AM','8 AM','9 AM','10 AM','11 AM','12 PM', '1 PM', '2 PM', '3 PM', '4 PM',  '5 PM', '6 PM', '7 PM', '8 PM', '9 PM', '10 PM', '11 PM' ]
ax.set_xticklabels(ticks)

# suppress the radial labels
plt.setp(ax.get_yticklabels(), visible=False)

#Bars to the wall
plt.ylim(0,2)

plt.legend(bbox_to_anchor=(1,0), fancybox=True, shadow=True)
plt.show()

The 'Time' column could also be transformed to radians with

def trans(x):
    h,m = map(int,x)
    return 2 * np.pi * (h + m/60)/24

xs = df['Time'].str.split(':')
xs = xs.apply(trans)

Which is probably a little better than using timedelta's - that seemed a little convoluted.

like image 116
wwii Avatar answered Aug 24 '26 05:08

wwii



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!