Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove cftime.utime #59

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 41 additions & 24 deletions nc_time_axis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CalendarDateTime(object):
Container for :class:`cftime.datetime` object and calendar.

"""

def __init__(self, datetime, calendar):
self.datetime = datetime
self.calendar = calendar
Expand Down Expand Up @@ -81,7 +82,7 @@ def pick_format(self, ndays):

def __call__(self, x, pos=0):
format_string = self.pick_format(ndays=self.locator.ndays)
dt = cftime.utime(self.time_units, self.calendar).num2date(x)
dt = cftime.num2date(x, self.time_units, self.calendar)
return dt.strftime(format_string)


Expand All @@ -90,6 +91,7 @@ class NetCDFTimeDateLocator(mticker.Locator):
Determines tick locations when plotting cftime.datetime data.

"""

def __init__(self, max_n_ticks, calendar, date_unit, min_n_ticks=3):
# The date unit must be in the form of days since ...

Expand Down Expand Up @@ -143,17 +145,17 @@ def tick_values(self, vmin, vmax):

self.ndays = float(abs(vmax - vmin))

utime = cftime.utime(self.date_unit, self.calendar)
lower = utime.num2date(vmin)
upper = utime.num2date(vmax)
lower = cftime.num2date(vmin, self.date_unit, self.calendar)
upper = cftime.num2date(vmax, self.date_unit, self.calendar)

resolution, n = self.compute_resolution(vmin, vmax, lower, upper)

if resolution == 'YEARLY':
# TODO START AT THE BEGINNING OF A DECADE/CENTURY/MILLENIUM as
# appropriate.
years = self._max_n_locator.tick_values(lower.year, upper.year)
ticks = [cftime.datetime(int(year), 1, 1) for year in years]
ticks = [cftime.datetime(int(year), 1, 1, calendar=self.calendar)
for year in years]
elif resolution == 'MONTHLY':
# TODO START AT THE BEGINNING OF A DECADE/CENTURY/MILLENIUM as
# appropriate.
Expand All @@ -162,31 +164,42 @@ def tick_values(self, vmin, vmax):
for offset in months_offset:
year = lower.year + np.floor((lower.month + offset) / 12)
month = ((lower.month + offset) % 12) + 1
ticks.append(cftime.datetime(int(year), int(month), 1))
ticks.append(
cftime.datetime(
int(year), int(month), 1, calendar=self.calendar
)
)
elif resolution == 'DAILY':
# TODO: It would be great if this favoured multiples of 7.
days = self._max_n_locator_days.tick_values(vmin, vmax)
ticks = [utime.num2date(dt) for dt in days]
ticks = [cftime.num2date(dt, self.date_unit, self.calendar)
for dt in days]
elif resolution == 'HOURLY':
hour_unit = 'hours since 2000-01-01'
hour_utime = cftime.utime(hour_unit, self.calendar)
in_hours = hour_utime.date2num([lower, upper])
in_hours = cftime.date2num(
[lower, upper], hour_unit, self.calendar
)
hours = self._max_n_locator.tick_values(in_hours[0], in_hours[1])
ticks = [hour_utime.num2date(dt) for dt in hours]
ticks = [cftime.num2date(dt, hour_unit, self.calendar)
for dt in hours]
elif resolution == 'MINUTELY':
minute_unit = 'minutes since 2000-01-01'
minute_utime = cftime.utime(minute_unit, self.calendar)
in_minutes = minute_utime.date2num([lower, upper])
in_minutes = cftime.date2num(
[lower, upper], minute_unit, self.calendar
)
minutes = self._max_n_locator.tick_values(in_minutes[0],
in_minutes[1])
ticks = [minute_utime.num2date(dt) for dt in minutes]
ticks = [cftime.num2date(dt, minute_unit, self.calendar)
for dt in minutes]
elif resolution == 'SECONDLY':
second_unit = 'seconds since 2000-01-01'
second_utime = cftime.utime(second_unit, self.calendar)
in_seconds = second_utime.date2num([lower, upper])
in_seconds = cftime.date2num(
[lower, upper], second_unit, self.calendar
)
seconds = self._max_n_locator.tick_values(in_seconds[0],
in_seconds[1])
ticks = [second_utime.num2date(dt) for dt in seconds]
ticks = [cftime.num2date(dt, second_unit, self.calendar)
for dt in seconds]
else:
msg = 'Resolution {} not implemented yet.'.format(resolution)
raise ValueError(msg)
Expand All @@ -197,9 +210,9 @@ def tick_values(self, vmin, vmax):
"gregorian",
"julian",
"standard",
]:
]:
ticks = [t for t in ticks if t.year != 0]
return utime.date2num(ticks)
return cftime.date2num(ticks, self.date_unit, self.calendar)


class NetCDFTimeConverter(mdates.DateConverter):
Expand Down Expand Up @@ -265,13 +278,13 @@ def default_units(cls, sample_point, axis):
def convert(cls, value, unit, axis):
"""
Converts value, if it is not already a number or sequence of numbers,
with :func:`cftime.utime().date2num`.
with :func:`cftime.date2num`.

"""
shape = None
if isinstance(value, np.ndarray):
# Don't do anything with numeric types.
if value.dtype != np.object:
if value.dtype != object:
return value
shape = value.shape
value = value.reshape(-1)
Expand All @@ -293,15 +306,19 @@ def convert(cls, value, unit, axis):
'CalendarDateTime object must be of type '
'`cftime.datetime`.')

ut = cftime.utime(cls.standard_unit, calendar=first_value.calendar)

if isinstance(value, (CalendarDateTime, cftime.datetime)):
value = [value]

if isinstance(first_value, CalendarDateTime):
result = ut.date2num([v.datetime for v in value])
result = cftime.date2num(
[v.datetime for v in value],
cls.standard_unit,
first_value.calendar
)
else:
result = ut.date2num(value)
result = cftime.date2num(
value, cls.standard_unit, first_value.calendar
)

if shape is not None:
result = result.reshape(shape)
Expand Down
4 changes: 3 additions & 1 deletion nc_time_axis/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
# Pick the first branch that is returned. Good or bad.
branch_name = branches[0]

branch_name = branch_name.replace(' ', '.').replace('(', '').replace(')', '')
branch_name = branch_name.replace(
' ', '.'
).replace('(', '').replace(')', '')

pieces['branch'] = branch_name

Expand Down
2 changes: 1 addition & 1 deletion nc_time_axis/tests/integration/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def tearDown(self):
plt.close('all')

def test_360_day_calendar_CalendarDateTime(self):
datetimes = [cftime.datetime(1986, month, 30)
datetimes = [cftime.datetime(1986, month, 30, calendar='360_day')
for month in range(1, 6)]
cal_datetimes = [nc_time_axis.CalendarDateTime(dt, '360_day')
for dt in datetimes]
Expand Down
4 changes: 2 additions & 2 deletions nc_time_axis/tests/unit/test_NetCDFTimeConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ def test_cftime_raw_date(self):

def test_cftime_np_array_CalendarDateTime(self):
val = np.array([CalendarDateTime(cftime.datetime(2012, 6, 4),
'360_day')], dtype=np.object)
'360_day')], dtype=object)
result = NetCDFTimeConverter().convert(val, None, None)
self.assertEqual(result, np.array([4473.]))

def test_cftime_np_array_raw_date(self):
val = np.array([cftime.Datetime360Day(2012, 6, 4)], dtype=np.object)
val = np.array([cftime.Datetime360Day(2012, 6, 4)], dtype=object)
result = NetCDFTimeConverter().convert(val, None, None)
self.assertEqual(result, np.array([4473.]))

Expand Down
13 changes: 8 additions & 5 deletions nc_time_axis/tests/unit/test_NetCDFTimeDateLocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ def check(self, max_n_ticks, num1, num2):
locator = NetCDFTimeDateLocator(max_n_ticks=max_n_ticks,
calendar=self.calendar,
date_unit=self.date_unit)
utime = cftime.utime(self.date_unit, self.calendar)
return locator.compute_resolution(num1, num2, utime.num2date(num1),
utime.num2date(num2))
return locator.compute_resolution(
num1,
num2,
cftime.num2date(num1, self.date_unit, self.calendar),
cftime.num2date(num2, self.date_unit, self.calendar)
)

def test_one_minute(self):
self.assertEqual(self.check(20, 0, 0.0003),
Expand Down Expand Up @@ -146,9 +149,9 @@ def check(self, max_n_ticks, num1, num2, calendar):
def test_yearly_yr0_remove(self):
for calendar in self.all_calendars:
# convert values to dates, check that none of them has year 0
num2date = cftime.utime(self.date_unit, calendar).num2date
ticks = self.check(5, 0, 100 * 365, calendar)
year_ticks = [num2date(t).year for t in ticks]
year_ticks = [cftime.num2date(t, self.date_unit, calendar).year
for t in ticks]
if calendar in self.yr0_remove_calendars:
self.assertNotIn(0, year_ticks)
else:
Expand Down
12 changes: 6 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
packages = []
for d, _, _ in os.walk(os.path.join(here, 'nc_time_axis')):
if os.path.exists(os.path.join(d, '__init__.py')):
packages.append(d[len(here)+1:].replace(os.path.sep, '.'))
packages.append(d[len(here) + 1:].replace(os.path.sep, '.'))

setup_args = dict(
name='nc-time-axis',
Expand All @@ -20,11 +20,11 @@
author='Laura Dreyer, Philip Elson',
url='https://github.com/scitools/nc-time-axis',
packages=packages,
install_requires = ['cftime',
'matplotlib',
'numpy',
'six'],
tests_require = ['mock', 'pep8'],
install_requires=['cftime>=1.2',
'matplotlib',
'numpy',
'six'],
tests_require=['mock', 'pep8'],
test_suite='nc_time_axis.tests'
)

Expand Down