Skip to content

Commit 065788a

Browse files
authored
Merge pull request #3957 from janezd/retain-selection
[FIX] Fix storing and retrieving selection, and unconditional auto commit
2 parents 6c81328 + 278caca commit 065788a

20 files changed

+217
-13
lines changed

Orange/widgets/data/owtable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def update(_):
536536
self.selected_cols = []
537537

538538
self.set_selection()
539-
self.commit()
539+
self.unconditional_commit()
540540

541541
def _setup_table_view(self, view, data):
542542
"""Setup the `view` (QTableView) with `data` (Orange.data.Table)

Orange/widgets/data/tests/test_owtable.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from unittest.mock import Mock
1+
import unittest
2+
from unittest.mock import Mock, patch
23

34
from Orange.widgets.data.owtable import OWDataTable
45
from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin
@@ -57,3 +58,14 @@ def test_attrs_appear_in_corner_text(self):
5758
# false positive, pylint: disable=unsubscriptable-object
5859
self.assertEqual(
5960
self.widget.set_corner_text.call_args[0][1], "\na\nb\nc")
61+
62+
def test_unconditional_commit_on_new_signal(self):
63+
with patch.object(self.widget, 'unconditional_commit') as commit:
64+
self.widget.auto_commit = False
65+
commit.reset_mock()
66+
self.send_signal(self.widget.Inputs.data, self.data)
67+
commit.assert_called()
68+
69+
70+
if __name__ == "__main__":
71+
unittest.main()

Orange/widgets/tests/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ def test_plot_once(self, timeout=DEFAULT_TIMEOUT):
614614
"""Test if data is plotted only once but committed on every input change"""
615615
table = Table("heart_disease")
616616
self.widget.setup_plot = Mock()
617-
self.widget.commit = Mock()
617+
self.widget.commit = self.widget.unconditional_commit = Mock()
618618
self.send_signal(self.widget.Inputs.data, table)
619619
self.widget.setup_plot.assert_called_once()
620620
self.widget.commit.assert_called_once()

Orange/widgets/unsupervised/owdistancemap.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,16 @@ def selections(self):
225225
range(r.left(), r.right() + 1))
226226
for r in selections]
227227

228+
def set_selections(self, ranges):
229+
self.__clearSelections()
230+
for y, x in ranges:
231+
area = QRectF(x.start, y.start,
232+
x.stop - x.start - 1, y.stop - y.start - 1)
233+
item = DistanceMapItem.SelectionRect(area, self)
234+
item.setPen(QPen(Qt.red, 0))
235+
self.__selections.append((item, area))
236+
self.selectionChanged.emit()
237+
228238
def hoverMoveEvent(self, event):
229239
super().hoverMoveEvent(event)
230240
i, j = self._cellAt(event.pos())
@@ -268,6 +278,7 @@ class Outputs:
268278
color_high = settings.Setting(1.0)
269279

270280
annotation_idx = settings.ContextSetting(0)
281+
pending_selection = settings.Setting(None, schema_only=True)
271282

272283
autocommit = settings.Setting(True)
273284

@@ -393,6 +404,14 @@ def __init__(self):
393404

394405
self.grid_widget.scene().installEventFilter(self)
395406

407+
self.settingsAboutToBePacked.connect(self.pack_settings)
408+
409+
def pack_settings(self):
410+
if self.matrix_item is not None:
411+
self.pending_selection = self.matrix_item.selections()
412+
else:
413+
self.pending_selection = None
414+
396415
@Inputs.distances
397416
def set_distances(self, matrix):
398417
self.closeContext()
@@ -473,6 +492,9 @@ def handleNewSignals(self):
473492
self._update_ordering()
474493
self._setup_scene()
475494
self._update_labels()
495+
if self.pending_selection is not None:
496+
self.matrix_item.set_selections(self.pending_selection)
497+
self.pending_selection = None
476498
self.unconditional_commit()
477499

478500
def _clear_plot(self):

Orange/widgets/unsupervised/tests/test_owdistancemap.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Test methods with long descriptive names can omit docstrings
22
# pylint: disable=missing-docstring
33
import random
4+
import unittest
5+
46
from Orange.distance import Euclidean
57
from Orange.widgets.unsupervised.owdistancemap import OWDistanceMap
68
from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin
@@ -24,3 +26,20 @@ def _select_data(self):
2426
self.widget._selection = selected_indices
2527
self.widget.commit()
2628
return selected_indices
29+
30+
def test_saved_selection(self):
31+
self.widget.settingsHandler.pack_data(self.widget)
32+
# no assert here, just test is doesn't crash on empty
33+
34+
self.send_signal(self.signal_name, self.signal_data)
35+
random.seed(42)
36+
self.widget.matrix_item.set_selections([(range(5, 10), range(8, 15))])
37+
settings = self.widget.settingsHandler.pack_data(self.widget)
38+
39+
w = self.create_widget(OWDistanceMap, stored_settings=settings)
40+
self.send_signal(self.signal_name, self.signal_data)
41+
self.assertEqual(len(self.get_output(w.Outputs.selected_data)), 10)
42+
43+
44+
if __name__ == "__main__":
45+
unittest.main()

Orange/widgets/unsupervised/tests/test_owmds.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_plot_once(self, timeout=5000):
5353
"""Test if data is plotted only once but committed on every input change"""
5454
table = Table("heart_disease")
5555
self.widget.setup_plot = Mock()
56-
self.widget.commit = Mock()
56+
self.widget.commit = self.widget.unconditional_commit = Mock()
5757
self.send_signal(self.widget.Inputs.data, table)
5858
self.widget.commit.reset_mock()
5959
self.wait_until_stop_blocking()

Orange/widgets/unsupervised/tests/test_owtsne.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def _check_exaggeration(call, exaggeration):
211211
def test_plot_once(self):
212212
"""Test if data is plotted only once but committed on every input change"""
213213
self.widget.setup_plot = Mock()
214-
self.widget.commit = Mock()
214+
self.widget.commit = self.widget.unconditional_commit = Mock()
215215

216216
self.send_signal(self.widget.Inputs.data, self.data)
217217
# TODO: The base widget immediately calls `setup_plot` and `commit`

Orange/widgets/utils/tests/test_concurrent_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_button_toggle(self):
4444
def test_plot_once(self):
4545
table = Table("heart_disease")
4646
self.widget.setup_plot = Mock()
47-
self.widget.commit = Mock()
47+
self.widget.commit = self.widget.unconditional_commit = Mock()
4848
self.send_signal(self.widget.Inputs.data, table)
4949
self.widget.setup_plot.assert_called_once()
5050
self.widget.commit.assert_called_once()

Orange/widgets/visualize/owheatmap.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ class Outputs:
427427

428428
palette_index = settings.Setting(_default_palette_index)
429429
column_label_pos = settings.Setting(PositionTop)
430+
selected_rows = settings.Setting(None, schema_only=True)
430431

431432
auto_commit = settings.Setting(True)
432433

@@ -454,6 +455,7 @@ class Warning(widget.OWWidget.Warning):
454455

455456
def __init__(self):
456457
super().__init__()
458+
self.__pending_selection = self.selected_rows
457459

458460
# set default settings
459461
self.space_x = 10
@@ -719,7 +721,14 @@ def set_dataset(self, data=None):
719721
self.openContext(self.data)
720722
if self.annotation_index >= len(self.annotation_vars):
721723
self.annotation_index = 0
724+
722725
self.update_heatmaps()
726+
if data is not None and self.__pending_selection is not None:
727+
self.selection_manager.select_rows(self.__pending_selection)
728+
self.selected_rows = self.__pending_selection
729+
self.__pending_selection = None
730+
731+
self.unconditional_commit()
723732

724733
def update_heatmaps(self):
725734
if self.data is not None:
@@ -739,13 +748,13 @@ def update_heatmaps(self):
739748
self.selected_rows = []
740749
else:
741750
self.clear()
742-
self.commit()
743751

744752
def update_merge(self):
745753
self.kmeans_model = None
746754
self.merge_indices = None
747755
if self.data is not None and self.merge_kmeans:
748756
self.update_heatmaps()
757+
self.commit()
749758

750759
def _make_parts(self, data, group_var=None, group_key=None):
751760
"""
@@ -1393,9 +1402,11 @@ def update_color_schema(self):
13931402

13941403
def update_sorting_examples(self):
13951404
self.update_heatmaps()
1405+
self.commit()
13961406

13971407
def update_clustering_examples(self):
13981408
self.update_heatmaps()
1409+
self.commit()
13991410

14001411
def update_legend(self):
14011412
for item in self.heatmap_scene.items():

Orange/widgets/visualize/owlineplot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ def set_data(self, data):
547547

548548
self.openContext(data)
549549
self.setup_plot()
550-
self.commit()
550+
self.unconditional_commit()
551551

552552
def check_data(self):
553553
def error(err):

0 commit comments

Comments
 (0)