diff --git a/nc_time_axis/__init__.py b/nc_time_axis/__init__.py index b3e0804..c05e6e6 100644 --- a/nc_time_axis/__init__.py +++ b/nc_time_axis/__init__.py @@ -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 @@ -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) @@ -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 ... @@ -143,9 +145,8 @@ 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) @@ -153,7 +154,8 @@ def tick_values(self, vmin, vmax): # 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. @@ -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) @@ -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): @@ -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) @@ -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) diff --git a/nc_time_axis/_version.py b/nc_time_axis/_version.py index d2eef2a..970ab03 100644 --- a/nc_time_axis/_version.py +++ b/nc_time_axis/_version.py @@ -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 diff --git a/nc_time_axis/tests/integration/test_plot.py b/nc_time_axis/tests/integration/test_plot.py index ba1d5b7..780a8fd 100644 --- a/nc_time_axis/tests/integration/test_plot.py +++ b/nc_time_axis/tests/integration/test_plot.py @@ -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] diff --git a/nc_time_axis/tests/unit/test_NetCDFTimeConverter.py b/nc_time_axis/tests/unit/test_NetCDFTimeConverter.py index 5d5edaf..2fa0c42 100644 --- a/nc_time_axis/tests/unit/test_NetCDFTimeConverter.py +++ b/nc_time_axis/tests/unit/test_NetCDFTimeConverter.py @@ -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.])) diff --git a/nc_time_axis/tests/unit/test_NetCDFTimeDateLocator.py b/nc_time_axis/tests/unit/test_NetCDFTimeDateLocator.py index ed48f43..25cdb42 100644 --- a/nc_time_axis/tests/unit/test_NetCDFTimeDateLocator.py +++ b/nc_time_axis/tests/unit/test_NetCDFTimeDateLocator.py @@ -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), @@ -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: diff --git a/setup.py b/setup.py index 3ac3be7..ea6e07c 100644 --- a/setup.py +++ b/setup.py @@ -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', @@ -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' )