Skip to content
Advertisement

How to label milliseconds axis with datetime labels in matplotlib

I’ve got a sort of timeline plot. I’m drawing rectangles all over it, which is easy to do when time is in milliseconds. But then the x axis labels come out numerical, and I’d rather they be dates. I can convert my timestamps with df['timestamp'] = pandas.to_datetime(df['timestamp']) to fix the x axis labels, but then my rectangle drawing math breaks, because I can’t subtract milliseconds from a datetime like rect = [(t - 59000, h - 0.4), (t - 59000, h + 0.4), (t, h + 0.4), (t, h - 0.4), (t - 59000, h - 0.4)]; bars.append(rect); bars = PolyCollection(bars)

I think it would be easiest to just change the way my axis is labeled. How can I make it quit trying to plot massively long numbers and instead plot pretty date strings?

enter image description here

I just want to show the x axis labels as datetimes instead of these horribly unreadable numbers.

import pandas
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
from matplotlib.ticker import MultipleLocator

df = pandas.read_csv('thing.csv')

vert = {"upright":1, "supine":2, "lying_left":3, "prone":4, "lying_right":5, "unknown":6}

fig, (ax1) = pyplot.subplots(1, 1, figsize=(15,5))

# first plot of positions over time
# get the computed body positions as bars
bars = []
colors = []
for i,row in df.iterrows():
    h = vert[row['body_position']]
    t = row['timestamp']
    
    rect = [(t - 59000, h - 0.4), (t - 59000, h + 0.4), (t, h + 0.4), (t, h - 0.4), (t - 59000, h - 0.4)]
    bars.append(rect)
    colors.append("C" + str(h-1))

bars = PolyCollection(bars, facecolors=colors)
ax1.add_collection(bars)

ax1.autoscale()
ax1.xaxis.set_major_locator(MultipleLocator(60000))
#ax1.set_xticklabels([''], rotation=90)
#ax1.xaxis.set_major_formatter(dates.DateFormatter("%B-%dn%H:%M"))

ax1.set_yticks(sorted(vert.values()))
ax1.set_yticklabels(sorted(vert, key=vert.get))

pyplot.tight_layout()
pyplot.show()

Here is some example data used to generate the plot:

timestamp,incline_angle,rotation_angle,body_position
1631311140000,,,unknown
1631311200000,,,unknown
1631311260000,2.698802523069221,175.23174346257375,upright
1631311320000,3.79042308483573,167.83999245871857,upright
1631311380000,1.5175027051794074,179.61841112309935,upright
1631311440000,3.975208379737314,171.42631984353366,upright
1631311500000,1.1885374082444298,86.49027321064233,upright
1631311560000,4.810193480680129,21.462454182905063,upright
1631311620000,,,unknown
1631311680000,88.69449620162857,-178.52467261213772,supine
1631311740000,76.13842375737948,-176.28409623055694,supine
1631311800000,56.72313055674839,-171.72681198213715,supine
1631311860000,,,unknown
1631311920000,77.82676616765237,-72.18362857622509,lying_right
1631311980000,81.8046648695628,-46.69883607858903,lying_right
1631312040000,90.30495291582416,-11.324002429040227,prone
1631312100000,,,unknown
1631312160000,108.06979339334902,108.76621826399024,lying_left
1631312220000,,,unknown
1631312280000,,,unknown
1631312340000,,,unknown
1631312400000,117.55244721818904,165.87088640221413,unknown
1631312460000,0.5689364636363466,171.6313935247612,upright
1631312520000,10.566662943419471,-10.860907998962931,upright
1631312580000,24.244743971818696,-3.2077664692605854,upright
1631312640000,24.790924330066783,-5.473576795955548,upright
1631312700000,27.581635762266146,-6.965410020736653,upright

Advertisement

Answer

Alright, great! I was able to reproduce your code and I added a couple of lines to get the outcome you are looking for @PavelKomarov

import pandas
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
from matplotlib.ticker import MultipleLocator
import matplotlib.pyplot as plt

df = pandas.read_csv('thing.csv')

vert = {"upright":1, "supine":2, "lying_left":3, "prone":4, "lying_right":5, "unknown":6}

fig, (ax1) = pyplot.subplots(1, 1, figsize=(15,5))

# first plot of positions over time
# get the computed body positions as bars
bars = []
colors = []
for i,row in df.iterrows():
    h = vert[row['body_position']]
    t = row['timestamp']
    
    rect = [(t - 59000, h - 0.4), (t - 59000, h + 0.4), (t, h + 0.4), (t, h - 0.4), (t - 59000, h - 0.4)]
    bars.append(rect)
    colors.append("C" + str(h-1))

bars = PolyCollection(bars, facecolors=colors)
ax1.add_collection(bars)

ax1.autoscale()
ax1.xaxis.set_major_locator(MultipleLocator(60000))

ax1.set_yticks(sorted(vert.values()))
ax1.set_yticklabels(sorted(vert, key=vert.get))

ax1.set_xticklabels([pd.to_datetime(x).strftime("%Y/%m/%d") for x in ax1.get_xticks()])
plt.xticks(rotation=90)

pyplot.tight_layout()
pyplot.show()

The 2 extra lines I added were:

ax1.set_xticklabels([pd.to_datetime(x).strftime("%Y/%m/%d") for x in ax1.get_xticks()])
plt.xticks(rotation=90)

The timestamps on the xaxis were down to the milliseconds so I formatted them to be in YYYY/MM/DD you can change the format using this.

Let me know if this is what you were looking for.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement