Repository: biolab/orange3

Issue:
Scatter Plot: send Features from one SP to another

##### Orange version
<!-- From menu _Help→About→Version_ or code `Orange.version.full_version` -->
3.7.dev

##### Expected behavior
Scatter Plot (1) can be connected to Scatter Plot (2) by Features output as well.


##### Actual behavior
Scatter Plot (2) doesn't accept Features from Scatter Plot (1).


##### Steps to reproduce the behavior
File - Scatter Plot (1) - Scatter Plot (2)


##### Additional info (worksheets, data, screenshots, ...)
Line in Edit Links cannot be connected.




Discussion:

Resolving patch:
diff --git a/Orange/widgets/visualize/owscatterplot.py b/Orange/widgets/visualize/owscatterplot.py
--- a/Orange/widgets/visualize/owscatterplot.py
+++ b/Orange/widgets/visualize/owscatterplot.py
@@ -9,8 +9,7 @@
 from sklearn.metrics import r2_score
 
 import Orange
-from Orange.data import Table, Domain, StringVariable, ContinuousVariable, \
-    DiscreteVariable
+from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable
 from Orange.canvas import report
 from Orange.data.sql.table import SqlTable, AUTO_DL_LIMIT
 from Orange.preprocess.score import ReliefF, RReliefF
@@ -101,7 +100,7 @@ class Inputs:
     class Outputs:
         selected_data = Output("Selected Data", Table, default=True)
         annotated_data = Output(ANNOTATED_DATA_SIGNAL_NAME, Table)
-        features = Output("Features", Table, dynamic=False)
+        features = Output("Features", AttributeList, dynamic=False)
 
     settings_version = 2
     settingsHandler = DomainContextHandler()
@@ -452,12 +451,8 @@ def send_data(self):
             self.selection_group = None
 
     def send_features(self):
-        features = None
-        if self.attr_x or self.attr_y:
-            dom = Domain([], metas=(StringVariable(name="feature"),))
-            features = Table(dom, [[self.attr_x], [self.attr_y]])
-            features.name = "Features"
-        self.Outputs.features.send(features)
+        features = [attr for attr in [self.attr_x, self.attr_y] if attr]
+        self.Outputs.features.send(features or None)
 
     def commit(self):
         self.send_data()


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
@@ -308,7 +308,25 @@ def test_features_and_no_data(self):
     def test_features_and_data(self):
         data = Table("iris")
         self.send_signal(self.widget.Inputs.data, data)
-        self.send_signal(self.widget.Inputs.features, data.domain)
+        self.send_signal(self.widget.Inputs.features, data.domain[2:])
+        self.assertIs(self.widget.attr_x, data.domain[2])
+        self.assertIs(self.widget.attr_y, data.domain[3])
+
+    def test_output_features(self):
+        data = Table("iris")
+        self.send_signal(self.widget.Inputs.data, data)
+
+        # This doesn't work because combo's callbacks are connected to signal
+        # `activated`, which is only triggered by user interaction, and not to
+        # `currentIndexChanged`
+        # combo_y = self.widget.controls.attr_y
+        # combo_y.setCurrentIndex(combo_y.model().indexOf(data.domain[3]))
+        # This is a workaround
+        self.widget.attr_y = data.domain[3]
+        self.widget.update_attr()
+
+        features = self.get_output(self.widget.Outputs.features)
+        self.assertEqual(features, [data.domain[0], data.domain[3]])
 
     def test_send_report(self):
         data = Table("iris")