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] settings: Do not clear schema_only settings on close_context #2691

Merged
merged 2 commits into from
Oct 23, 2017
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
11 changes: 0 additions & 11 deletions Orange/widgets/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,17 +787,6 @@ def close_context(self, widget):
if widget.current_context is None:
return

# Clear schema-only settings when *closing* the context
# FIXME: Sadly, schema-only settings aren't cleared when non-contextual
# SettingsHandler is used. Example: widget has non-contextual
# SettingsHandler, user loads schema that includes widget, user
# passes new data to widget => widget's schema-only settings still
# have previous values because equivalent of below reset was never
# called (i.e. `close_context()`).
for name, setting in self.known_settings.items():
if setting.schema_only:
setattr(widget, name, setting.default)

self.settings_from_widget(widget)
widget.current_context = None

Expand Down
12 changes: 12 additions & 0 deletions Orange/widgets/tests/test_context_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class SimpleWidget:
settings_version = 1

setting = Setting(42)
schema_only_setting = Setting(None, schema_only=True)

context_setting = ContextSetting(42)

Expand Down Expand Up @@ -181,6 +182,17 @@ def test_write_defaults_stores_version(self):
for c in contexts:
self.assertEqual(c.values.get("__version__", 0xBAD), 1)

def test_close_context(self):
handler = ContextHandler()
handler.bind(SimpleWidget)
widget = SimpleWidget()
widget.storeSpecificSettings = Mock()
handler.initialize(widget)
widget.schema_only_setting = 0xD06F00D
widget.current_context = handler.new_context()
handler.close_context(widget)
self.assertEqual(widget.schema_only_setting, 0xD06F00D)


class TestSettingsPrinter(TestCase):
def test_formats_contexts(self):
Expand Down
11 changes: 8 additions & 3 deletions Orange/widgets/visualize/owlinearprojection.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ def __init__(self):
self.__legend = None
self.__selection_item = None
self.__replot_requested = False
#: Remember the saved state to restore
self.__pending_selection_restore = self.selection_indices
self.selection_indices = None

box = gui.vBox(self.controlArea, "Axes")

Expand Down Expand Up @@ -425,6 +428,7 @@ def sizeHint(self):

def clear(self):
self.data = None
self.selection_indices = None
self._subset_mask = None
self._selection_mask = None
self.varmodel_selected[:] = []
Expand Down Expand Up @@ -515,8 +519,9 @@ def set_data(self, data):
if set(selected_keys).issubset(set(state.keys())):
pass

if self.selection_indices is not None:
self.select_indices(self.selection_indices)
if self.__pending_selection_restore is not None:
self.select_indices(self.__pending_selection_restore)
self.__pending_selection_restore = None

# update the defaults state (the encoded state must contain
# all variables in the input domain)
Expand Down Expand Up @@ -942,6 +947,7 @@ def select_indices(self, indices, modifiers=Qt.NoModifier):
self._selection_mask[indices] = True

self._on_color_change()
self.selection_indices = numpy.flatnonzero(self._selection_mask).tolist()
self.commit()

def commit(self):
Expand All @@ -952,7 +958,6 @@ def commit(self):
if len(indices) > 0:
subset = self.data[indices]

self.selection_indices = indices
self.Outputs.selected_data.send(subset)
self.Outputs.annotated_data.send(create_annotated_table(self.data, indices))

Expand Down
36 changes: 25 additions & 11 deletions Orange/widgets/visualize/owscatterplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ class Outputs:

attr_x = ContextSetting(None)
attr_y = ContextSetting(None)

#: Serialized selection state to be restored
selection_group = Setting(None, schema_only=True)

graph = SettingProvider(OWScatterPlotGraph)
Expand Down Expand Up @@ -142,6 +144,9 @@ def __init__(self):
self.attribute_selection_list = None # list of Orange.data.Variable
self.__timer = QTimer(self, interval=1200)
self.__timer.timeout.connect(self.add_data)
#: Remember the saved state to restore
self.__pending_selection_restore = self.selection_group
self.selection_group = None

common_options = dict(
labelWidth=50, orientation=Qt.Horizontal, sendSelectedValue=True,
Expand Down Expand Up @@ -332,14 +337,16 @@ def handleNewSignals(self):
self.update_graph()
self.cb_class_density.setEnabled(self.graph.can_draw_density())
self.cb_reg_line.setEnabled(self.graph.can_draw_regresssion_line())
self.apply_selection()
if self.data is not None and self.__pending_selection_restore is not None:
self.apply_selection(self.__pending_selection_restore)
self.__pending_selection_restore = None
self.unconditional_commit()

def apply_selection(self):
"""Apply selection saved in workflow."""
if self.data is not None and self.selection_group is not None:
def apply_selection(self, selection):
"""Apply `selection` to the current plot."""
if self.data is not None:
self.graph.selection = np.zeros(len(self.data), dtype=np.uint8)
self.selection_group = [x for x in self.selection_group if x[0] < len(self.data)]
self.selection_group = [x for x in selection if x[0] < len(self.data)]
selection_array = np.array(self.selection_group).T
self.graph.selection[selection_array[0]] = selection_array[1]
self.graph.update_colors(keep_colors=True)
Expand Down Expand Up @@ -389,6 +396,19 @@ def update_graph(self, reset_view=True, **_):
self.graph.update_data(self.attr_x, self.attr_y, reset_view)

def selection_changed(self):

# Store current selection in a setting that is stored in workflow
if isinstance(self.data, SqlTable):
selection = None
elif self.data is not None:
selection = self.graph.get_selection()
else:
selection = None
if selection is not None and len(selection):
self.selection_group = list(zip(selection, self.graph.selection[selection]))
else:
self.selection_group = None

self.commit()

def send_data(self):
Expand All @@ -410,12 +430,6 @@ def _get_annotated():
self.Outputs.annotated_data.send(_get_annotated())
self.Outputs.selected_data.send(_get_selected())

# Store current selection in a setting that is stored in workflow
if len(selection):
self.selection_group = list(zip(selection, graph.selection[selection]))
else:
self.selection_group = None

def send_features(self):
features = [attr for attr in [self.attr_x, self.attr_y] if attr]
self.Outputs.features.send(features or None)
Expand Down
10 changes: 8 additions & 2 deletions Orange/widgets/visualize/tests/test_owscatterplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ def test_saving_selection(self):

def test_points_selection(self):
# Opening widget with saved selection should restore it
self.widget.selection_group = [(i, 1) for i in range(50)]
self.widget = self.create_widget(
OWScatterPlot, stored_settings={
"selection_group": [(i, 1) for i in range(50)]}
)
self.send_signal(self.widget.Inputs.data, self.data) # iris
selected_data = self.get_output(self.widget.Outputs.selected_data)
self.assertEqual(len(selected_data), 50)
Expand All @@ -269,7 +272,10 @@ def test_migrate_selection(self):
def test_invalid_points_selection(self):
# if selection contains rows that are not present in the current
# dataset, widget should select what can be selected.
self.widget.selection_group = [(i, 1) for i in range(50)]
self.widget = self.create_widget(
OWScatterPlot, stored_settings={
"selection_group": [(i, 1) for i in range(50)]}
)
self.send_signal(self.widget.Inputs.data, self.data[:10])
selected_data = self.get_output(self.widget.Outputs.selected_data)
self.assertEqual(len(selected_data), 10)
Expand Down