34

I have my data in an array of the following structure,

[[1293606162197, 0, 0],
 [1293605477994, 63, 0],
 [1293605478057, 0, 0],
 [1293605478072, 2735, 1249],
 [1293606162213, 0, 0],
 [1293606162229, 0, 0]]

The first column is epoch time (in ms), second is y1 and third is y2. I need a plot with the time on the x-axis, and y1 and y2 on left and right y-axes.

I have been scouring through the documentation but couldn't find any way to get my x-axis ticks to display both date and time, like "28/12 16:48", i.e., "date/month hour:min". All the documentation helps me with is to display dates alone, but that is not what I want.

It is actually a follow-up to my previous question.

2
  • Should the X-axis represent real linear time or you need just the 'DD/MM HH:MM' text under each tick that has data? Commented Mar 31, 2011 at 11:13
  • I want the absolute date, which will need to be displayed vertically, as it won't fit horizontally. Commented Mar 31, 2011 at 11:24

2 Answers 2

49

I hope this helps. I've always had a hard time with matplotlib's dates. Matplotlib requires a float format which is days since epoch. The helper functions num2date and date2num along with python builtin datetime can be used to convert to/from. The formatting business was lifted from this example. You can change an axis on any plot to a date axis using set_major_formatter.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import dates
import datetime

a = np.array([
    [1293605162197, 0, 0],
    [1293605477994, 63, 0],
    [1293605478057, 0, 0],
    [1293605478072, 2735, 1249],
    [1293606162213, 0, 0],
    [1293606162229, 0, 0]])

d = a[:,0]
y1 = a[:,1]
y2 = a[:,2]

# convert epoch to matplotlib float format
s = d/1000
ms = d-1000*s  # not needed?
dts = map(datetime.datetime.fromtimestamp, s)
fds = dates.date2num(dts) # converted

# matplotlib date format object
hfmt = dates.DateFormatter('%m/%d %H:%M')

fig = plt.figure()
ax = fig.add_subplot(111)
ax.vlines(fds, y2, y1)

ax.xaxis.set_major_locator(dates.MinuteLocator())
ax.xaxis.set_major_formatter(hfmt)
ax.set_ylim(bottom = 0)
plt.xticks(rotation='vertical')
plt.subplots_adjust(bottom=.3)
plt.show()

result

Sign up to request clarification or add additional context in comments.

1 Comment

If you use a really large dataset, you probably want to call any plot functions after you call ax.xaxis.set_major_locator() otherwise you may run into an "RuntimeError: RRuleLocator" which you could avoid.
0

In more recent versions of matplotlib (e.g. 3.7.0), there's no need to explicitly convert date to numbers, matplotlib handles it internally. So simply passing the datetime objects as x-values works.

To show custom ticks, DateFormatter along with MinuteLocator/MicrosecondLocator etc. (depending on the resolution of the time component) can be used.

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime

data = [[1293606162197, 0, 0], [1293605477994, 63, 0], [1293605478057, 0, 0], 
        [1293605478072, 2735, 1249], [1293606162213, 0, 0], [1293606162229, 0, 0]]

# sort time-series by datetime
x, y1, y2 = zip(*sorted(data, key=lambda x: x[0]))

# convert to datetime objects
x = [datetime.datetime.fromtimestamp(i / 1000) for i in x]

fig, ax = plt.subplots()
ax.plot(x, y1, label='y1');       # plot y1 series
ax.plot(x, y2, label='y2')        # plot y2 series
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d/%m %H:%M'))  # format date/time
ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=2))       # show every second minute
ax.legend()                                                        # show legend
fig.autofmt_xdate();                                               # format ticklabels

img

If you don't particularly care how datetime is shown as x-ticks, there matplotlib.dates.ConciseDateFormatter that does "pretty" formatting for you. For the example at hand, that would look like:

ax = plt.subplot()
ax.plot(x, y1, label='y1');       # plot y1 series
ax.plot(x, y2, label='y2')        # plot y2 series

locator = mdates.MinuteLocator(interval=2)
ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(locator))  # format date/time
ax.xaxis.set_major_locator(locator)                                 # show every second minute
ax.legend();

img2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.