Repository: biolab/orange3

Issue:
Setting handlers retrieve attributes that are not in the domain
Connect File -> Predictions -> Scatter plot. Connect SVM to File and Predictions. In the Scatter plot, use attribute SVM for shape. Now remove SVM and replace it with classification trees. You get

```
  File "/Users/janez/Desktop/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/Orange/widgets/visualize/owscatterplotgraph.py", line 872, in get_shape_index
    len(self.data_domain[attr_shape].values) <= \
  File "/Users/janez/Desktop/Orange3.app/Contents/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/Orange/data/domain.py", line 223, in __getitem__
    idx = self._indices[idx]
KeyError: 'SVM'
```

I guess what happens here is that a context is reused since the `shape` is not required attribute. This is OK. But while reusing the context, the stored value of `shape` (SVM) is copied into the widget attribute. The widget crashes when it tries to use it.



Discussion:

Resolving patch:
diff --git a/Orange/widgets/settings.py b/Orange/widgets/settings.py
--- a/Orange/widgets/settings.py
+++ b/Orange/widgets/settings.py
@@ -531,6 +531,7 @@ class ContextSetting(Setting):
     # something with the attributes. Large majority does, so this greatly
     # simplifies the declaration of settings in widget at no (visible)
     # cost to those settings that don't need it
+    # TODO: exclude_metas should be disabled by default
     def __init__(self, default, not_attribute=False, required=0,
                  exclude_attributes=False, exclude_metas=True, **data):
         super().__init__(default, **data)
diff --git a/Orange/widgets/visualize/owscatterplotgraph.py b/Orange/widgets/visualize/owscatterplotgraph.py
--- a/Orange/widgets/visualize/owscatterplotgraph.py
+++ b/Orange/widgets/visualize/owscatterplotgraph.py
@@ -453,11 +453,11 @@ def _define_symbols():
 
 
 class OWScatterPlotGraph(gui.OWComponent, ScaleScatterPlotData):
-    attr_color = ContextSetting("", ContextSetting.OPTIONAL)
-    attr_label = ContextSetting("", ContextSetting.OPTIONAL)
+    attr_color = ContextSetting("", ContextSetting.OPTIONAL, exclude_metas=False)
+    attr_label = ContextSetting("", ContextSetting.OPTIONAL, exclude_metas=False)
     label_only_selected = Setting(False)
-    attr_shape = ContextSetting("", ContextSetting.OPTIONAL)
-    attr_size = ContextSetting("", ContextSetting.OPTIONAL)
+    attr_shape = ContextSetting("", ContextSetting.OPTIONAL, exclude_metas=False)
+    attr_size = ContextSetting("", ContextSetting.OPTIONAL, exclude_metas=False)
 
     point_width = Setting(10)
     alpha_value = Setting(128)


Test patch:
diff --git a/Orange/widgets/visualize/tests/test_owscatterplot.py b/Orange/widgets/visualize/tests/test_owscatterplot.py
--- a/Orange/widgets/visualize/tests/test_owscatterplot.py
+++ b/Orange/widgets/visualize/tests/test_owscatterplot.py
@@ -56,3 +56,16 @@ def test_score_heuristics(self):
         vizrank = ScatterPlotVizRank(self.widget)
         self.assertEqual([x.name for x in vizrank.score_heuristic()],
                          list("abcd"))
+
+    def test_optional_combos(self):
+        domain = self.iris.domain
+        d1 = Domain(domain.attributes[:2], domain.class_var,
+                   [domain.attributes[2]])
+        t1 = Table(d1, self.iris)
+        self.send_signal("Data", t1)
+        self.widget.graph.attr_size = domain.attributes[2].name
+
+        d2 = Domain(domain.attributes[:2], domain.class_var,
+                    [domain.attributes[3]])
+        t2 = Table(d2, self.iris)
+        self.send_signal("Data", t2)