Matplotlib appears not to immediately recognize the real_datetime objects used by cftime as datetime objects, even though they are simply datetime objects with a couple extra properties.
The code below illustrates the issue:
This first block of code demonstrates that matplotlib deals with datetime objects for plotting.
>>> import cftime
>>> import pylab
>>> import datetime
>>> import numpy
>>>
>>> # generate a set of dates
>>> hours = numpy.arange(0,24,dtype = int)
>>> dates = numpy.array( [ datetime.datetime(2018,2,15,h) for h in hours ] )
>>>
>>> # generate a sine wave for plotting purposes
>>> sine = numpy.sin(hours*2*numpy.pi/24)
>>>
>>> # plot the sine wave using the datetime objects as the x values
>>> pylab.plot(dates,sine)
[<matplotlib.lines.Line2D at 0x2aaad2e69588>]
>>># run the datetime objects through cftime routines to produce `real_datetime` objects
>>> units = "hours since 2018-02-15 00:00:00"
>>> hours_since = cftime.date2num(dates, units)
>>> dates_cftime = cftime.num2date(hours_since, units)
>>>
>>> # attempt to plot using the real_datetime objects as the x values
>>> pylab.plot(dates_cftime, sine)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-0587aadf3c86> in <module>()
3 dates_cftime = cftime.num2date(hours_since, units)
4
----> 5 pylab.plot(dates_cftime, sine)
... (ommitting most of the traceback)
TypeError: float() argument must be a string or a number, not 'real_datetime'
In the older netCDF4 versions of num2date(), the return value was a datetime object, so code like the above would work. The change to real_datetime objects appears to break this type of code.
One workaround, based on the matplotlib units API, is to explicitly tell matplotlib to treat real_datetime objects like datetime objects:
>>> # fix a plotting issue with netCDF4
>>> import matplotlib
>>> matplotlib.units.registry[cftime.real_datetime] = matplotlib.units.registry[datetime.datetime]
>>>
>>> pylab.plot(dates_cftime, sine)
[<matplotlib.lines.Line2D at 0x2aaadba09b00>]
Given what I understand about cftime's real_datetime objects, I'm not sure this is a good, general purpose workaround, since matplotlib likely assumes a proleptic gregorian calendar. I suspect a better solution would be for cftime to have a converter routine and to work with the matplotlib developers to automatically register the cftime converter routine if cftime is importable.
Matplotlib appears not to immediately recognize the
real_datetime
objects used bycftime
asdatetime
objects, even though they are simply datetime objects with a couple extra properties.The code below illustrates the issue:
This first block of code demonstrates that matplotlib deals with datetime objects for plotting.
In the older netCDF4 versions of
num2date()
, the return value was adatetime
object, so code like the above would work. The change toreal_datetime
objects appears to break this type of code.One workaround, based on the matplotlib units API, is to explicitly tell matplotlib to treat
real_datetime
objects likedatetime
objects:Given what I understand about cftime's
real_datetime
objects, I'm not sure this is a good, general purpose workaround, since matplotlib likely assumes a proleptic gregorian calendar. I suspect a better solution would be for cftime to have a converter routine and to work with the matplotlib developers to automatically register the cftime converter routine if cftime is importable.