Skip to content
Permalink
Browse files

Datetime improvements (#2267)

  • Loading branch information...
philippjfr authored and Philipp Rudiger committed Jan 26, 2018
1 parent 08eaebf commit 7a17cd98176d42552eae7a89363255554d43ac5b
@@ -1,3 +1,5 @@
from datetime import date, datetime

from .boundingregion import * # noqa (API import)
from .data import * # noqa (API import)
from .dimension import * # noqa (API import)
@@ -24,6 +26,8 @@
Dimension.type_formatters[np.float32] = "%.5g"
Dimension.type_formatters[np.float64] = "%.5g"
Dimension.type_formatters[np.datetime64] = '%Y-%m-%d %H:%M:%S'
Dimension.type_formatters[datetime] = '%Y-%m-%d %H:%M:%S'
Dimension.type_formatters[date] = '%Y-%m-%d'

try:
import pandas as pd
@@ -281,7 +281,7 @@ def indexed(cls, dataset, selection):
@classmethod
def range(cls, dataset, dimension):
column = dataset.dimension_values(dimension)
if dataset.get_dimension_type(dimension) is np.datetime64:
if column.dtype.kind == 'M':
return column.min(), column.max()
else:
try:
@@ -449,7 +449,7 @@ def pprint_value(self, value):
if callable(formatter):
return formatter(value)
elif isinstance(formatter, basestring):
if isinstance(value, dt.datetime):
if isinstance(value, (dt.datetime, dt.date)):
return value.strftime(formatter)
elif isinstance(value, np.datetime64):
return dt64_to_dt(value).strftime(formatter)
@@ -28,7 +28,7 @@
except:
import builtins as builtins # noqa (compatibility)

datetime_types = (np.datetime64, dt.datetime)
datetime_types = (np.datetime64, dt.datetime, dt.date)
timedelta_types = (np.timedelta64, dt.timedelta,)

try:
@@ -292,22 +292,26 @@ def _axes_props(self, plots, subplots, element, ranges):
if plots and self.shared_axes and not norm_opts.get('axiswise', False):
plot_ranges = self._merge_ranges(plots, xlabel, ylabel)

if el.get_dimension_type(0) in util.datetime_types:
x_axis_type = 'datetime'
else:
x_axis_type = 'log' if self.logx else 'auto'

if len(dims) > 1 and el.get_dimension_type(1) in util.datetime_types:
y_axis_type = 'datetime'
else:
y_axis_type = 'log' if self.logy else 'auto'

# Get the Element that determines the range and get_extents
range_el = el if self.batched and not isinstance(self, OverlayPlot) else element
l, b, r, t = self.get_extents(range_el, ranges)
if self.invert_axes:
l, b, r, t = b, l, t, r

xtype = el.get_dimension_type(0)
if ((xtype is np.object_ and type(l) in util.datetime_types) or
xtype in util.datetime_types):
x_axis_type = 'datetime'
else:
x_axis_type = 'log' if self.logx else 'auto'

y_axis_type = 'log' if self.logy else 'auto'
if len(dims) > 1:
ytype = el.get_dimension_type(1)
if ((ytype is np.object_ and type(b) in util.datetime_types)
or ytype in util.datetime_types):
y_axis_type = 'datetime'

# Declare shared axes
if 'x_range' in plot_ranges:
self._shared['x'] = True
@@ -1,10 +1,14 @@
from bokeh.models.widgets import DataTable, TableColumn

import param

from ...core import Dataset
from bokeh.models.widgets import (
DataTable, TableColumn, NumberEditor, NumberFormatter, DateFormatter,
TimeEditor, StringFormatter, StringEditor, IntEditor
)

from ...core import Dataset, Dimension
from ...element import ItemTable
from ...streams import Buffer
from ...core.util import dimension_sanitizer, datetime_types
from ..plot import GenericElementPlot
from .plot import BokehPlot

@@ -46,12 +50,8 @@ def _execute_hooks(self, element):


def get_data(self, element, ranges, style):
dims = element.dimensions()
mapping = {d.name: d.name for d in dims}
data = {d: element.dimension_values(d) for d in dims}
data = {d.name: values if values.dtype.kind in "if" else list(map(d.pprint_value, values))
for d, values in data.items()}
return data, mapping, style
return ({dimension_sanitizer(d.name): element.dimension_values(d)
for d in element.dimensions()}, {}, style)


def initialize_plot(self, ranges=None, plot=None, plots=None, source=None):
@@ -70,8 +70,28 @@ def initialize_plot(self, ranges=None, plot=None, plots=None, source=None):
source = self._init_datasource(data)
self.handles['source'] = source

columns = []
dims = element.dimensions()
columns = [TableColumn(field=d.name, title=d.pprint_label) for d in dims]
for d in dims:
col = dimension_sanitizer(d.name)
kind = data[col].dtype.kind
if kind == 'i':
formatter = NumberFormatter()
editor = IntEditor()
elif kind == 'f':
formatter = NumberFormatter(format='0,0.0[00000]')
editor = NumberEditor()
elif kind == 'M' or (kind == 'O' and type(data[col][0]) in datetime_types):
dimtype = element.get_dimension_type(0)
dformat = Dimension.type_formatters.get(dimtype, '%Y-%m-%d %H:%M:%S')
formatter = DateFormatter(format=dformat)
editor = TimeEditor()
else:
formatter = StringFormatter()
editor = StringEditor()
column = TableColumn(field=d.name, title=d.pprint_label,
editor=editor, formatter=formatter)
columns.append(column)
style['reorderable'] = False
table = DataTable(source=source, columns=columns, height=self.height,
width=self.width, **style)
@@ -597,7 +597,7 @@ def date_to_integer(date):
date = dt64_to_dt(date)
elif pd and isinstance(date, pd.Timestamp):
date = date.to_pydatetime()
if isinstance(date, dt.datetime):
if isinstance(date, (dt.datetime, dt.date)):
dt_int = time.mktime(date.timetuple())*1000
else:
raise ValueError('Datetime type not recognized')
@@ -72,7 +72,8 @@ def get_data(self, element, ranges, style):
ys = element.dimension_values(1)
dims = element.dimensions()
if xs.dtype.kind == 'M':
dt_format = Dimension.type_formatters[np.datetime64]
dimtype = element.get_dimension_type(0)
dt_format = Dimension.type_formatters.get(dimtype, '%Y-%m-%d %H:%M:%S')
dims[0] = dims[0](value_format=DateFormatter(dt_format))
coords = (ys, xs) if self.invert_axes else (xs, ys)
return coords, style, {'dimensions': dims}

0 comments on commit 7a17cd9

Please sign in to comment.
You can’t perform that action at this time.