Skip to content

Commit 6b261e0

Browse files
committed
Pythagorean Tree: new signals and minor refactoring
1 parent cfb2bc8 commit 6b261e0

File tree

2 files changed

+61
-56
lines changed

2 files changed

+61
-56
lines changed

Orange/widgets/visualize/owpythagorastree.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
from Orange.base import TreeModel, SklModel
1010
from Orange.data.table import Table
11-
from Orange.widgets import gui, settings, widget
11+
from Orange.widgets import gui, settings
1212
from Orange.widgets.utils.annotated_data import (
1313
create_annotated_table,
1414
ANNOTATED_DATA_SIGNAL_NAME
1515
)
16+
from Orange.widgets.utils.signals import Input, Output
1617
from Orange.widgets.visualize.pythagorastreeviewer import (
1718
PythagorasTreeViewer,
1819
SquareGraphicsItem,
@@ -43,9 +44,12 @@ class OWPythagorasTree(OWWidget):
4344

4445
priority = 1000
4546

46-
inputs = [('Tree', TreeModel, 'set_tree')]
47-
outputs = [('Selected Data', Table, widget.Default),
48-
(ANNOTATED_DATA_SIGNAL_NAME, Table)]
47+
class Inputs:
48+
tree = Input("Tree", TreeModel)
49+
50+
class Outputs:
51+
selected_data = Output("Selected Data", Table, default=True)
52+
annotated_data = Output(ANNOTATED_DATA_SIGNAL_NAME, Table)
4953

5054
# Enable the save as feature
5155
graph_name = 'scene'
@@ -136,6 +140,7 @@ def __init__(self):
136140
# Clear the widget to correctly set the intial values
137141
self.clear()
138142

143+
@Inputs.tree
139144
def set_tree(self, model=None):
140145
"""When a different tree is given."""
141146
self.clear()
@@ -185,8 +190,7 @@ def set_tree(self, model=None):
185190
# self.depth_limit = model.meta_depth_limit
186191
# self.update_depth()
187192

188-
self.send(ANNOTATED_DATA_SIGNAL_NAME,
189-
create_annotated_table(self.instances, None))
193+
self.Outputs.annotated_data.send(create_annotated_table(self.instances, None))
190194

191195
def clear(self):
192196
"""Clear all relevant data from the widget."""
@@ -296,16 +300,15 @@ def onDeleteWidget(self):
296300
def commit(self):
297301
"""Commit the selected data to output."""
298302
if self.instances is None:
299-
self.send('Selected Data', None)
300-
self.send(ANNOTATED_DATA_SIGNAL_NAME, None)
303+
self.Outputs.selected_data.send(None)
304+
self.Outputs.annotated_data.send(None)
301305
return
302306
nodes = [i.tree_node.label for i in self.scene.selectedItems()
303307
if isinstance(i, SquareGraphicsItem)]
304308
data = self.tree_adapter.get_instances_in_nodes(nodes)
305-
self.send('Selected Data', data)
309+
self.Outputs.selected_data.send(data)
306310
selected_indices = self.tree_adapter.get_indices(nodes)
307-
self.send(ANNOTATED_DATA_SIGNAL_NAME,
308-
create_annotated_table(self.instances, selected_indices))
311+
self.Outputs.annotated_data.send(create_annotated_table(self.instances, selected_indices))
309312

310313
def send_report(self):
311314
"""Send report."""

Orange/widgets/visualize/tests/test_owpythagorastree.py

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def get_tree_nodes(self):
134134
return (sq.tree_node for sq in self.get_squares())
135135

136136
def test_tree_is_drawn(self):
137-
self.send_signal('Tree', self.housing)
137+
self.send_signal(self.widget.Inputs.tree, self.housing)
138138
self.assertTrue(len(self.get_squares()) > 0)
139139

140140
def _check_all_same(self, items):
@@ -162,13 +162,14 @@ def _callback():
162162
self.assertTrue(any(x is False for x in squares_same),
163163
'Colors did not change for %s data' % data_type)
164164

165-
self.send_signal('Tree', self.titanic)
165+
w = self.widget
166+
self.send_signal(w.Inputs.tree, self.titanic)
166167
_test('classification')
167-
self.send_signal('Tree', self.housing)
168+
self.send_signal(w.Inputs.tree, self.housing)
168169
_test('regression')
169170

170171
def test_changing_size_adjustment_changes_sizes(self):
171-
self.send_signal('Tree', self.titanic)
172+
self.send_signal(self.widget.Inputs.tree, self.titanic)
172173
squares = []
173174

174175
def _callback():
@@ -187,7 +188,7 @@ def test_log_scale_slider(self):
187188
self.assertFalse(self.widget.log_scale_box.isEnabled(),
188189
'Should be disabled with no tree')
189190

190-
self.send_signal('Tree', self.titanic)
191+
self.send_signal(self.widget.Inputs.tree, self.titanic)
191192
# No size adjustment
192193
simulate.combobox_activate_item(self.widget.size_calc_combo, 'Normal')
193194
self.assertFalse(self.widget.log_scale_box.isEnabled(),
@@ -216,95 +217,96 @@ def test_log_scale_slider(self):
216217

217218
def test_legend(self):
218219
"""Test legend behaviour."""
219-
self.widget.cb_show_legend.setChecked(True)
220+
w = self.widget
221+
w.cb_show_legend.setChecked(True)
220222

221-
self.send_signal('Tree', self.titanic)
223+
self.send_signal(w.Inputs.tree, self.titanic)
222224
self.assertIsInstance(self.widget.legend, OWDiscreteLegend)
223225
self.assertTrue(self.widget.legend.isVisible())
224226

225227
# The legend should be invisible when regression coloring is none
226-
self.send_signal('Tree', self.housing)
227-
self.assertIsInstance(self.widget.legend, OWContinuousLegend)
228-
self.assertFalse(self.widget.legend.isVisible())
228+
self.send_signal(w.Inputs.tree, self.housing)
229+
self.assertIsInstance(w.legend, OWContinuousLegend)
230+
self.assertFalse(w.legend.isVisible())
229231

230232
# The legend should appear when there is a coloring (2 is mean coloring)
231233
index = 2
232-
simulate.combobox_activate_index(self.widget.target_class_combo, index)
233-
self.assertIsInstance(self.widget.legend, OWContinuousLegend)
234-
self.assertTrue(self.widget.legend.isVisible())
234+
simulate.combobox_activate_index(w.target_class_combo, index)
235+
self.assertIsInstance(w.legend, OWContinuousLegend)
236+
self.assertTrue(w.legend.isVisible())
235237

236238
# Check that switching back to a discrete target class works
237-
self.send_signal('Tree', self.titanic)
238-
self.assertIsInstance(self.widget.legend, OWDiscreteLegend)
239-
self.assertTrue(self.widget.legend.isVisible())
239+
self.send_signal(w.Inputs.tree, self.titanic)
240+
self.assertIsInstance(w.legend, OWDiscreteLegend)
241+
self.assertTrue(w.legend.isVisible())
240242

241243
def test_checking_legend_checkbox_shows_and_hides_legend(self):
242-
self.send_signal('Tree', self.titanic)
244+
w = self.widget
245+
self.send_signal(w.Inputs.tree, self.titanic)
243246
# Hide the legend
244-
self.widget.cb_show_legend.setChecked(False)
245-
self.assertFalse(self.widget.legend.isVisible(), 'Hiding legend failed')
247+
w.cb_show_legend.setChecked(False)
248+
self.assertFalse(w.legend.isVisible(), 'Hiding legend failed')
246249
# Show the legend
247-
self.widget.cb_show_legend.setChecked(True)
248-
self.assertTrue(self.widget.legend.isVisible(), 'Showing legend failed')
250+
w.cb_show_legend.setChecked(True)
251+
self.assertTrue(w.legend.isVisible(), 'Showing legend failed')
249252

250253
def test_tooltip_changes_for_classification_target_class(self):
251254
"""Tooltips should change when a target class is specified with a
252255
discrete target class."""
253-
self.widget.cb_show_tooltips.setChecked(True)
254-
self.send_signal('Tree', self.titanic)
256+
w = self.widget
257+
w.cb_show_tooltips.setChecked(True)
258+
self.send_signal(w.Inputs.tree, self.titanic)
255259
tooltips = []
256260

257261
def _callback():
258262
tooltips.append(self.get_visible_squares()[2].toolTip())
259263

260-
simulate.combobox_run_through_all(
261-
self.widget.target_class_combo, callback=_callback)
264+
simulate.combobox_run_through_all(w.target_class_combo, callback=_callback)
262265

263266
self.assertFalse(self._check_all_same(tooltips))
264267

265268
def test_checking_tooltip_shows_and_hides_tooltips(self):
266-
self.send_signal('Tree', self.titanic)
269+
w = self.widget
270+
self.send_signal(w.Inputs.tree, self.titanic)
267271
square = self.get_squares()[0]
268272
# Hide tooltips
269-
self.widget.cb_show_tooltips.setChecked(False)
273+
w.cb_show_tooltips.setChecked(False)
270274
self.assertEqual(square.toolTip(), '', 'Hiding tooltips failed')
271275
# Show tooltips
272-
self.widget.cb_show_tooltips.setChecked(True)
276+
w.cb_show_tooltips.setChecked(True)
273277
self.assertNotEqual(square.toolTip(), '', 'Showing tooltips failed')
274278

275279
def test_changing_max_depth_slider(self):
276-
self.send_signal('Tree', self.titanic)
280+
w = self.widget
281+
self.send_signal(w.Inputs.tree, self.titanic)
277282

278-
max_depth = self.widget.tree_adapter.max_depth
283+
max_depth = w.tree_adapter.max_depth
279284
num_squares_full = len(self.get_visible_squares())
280-
self.assertEqual(self.widget.depth_limit, max_depth,
281-
'Full tree should be drawn initially')
285+
self.assertEqual(w.depth_limit, max_depth, 'Full tree should be drawn initially')
282286

283287
self.widget.depth_slider.setValue(max_depth - 1)
284288
num_squares_less = len(self.get_visible_squares())
285289
self.assertLess(num_squares_less, num_squares_full,
286290
'Lowering tree depth limit did not hide squares')
287291

288-
self.widget.depth_slider.setValue(max_depth + 1)
292+
w.depth_slider.setValue(max_depth + 1)
289293
self.assertGreater(len(self.get_visible_squares()), num_squares_less,
290294
'Increasing tree depth limit did not show squares')
291295

292296
def test_label_on_tree_connect_and_disconnect(self):
297+
w = self.widget
293298
regex = r'Nodes:(.+)\s*Depth:(.+)'
294299
# Should contain no info by default
295300
self.assertNotRegex(
296301
self.widget.info.text(), regex,
297302
'Initial info should not contain node or depth info')
298303
# Test info label for tree
299-
self.send_signal('Tree', self.titanic)
300-
self.assertRegex(
301-
self.widget.info.text(), regex,
302-
'Valid tree does not update info')
304+
self.send_signal(w.Inputs.tree, self.titanic)
305+
self.assertRegex(w.info.text(), regex, 'Valid tree does not update info')
303306
# Remove tree from input
304-
self.send_signal('Tree', None)
307+
self.send_signal(w.Inputs.tree, None)
305308
self.assertNotRegex(
306-
self.widget.info.text(), regex,
307-
'Initial info should not contain node or depth info')
309+
w.info.text(), regex, 'Initial info should not contain node or depth info')
308310

309311
def test_tree_determinism(self):
310312
"""Check that the tree is drawn identically upon receiving the same
@@ -313,7 +315,7 @@ def test_tree_determinism(self):
313315
# Make sure the tree are deterministic for iris
314316
scene_nodes = []
315317
for _ in range(n_tries):
316-
self.send_signal(self.signal_name, self.signal_data)
318+
self.send_signal(self.widget.Inputs.tree, self.signal_data)
317319
scene_nodes.append([n.pos() for n in self.get_visible_squares()])
318320
for node_row in zip(*scene_nodes):
319321
self.assertTrue(
@@ -330,7 +332,7 @@ def test_tree_determinism(self):
330332
data_same_entropy = TreeLearner()(data_same_entropy)
331333
scene_nodes = []
332334
for _ in range(n_tries):
333-
self.send_signal(self.signal_name, data_same_entropy)
335+
self.send_signal(self.widget.Inputs.tree, data_same_entropy)
334336
scene_nodes.append([n.pos() for n in self.get_visible_squares()])
335337
for node_row in zip(*scene_nodes):
336338
self.assertTrue(
@@ -342,14 +344,14 @@ def test_tree_determinism(self):
342344

343345
def test_keep_colors_on_sizing_change(self):
344346
"""The color should be the same after a full recompute of the tree."""
345-
self.send_signal('Tree', self.titanic)
347+
w = self.widget
348+
self.send_signal(w.Inputs.tree, self.titanic)
346349
colors = []
347350

348351
def _callback():
349352
colors.append([sq.brush().color() for sq in self.get_visible_squares()])
350353

351-
simulate.combobox_run_through_all(
352-
self.widget.size_calc_combo, callback=_callback)
354+
simulate.combobox_run_through_all(w.size_calc_combo, callback=_callback)
353355

354356
# Check that individual squares all have the same color
355357
colors_same = [self._check_all_same(x) for x in zip(*colors)]

0 commit comments

Comments
 (0)