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

Fix for mid date interpolation #2757

Merged
merged 6 commits into from
Jun 20, 2018
Merged
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
4 changes: 4 additions & 0 deletions holoviews/element/comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ def compare_floats(cls, arr1, arr2, msg='Floats'):
@classmethod
def compare_arrays(cls, arr1, arr2, msg='Arrays'):
try:
if arr1.dtype.kind == 'M':
arr1 = arr1.astype('datetime64[ns]').astype('int64')
if arr2.dtype.kind == 'M':
arr2 = arr2.astype('datetime64[ns]').astype('int64')
assert_array_equal(arr1, arr2)
except:
try:
Expand Down
82 changes: 53 additions & 29 deletions holoviews/operation/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,45 +674,70 @@ class interpolate_curve(Operation):
Controls the transition point of the step along the x-axis.""")

@classmethod
def pts_to_prestep(cls, x, y):
steps = np.zeros((2, 2 * len(x) - 1))
steps[0, 0::2] = x
steps[0, 1::2] = steps[0, 0:-2:2]
steps[1:, 0::2] = y
steps[1:, 1::2] = steps[1:, 2::2]
return steps
def pts_to_prestep(cls, x, values):
steps = np.zeros(2 * len(x) - 1)
value_steps = tuple(np.empty(2 * len(x) - 1, dtype=v.dtype) for v in values)

steps[0::2] = x
steps[1::2] = steps[0:-2:2]

val_arrays = []
for v, s in zip(values, value_steps):
s[0::2] = v
s[1::2] = s[2::2]
val_arrays.append(s)

return steps, tuple(val_arrays)

@classmethod
def pts_to_midstep(cls, x, y):
steps = np.zeros((2, 2 * len(x)))
x = np.asanyarray(x)
steps[0, 1:-1:2] = steps[0, 2::2] = (x[:-1] + x[1:]) / 2
steps[0, 0], steps[0, -1] = x[0], x[-1]
steps[1:, 0::2] = y
steps[1:, 1::2] = steps[1:, 0::2]
return steps
def pts_to_midstep(cls, x, values):
steps = np.zeros(2 * len(x))
value_steps = tuple(np.empty(2 * len(x), dtype=v.dtype) for v in values)

steps[1:-1:2] = steps[2::2] = x[:-1] + (x[1:] - x[:-1])/2
steps[0], steps[-1] = x[0], x[-1]

val_arrays = []
for v, s in zip(values, value_steps):
s[0::2] = v
s[1::2] = s[0::2]
val_arrays.append(s)

return steps, tuple(val_arrays)

@classmethod
def pts_to_poststep(cls, x, y):
steps = np.zeros((2, 2 * len(x) - 1))
steps[0, 0::2] = x
steps[0, 1::2] = steps[0, 2::2]
steps[1:, 0::2] = y
steps[1:, 1::2] = steps[1:, 0:-2:2]
return steps
def pts_to_poststep(cls, x, values):
steps = np.zeros(2 * len(x) - 1)
value_steps = tuple(np.empty(2 * len(x) - 1, dtype=v.dtype) for v in values)

steps[0::2] = x
steps[1::2] = steps[2::2]

val_arrays = []
for v, s in zip(values, value_steps):
s[0::2] = v
s[1::2] = s[0:-2:2]
val_arrays.append(s)

return steps, tuple(val_arrays)

def _process_layer(self, element, key=None):
INTERPOLATE_FUNCS = {'steps-pre': self.pts_to_prestep,
'steps-mid': self.pts_to_midstep,
'steps-post': self.pts_to_poststep}
if self.p.interpolation not in INTERPOLATE_FUNCS:
return element
x, y = element.dimension_values(0), element.dimension_values(1)
if 'f' in (x.dtype.kind, y.dtype.kind):
x, y = x.astype('float'), y.astype('float')
array = INTERPOLATE_FUNCS[self.p.interpolation](x, y)
dvals = tuple(element.dimension_values(d) for d in element.dimensions()[2:])
return element.clone((array[0, :].astype(x.dtype), array[1, :].astype(y.dtype))+dvals)
x = element.dimension_values(0)
dtype = x.dtype
is_datetime = dtype.kind == 'M' or isinstance(x[0], datetime_types)
if is_datetime:
dt_type = dtype if dtype.kind == 'M' else 'datetime64[ns]'
x = x.astype(dt_type).astype('int64')
dvals = tuple(element.dimension_values(d) for d in element.dimensions()[1:])
xs, dvals = INTERPOLATE_FUNCS[self.p.interpolation](x.astype('f'), dvals)
if is_datetime:
xs = xs.astype(dt_type)
return element.clone((xs,)+dvals)

def _process(self, element, key=None):
return element.map(self._process_layer, Element)
Expand Down Expand Up @@ -833,4 +858,3 @@ def _process(self, p, element, ranges={}):
datatype=['dataframe', 'dictionary'])
data[(d1.name, d2.name)] = el
return data

61 changes: 61 additions & 0 deletions tests/operation/testoperation.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,77 @@ def test_interpolate_curve_pre(self):
curve = Curve([(0, 0), (0, 0.5), (1, 0.5), (1, 1), (2, 1)])
self.assertEqual(interpolated, curve)

def test_interpolate_curve_pre_with_values(self):
interpolated = interpolate_curve(Curve([(0, 0, 'A'), (1, 0.5, 'B'), (2, 1, 'C')], vdims=['y', 'z']),
interpolation='steps-pre')
curve = Curve([(0, 0, 'A'), (0, 0.5, 'B'), (1, 0.5, 'B'), (1, 1, 'C'), (2, 1, 'C')], vdims=['y', 'z'])
self.assertEqual(interpolated, curve)

def test_interpolate_datetime_curve_pre(self):
dates = np.array([dt.datetime(2017, 1, i) for i in range(1, 5)]).astype('M')
values = [0, 1, 2, 3]
interpolated = interpolate_curve(Curve((dates, values)), interpolation='steps-pre')
dates_interp = np.array([
'2017-01-01T00:00:16.364011520', '2017-01-01T00:00:16.364011520',
'2017-01-02T00:01:05.465745408', '2017-01-02T00:01:05.465745408',
'2017-01-02T23:59:37.128525824', '2017-01-02T23:59:37.128525824',
'2017-01-04T00:00:26.230259712'
], dtype='datetime64[ns]')
curve = Curve((dates_interp, [0, 1, 1, 2, 2, 3, 3]))
self.assertEqual(interpolated, curve)

def test_interpolate_curve_mid(self):
interpolated = interpolate_curve(Curve([0, 0.5, 1]), interpolation='steps-mid')
curve = Curve([(0, 0), (0.5, 0), (0.5, 0.5), (1.5, 0.5), (1.5, 1), (2, 1)])
self.assertEqual(interpolated, curve)

def test_interpolate_curve_mid_with_values(self):
interpolated = interpolate_curve(Curve([(0, 0, 'A'), (1, 0.5, 'B'), (2, 1, 'C')], vdims=['y', 'z']),
interpolation='steps-mid')
curve = Curve([(0, 0, 'A'), (0.5, 0, 'A'), (0.5, 0.5, 'B'),
(1.5, 0.5, 'B'), (1.5, 1, 'C'), (2, 1, 'C')],
vdims=['y', 'z'])
self.assertEqual(interpolated, curve)

def test_interpolate_datetime_curve_mid(self):
dates = np.array([dt.datetime(2017, 1, i) for i in range(1, 5)]).astype('M')
values = [0, 1, 2, 3]
interpolated = interpolate_curve(Curve((dates, values)), interpolation='steps-mid')
dates_interp = np.array([
'2017-01-01T00:00:16.364011520', '2017-01-01T11:59:32.195401728',
'2017-01-01T11:59:32.195401728', '2017-01-02T12:00:21.297135616',
'2017-01-02T12:00:21.297135616', '2017-01-03T12:01:10.398869504',
'2017-01-03T12:01:10.398869504', '2017-01-04T00:00:26.230259712'
], dtype='datetime64[ns]')
curve = Curve((dates_interp, [0, 0, 1, 1, 2, 2, 3, 3]))
self.assertEqual(interpolated, curve)

def test_interpolate_curve_post(self):
interpolated = interpolate_curve(Curve([0, 0.5, 1]), interpolation='steps-post')
curve = Curve([(0, 0), (1, 0), (1, 0.5), (2, 0.5), (2, 1)])
self.assertEqual(interpolated, curve)

def test_interpolate_curve_post_with_values(self):
interpolated = interpolate_curve(Curve([(0, 0, 'A'), (1, 0.5, 'B'), (2, 1, 'C')], vdims=['y', 'z']),
interpolation='steps-post')
curve = Curve([(0, 0, 'A'), (1, 0, 'A'), (1, 0.5, 'B'),
(2, 0.5, 'B'), (2, 1, 'C')],
vdims=['y', 'z'])
self.assertEqual(interpolated, curve)

def test_interpolate_datetime_curve_post(self):
dates = np.array([dt.datetime(2017, 1, i) for i in range(1, 5)]).astype('M')
values = [0, 1, 2, 3]
interpolated = interpolate_curve(Curve((dates, values)), interpolation='steps-post')
dates_interp = np.array([
'2017-01-01T00:00:16.364011520', '2017-01-02T00:01:05.465745408',
'2017-01-02T00:01:05.465745408', '2017-01-02T23:59:37.128525824',
'2017-01-02T23:59:37.128525824', '2017-01-04T00:00:26.230259712',
'2017-01-04T00:00:26.230259712'
], dtype='datetime64[ns]')
curve = Curve((dates_interp, [0, 0, 1, 1, 2, 2, 3]))
self.assertEqual(interpolated, curve)

def test_stack_area_overlay(self):
areas = Area([1, 2, 3]) * Area([1, 2, 3])
stacked = Area.stack(areas)
Expand Down