Skip to content

Commit

Permalink
Merge pull request #211 from janezd/interpolate-facelift
Browse files Browse the repository at this point in the history
Interpolate: Facelift
  • Loading branch information
ajdapretnar committed Jun 17, 2022
2 parents 8afa300 + cfbf385 commit e71d462
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 45 deletions.
2 changes: 2 additions & 0 deletions orangecontrib/timeseries/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ def interpolate_timeseries(data, method='linear', multivariate=False):
from Orange.data import Domain
from orangecontrib.timeseries import Timeseries

assert method in ("linear", "cubic", "mean", "nearest")

attrs = data.domain.attributes
cvars = data.domain.class_vars
metas = data.domain.metas
Expand Down
93 changes: 48 additions & 45 deletions orangecontrib/timeseries/widgets/owinterpolate.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
from AnyQt.QtCore import Qt
from orangewidget.utils.widgetpreview import WidgetPreview

from Orange.data import Table
from Orange.util import try_
from Orange.widgets import widget, gui, settings
from Orange.widgets.widget import Input, Output
from Orange.widgets import gui, settings
from Orange.widgets.widget import Input, Output, Msg, OWWidget

from orangecontrib.timeseries import Timeseries


class OWInterpolate(widget.OWWidget):
class OWInterpolate(OWWidget):
name = 'Interpolate'
description = 'Induce missing values (nan) in the time series by interpolation.'
description = 'Interpolate missing values in the time series.'
icon = 'icons/Interpolate.svg'
priority = 15

class Inputs:
time_series = Input("Time series", Table)

class Outputs:
interpolated = Output("Interpolated time series", Timeseries, default=True)
timeseries = Output("Time series", Timeseries) # TODO
# interpolator = Output("Interpolation model", Model) # TODO
interpolated = Output("Interpolated time series", Timeseries)

want_main_area = False
resizing_enabled = False

interpolation = settings.Setting('linear')
Linear, Cubic, Nearest, Mean = range(4)
Options = ["Linear interpolation", "Cubic interpolation",
"Nearest point interpolation", "Mean/Mode interpolation"]
OptArgs = ["linear", "cubic", "nearest", "mean"]

interpolation = settings.Setting(Linear)
multivariate = settings.Setting(False)
autoapply = settings.Setting(True)

UserAdviceMessages = [
widget.Message('While you can freely choose the interpolation method '
'for continuous variables, discrete variables can only '
'be interpolated with the <i>nearest</i> method or '
'their mode (i.e. the most frequent value).',
'discrete-interp',
widget.Message.Warning)
]
settings_version = 2

class Warning(OWWidget.Warning):
# This message's formulation is weird but: the widget is narrow and
# it's better to start the sentence with "Categorical" (which is seen)
# than with "Missing values for ..."
discrete_mode = Msg(
"Categorical variables:\n"
"missing values are replaced by the most common value")

def __init__(self):
self.data = None
box = gui.vBox(self.controlArea, 'Interpolation Parameters')
gui.comboBox(box, self, 'interpolation',
callback=self.on_changed,
label='Interpolation of missing values:',
sendSelectedValue=True,
orientation=Qt.Horizontal,
items=('linear', 'cubic', 'nearest', 'mean'))
box = gui.vBox(self.controlArea, True)
gui.comboBox(box, self, 'interpolation', items=self.Options,
callback=self.commit.deferred)
gui.checkBox(box, self, 'multivariate',
label='Multi-variate interpolation',
callback=self.on_changed)
callback=self.commit.deferred)
gui.auto_commit(box, self, 'autoapply', 'Apply')

@Inputs.time_series
def set_data(self, data):
self.data = None if data is None else \
Timeseries.from_data_table(data)
self.on_changed()

def on_changed(self):
self.commit()
self.data = Timeseries.from_data_table(data) if data else None
self.commit.now()

@gui.deferred
def commit(self):
data = self.data
if data is not None:
data = data.copy()
data.set_interpolation(self.interpolation, self.multivariate)
self.Outputs.timeseries.send(data)
self.Outputs.interpolated.send(try_(lambda: data.interp()) or None)
self.Warning.clear()

if not self.data:
self.Outputs.interpolated.send(None)
return

if __name__ == "__main__":
from AnyQt.QtWidgets import QApplication
if self.interpolation not in (self.Mean, self.Nearest) \
and any(var.is_discrete for var in self.data.domain.variables):
self.Warning.discrete_mode()

a = QApplication([])
ow = OWInterpolate()
data = self.data.copy()
data.set_interpolation(self.OptArgs[self.interpolation], self.multivariate)
self.Outputs.interpolated.send(try_(lambda: data.interp()) or None)

@classmethod
def migrate_settings(cls, settings, version):
if not version or version < 2:
settings["interpolation"] = \
cls.OptArgs.index(settings["interpolation"])

data = Timeseries.from_file('airpassengers')
ow.set_data(data)

ow.show()
a.exec()
if __name__ == "__main__":
data = Timeseries.from_file('airpassengers')
WidgetPreview(OWInterpolate).run(data)

0 comments on commit e71d462

Please sign in to comment.