File: concurrent_example.py

package info (click to toggle)
orange3 3.40.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,908 kB
  • sloc: python: 162,745; ansic: 622; makefile: 322; sh: 93; cpp: 77
file content (133 lines) | stat: -rw-r--r-- 3,969 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# pylint: disable=too-many-ancestors
from typing import Optional
from types import SimpleNamespace as namespace

import numpy as np

from Orange.data import Table
from Orange.widgets import gui
from Orange.widgets.settings import Setting
from Orange.widgets.utils.concurrent import TaskState, ConcurrentWidgetMixin
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.visualize.utils.widget import OWDataProjectionWidget


class Result(namespace):
    embedding = None  # type: Optional[np.ndarray]


def run(data: Table, embedding: Optional[np.ndarray], state: TaskState):
    res = Result(embedding=embedding)

    # simulate wasteful calculation (increase 'steps')
    step, steps = 0, 10
    state.set_status("Calculating...")
    while step < steps:
        for _ in range(steps):
            x_data = np.array(np.mean(data.X, axis=1))
            if x_data.ndim == 2:
                x_data = x_data.ravel()
            y_data = np.random.rand(len(x_data))
            embedding = np.vstack((x_data, y_data)).T
        step += 1
        if step % (steps / 10) == 0:
            state.set_progress_value(100 * step / steps)

        if state.is_interruption_requested():
            return res

        res.embedding = embedding
        state.set_partial_result(res)
    return res


class OWConcurrentWidget(OWDataProjectionWidget, ConcurrentWidgetMixin):
    name = "Projection"
    param = Setting(0)

    def __init__(self):
        OWDataProjectionWidget.__init__(self)
        ConcurrentWidgetMixin.__init__(self)
        self.embedding = None  # type: Optional[np.ndarray]

    # GUI
    def _add_controls(self):
        box = gui.vBox(self.controlArea, True)
        gui.comboBox(
            box, self, "param", label="Parameter:",
            items=["Param A", "Param B"], labelWidth=80,
            callback=self.__param_combo_changed
        )
        self.run_button = gui.button(box, self, "Start", self._toggle_run)
        super()._add_controls()

    def __param_combo_changed(self):
        self._run()

    def _toggle_run(self):
       # Pause task
        if self.task is not None:
            self.cancel()
            self.run_button.setText("Resume")
            self.commit.deferred()
        # Resume task
        else:
            self._run()

    def _run(self):
        if self.data is None:
            return
        self.run_button.setText("Stop")
        self.start(run, self.data, self.embedding)

    # ConcurrentWidgetMixin
    def on_partial_result(self, result: Result):
        assert isinstance(result.embedding, np.ndarray)
        assert len(result.embedding) == len(self.data)
        first_result = self.embedding is None
        self.embedding = result.embedding
        if first_result:
            self.setup_plot()
        else:
            self.graph.update_coordinates()
            self.graph.update_density()

    def on_done(self, result: Result):
        assert isinstance(result.embedding, np.ndarray)
        assert len(result.embedding) == len(self.data)
        self.embedding = result.embedding
        self.run_button.setText("Start")
        self.commit.deferred()

    def on_exception(self, ex: Exception):
        raise ex

    # OWDataProjectionWidget
    @OWDataProjectionWidget.Inputs.data
    def set_data(self, data: Table):
        super().set_data(data)
        if self._invalidated:
            self._run()

    def get_embedding(self):
        if self.embedding is None:
            self.valid_data = None
            return None

        self.valid_data = np.all(np.isfinite(self.embedding), 1)
        return self.embedding

    def clear(self):
        super().clear()
        self.cancel()
        self.embedding = None

    def onDeleteWidget(self):
        self.shutdown()
        super().onDeleteWidget()


if __name__ == "__main__":
    table = Table("iris")
    WidgetPreview(OWConcurrentWidget).run(
        set_data=table, set_subset_data=table[::10])