1

So I have a plot that prints decimals instead of a date on the x axis. I have done the research on stackoverflow and have read that matplotlib does not handle datetime64 at all without codeing around it. I can't seem to find out why? Please note I am NOT asking how to fix it but WHY the problem exists, I know there is a good reason for it but I can't seem to find out why.

my line of code looks like this, I am NOT showing the rest of the program as it isn't relevant to the question I am asking.

my_dates =  np.array([d[0] for d in data]).astype('datetime64[D]')
theakson
  • 502
  • 7
  • 23

2 Answers2

2

Some of the reasons I read about were due to the difficulty and time implied in implementing this feature in some way that remains stable. The proposal is old (at least since 2012) as you can see here.

Several workarounds have been proposed and you'll find examples in SO like this and this.

As for matplotlib lib itself you'll find even some solutions that seemed to be workable as an initial prototype. This one was posted by agijsberts in this discussion here. Although the issue was in a pandas tracker the solution actually seems to require no pandas at all.

from matplotlib import units, dates
from matplotlib import pyplot as plt
from numpy import datetime64, timedelta64, arange, ndarray, dtype
from numpy.random import rand
import datetime

resolution_scale = {
    dtype('datetime64[ns]'): 1e-9,
    dtype('datetime64[us]'): 1e-6,
    dtype('datetime64[ms]'): 1e-3,
    dtype('datetime64[s]'): 1,
    dtype('datetime64[m]'): 60,
    dtype('datetime64[h]'): 60 * 60,
    dtype('datetime64[D]'): 24 * 60 * 60,
}

class Datetime64Converter(dates.DateConverter):
    @staticmethod
    def convert(values, unit, axis):
        if isinstance(values, ndarray) and issubclass(values.dtype.type, datetime64):
            return dates.epoch2num(values.view('i8') * resolution_scale[values.dtype])
        elif isinstance(values, datetime.date):
            return dates.date2num(values)
        else:
            return values

units.registry[datetime64] = Datetime64Converter

a = arange('2014-01-01', '2014-01-07', timedelta64(1, 'D'), dtype='datetime64[D]')
b = rand(len(a))
for i, r in enumerate(('ns', 'us', 'ms', 's', 'm', 'h', 'D')):
    plt.plot(a.astype('datetime64[{0}]'.format(r)), b + i, label=r)
plt.legend()
plt.show()

Yet, even with this, I still haven't heard of an actual compromise to do this (although notice that I'm not keeping myself informed either). Personally I would say that the reason for this not being implemented is just because it's not on anyone priority list.

Community
  • 1
  • 1
armatita
  • 12,825
  • 8
  • 48
  • 49
  • thanks so much @armatita really great of you to take the time. You confirmed what I suspected but wanted to make sure. Thanks again – theakson May 15 '16 at 19:50
0

As of Matplotlib >= 2.2.2 (possibly lower versions as well), numpy.datetime64 can directly be plotted.

The following produces the desired output

import numpy as np
import matplotlib.pyplot as plt

x = np.arange('2014-01-01', '2014-01-07', np.timedelta64(1, 'D'), dtype='datetime64[D]')
y = np.random.rand(len(x))

plt.plot(x,y)
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712