Skip to content

Commit

Permalink
Merge pull request #816 from ioam/datetime64_fixes
Browse files Browse the repository at this point in the history
Datetime64 fixes
  • Loading branch information
jlstevens authored Aug 18, 2016
2 parents a8bce95 + 613e82f commit 2b5e4a0
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 34 deletions.
1 change: 1 addition & 0 deletions holoviews/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Dimension.type_formatters[float] = "%.5g"
Dimension.type_formatters[np.float32] = "%.5g"
Dimension.type_formatters[np.float64] = "%.5g"
Dimension.type_formatters[np.datetime64] = '%Y-%m-%d %H:%M:%S'


def public(obj):
Expand Down
2 changes: 1 addition & 1 deletion holoviews/core/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def get_dimension_type(self, dim):
dim_obj = self.get_dimension(dim)
if dim_obj and dim_obj.type is not None:
return dim_obj.type
return self.interface.dimension_type(self, dim)
return self.interface.dimension_type(self, dim_obj)


def dframe(self, dimensions=None):
Expand Down
6 changes: 2 additions & 4 deletions holoviews/core/data/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,8 @@ def validate(cls, dataset):

@classmethod
def dimension_type(cls, dataset, dim):
if dim in dataset.kdims:
arr = dataset.data[dim.name]
elif dim in dataset.vdims:
arr = dataset.data[dim.name]
if dim in dataset.dimensions():
arr = cls.values(dataset, dim, False, False)
else:
return None
return arr.dtype.type
Expand Down
5 changes: 4 additions & 1 deletion holoviews/core/data/xarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ def range(cls, dataset, dimension):
dim = dataset.get_dimension(dimension).name
if dim in dataset.data:
data = dataset.data[dim]
return data.min().item(), data.max().item()
dmin, dmax = data.min().data, data.max().data
dmin = dmin if np.isscalar(dmin) else dmin.item()
dmax = dmax if np.isscalar(dmax) else dmax.item()
return dmin, dmax
else:
return np.NaN, np.NaN

Expand Down
9 changes: 7 additions & 2 deletions holoviews/core/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""
from __future__ import unicode_literals
import re
import datetime as dt
from operator import itemgetter

import numpy as np
Expand All @@ -13,7 +14,7 @@
from ..core.util import (basestring, sanitize_identifier,
group_sanitizer, label_sanitizer, max_range,
find_range, dimension_sanitizer, OrderedDict,
safe_unicode, unicode)
safe_unicode, unicode, dt64_to_dt)
from .options import Store, StoreOptions
from .pprint import PrettyPrinter

Expand Down Expand Up @@ -178,7 +179,11 @@ def pprint_value(self, value):
if callable(formatter):
return formatter(value)
elif isinstance(formatter, basestring):
if re.findall(r"\{(\w+)\}", formatter):
if isinstance(value, dt.datetime):
return value.strftime(formatter)
elif isinstance(value, np.datetime64):
return dt64_to_dt(value).strftime(formatter)
elif re.findall(r"\{(\w+)\}", formatter):
return formatter.format(value)
else:
return formatter % value
Expand Down
8 changes: 8 additions & 0 deletions holoviews/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import itertools
import string, fnmatch
import unicodedata
import datetime as dt
from collections import defaultdict

import numpy as np
Expand Down Expand Up @@ -917,3 +918,10 @@ def expand_grid_coords(dataset, dim):
idx = dataset.get_dimension_index(dim)
return cartesian_product(arrays)[idx]


def dt64_to_dt(dt64):
"""
Safely converts NumPy datetime64 to a datetime object.
"""
ts = (dt64 - np.datetime64('1970-01-01T00:00:00Z')) / np.timedelta64(1, 's')
return dt.datetime.utcfromtimestamp(ts)
17 changes: 15 additions & 2 deletions holoviews/plotting/mpl/chart.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from __future__ import unicode_literals

from itertools import product

import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.dates import date2num, DateFormatter

import param

from ...core import OrderedDict
from ...core import OrderedDict, Dimension
from ...core.util import (match_spec, unique_iterator, safe_unicode,
basestring, max_range, unicode)
from ...element import Points, Raster, Polygons, HeatMap
Expand Down Expand Up @@ -59,8 +61,19 @@ class CurvePlot(ChartPlot):
def get_data(self, element, ranges, style):
xs = element.dimension_values(0)
ys = element.dimension_values(1)
return (xs, ys), style, {}
dims = element.dimensions()
if xs.dtype.kind == 'M':
dt_format = Dimension.type_formatters[np.datetime64]
dims[0] = dims[0](value_format=DateFormatter(dt_format))
return (xs, ys), style, {'dimensions': dims}

def init_artists(self, ax, plot_args, plot_kwargs):
xs, ys = plot_args
if xs.dtype.kind == 'M':
artist = ax.plot_date(xs, ys, '-', **plot_kwargs)[0]
else:
artist = ax.plot(xs, ys, **plot_kwargs)[0]
return {'artist': artist}

def update_handles(self, key, axis, element, ranges, style):
artist = self.handles['artist']
Expand Down
11 changes: 7 additions & 4 deletions holoviews/plotting/mpl/element.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import math

import param
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker
from matplotlib import colors
import matplotlib.pyplot as plt
import numpy as np
import param
from matplotlib.dates import date2num

from ...core import util
from ...core import (OrderedDict, NdOverlay, DynamicMap,
Expand Down Expand Up @@ -301,7 +302,9 @@ def _set_axis_limits(self, axis, view, subplots, ranges):
scalex, scaley = True, True
extents = self.get_extents(view, ranges)
if extents and not self.overlaid:
coords = [coord if np.isreal(coord) else np.NaN for coord in extents]
coords = [coord if np.isreal(coord) or isinstance(coord, np.datetime64) else np.NaN for coord in extents]
coords = [date2num(util.dt64_to_dt(c)) if isinstance(c, np.datetime64) else c
for c in coords]
valid_lim = lambda c: util.isnumeric(c) and not np.isnan(c)
if self.projection == '3d' or len(extents) == 6:
l, b, zmin, r, t, zmax = coords
Expand Down
22 changes: 4 additions & 18 deletions holoviews/plotting/mpl/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,6 @@ class GridPlot(CompositePlot):
show_legend = param.Boolean(default=False, doc="""
Legends add to much clutter in a grid and are disabled by default.""")

tick_format = param.String(default="%.2f", doc="""
Formatting string for the GridPlot ticklabels.""")

xaxis = param.ObjectSelector(default='bottom',
objects=['bottom', 'top', None], doc="""
Whether and where to display the xaxis, supported options are
Expand Down Expand Up @@ -496,13 +493,15 @@ def _layout_axis(self, layout, axis):
yticks = [(plot_height/2)+(r*(plot_height+border_height)) for r in range(self.rows)]

layout_axis.set_xticks(xticks)
layout_axis.set_xticklabels(self._process_ticklabels(sorted(set(dim1_keys)), dims[0]))
layout_axis.set_xticklabels([dims[0].pprint_value(l)
for l in sorted(set(dim1_keys))])
for tick in layout_axis.get_xticklabels():
tick.set_rotation(self.xrotation)

ydim = dims[1] if layout.ndims > 1 else None
layout_axis.set_yticks(yticks)
layout_axis.set_yticklabels(self._process_ticklabels(sorted(set(dim2_keys)), ydim))
layout_axis.set_yticklabels([ydim.pprint_value(l) if ydim else ''
for l in sorted(set(dim2_keys))])
for tick in layout_axis.get_yticklabels():
tick.set_rotation(self.yrotation)

Expand All @@ -529,19 +528,6 @@ def _layout_axis(self, layout, axis):
return layout_axis


def _process_ticklabels(self, labels, dim):
formatted_labels = []
for k in labels:
if dim and dim.value_format:
k = dim.value_format(k)
elif not isinstance(k, (str, type(None))):
k = self.tick_format % k
elif k is None:
k = ''
formatted_labels.append(k)
return formatted_labels


def _adjust_subplots(self, axis, subaxes):
bbox = axis.get_position()
l, b, w, h = bbox.x0, bbox.y0, bbox.width, bbox.height
Expand Down
5 changes: 3 additions & 2 deletions holoviews/plotting/mpl/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,9 @@ def update_frame(self, key, ranges=None):
def _get_axis_kwargs(self):
xdim = self.layout.kdims[0]
ydim = self.layout.kdims[1] if self.layout.ndims > 1 else None
xticks = (self._xticks, self._process_ticklabels(self._xkeys, xdim))
yticks = (self._yticks, self._process_ticklabels(self._ykeys, ydim))
xticks = (self._xticks, [xdim.pprint_value(l) for l in self._xkeys])
yticks = (self._yticks, [ydim.pprint_value(l) if ydim else ''
for l in self._ykeys])
return dict(xlabel=xdim.pprint_label, ylabel=ydim.pprint_label if ydim else '',
xticks=xticks, yticks=yticks)

Expand Down

0 comments on commit 2b5e4a0

Please sign in to comment.