1

How can I convert a datetime into a floating point representation that is used by matplotlib's x-axis? matplotlib.dates.date2num doesn't seem to work as per below...

import pandas as pd
import matplotlib as mpl
import datetime

idx = pd.DatetimeIndex(
    [
        '2021-12-21 10:25:00+00:00', '2021-12-21 10:30:00+00:00',
        '2021-12-21 10:35:00+00:00', '2021-12-21 10:40:00+00:00',
        '2021-12-21 10:45:00+00:00', '2021-12-21 10:50:00+00:00',
        '2021-12-21 10:55:00+00:00', '2021-12-21 11:00:00+00:00',
        '2021-12-21 11:05:00+00:00', '2021-12-21 11:10:00+00:00'
    ],
    dtype='datetime64[ns, Europe/London]',
    name='time',
    freq=None
)
s = pd.Series(
    [0.6, 1.8, 2.7, 1.8, 1.5, 2.1, 0.9, 1.8, 3.2, 4.4],
    index=idx
)

fig, ax = plt.subplots()
s.plot(ax=ax)

target_x = datetime.datetime(2021, 12, 21, 18)
target_y = 2

ax.scatter(mpl.dates.date2num(target_x), target_y, marker='x')

The problem seems to be here:

>>> ax.get_xlim()
(27334705.0, 27334750.0)

whereas

>>> mpl.dates.date2num(target_x)
18982.75

References

Alexander McFarlane
  • 10,643
  • 9
  • 59
  • 100
  • Pandas uses a different datetime converter than matplotlib. – Jody Klymak Dec 22 '21 at 07:52
  • If you want to use date2num suggest you de register pandas converters. https://pandas.pydata.org/docs/reference/api/pandas.plotting.deregister_matplotlib_converters.html#pandas.plotting.deregister_matplotlib_converters – Jody Klymak Dec 22 '21 at 07:55

1 Answers1

1

It's Epochs / 60.

>>> ax.get_xticklabels()
[Text(27334705, 0, '10:25'),
 Text(27334740, 0, '11:00'),
 Text(27334750, 0, '11:10')]

So I noticed difference between the numbers in matplotlib representation is equal to difference in minutes between datetimes. And then you can confirm

>>> idx[7].timestamp() / 60 #'2021-12-21 11:00:00+00:00'
27334740.0

It checks out.
I don't know about the reasoning behind this, or a prettier method - just noticed this relation.

Code below draws the mark - had to add timezone information to your target datetime:

import pandas as pd
import matplotlib as mpl
import datetime
import pytz

idx = pd.DatetimeIndex(
    [
        '2021-12-21 10:25:00+00:00', '2021-12-21 10:30:00+00:00',
        '2021-12-21 10:35:00+00:00', '2021-12-21 10:40:00+00:00',
        '2021-12-21 10:45:00+00:00', '2021-12-21 10:50:00+00:00',
        '2021-12-21 10:55:00+00:00', '2021-12-21 11:00:00+00:00',
        '2021-12-21 11:05:00+00:00', '2021-12-21 11:10:00+00:00'
    ],
    dtype='datetime64[ns, Europe/London]',
    name='time',
    freq=None
)
s = pd.Series(
    [0.6, 1.8, 2.7, 1.8, 1.5, 2.1, 0.9, 1.8, 3.2, 4.4],
    index=idx
)

fig, ax = plt.subplots()
s.plot(ax=ax)

target_x = datetime.datetime(2021, 12, 21, 11, 0, 0, 0, pytz.UTC)
target_y = 2

ax.scatter(int(target_x.timestamp()/60), target_y, marker='x')
Patryk Kowalski
  • 561
  • 3
  • 13
  • 1
    Excellent spot! One other comment is that I noticed in `pandas` it can sometimes normalise the dates to `target_x.timestamp()/60/60/24` or `target_x.timestamp()/60/60` depending on the axes – Alexander McFarlane Dec 23 '21 at 07:22