Repository: biolab/orange3

Issue:
Outliers: Multiple class value error instead of No class value error
<!--
This is an issue template. Please fill in the relevant details in the
sections below.
-->

##### Orange version
<!-- From menu _Help→About→Version_ or code `Orange.version.full_version` -->
3.5.dev

##### Expected behavior
Outliers returns a correct error message. If there are no class values in the data, it says 'Data missing a class variable'.


##### Actual behavior
Outliers returns 'Multiple class data is not supported.'


##### Steps to reproduce the behavior
File (iris) - Select Columns (move iris to metas) - Outliers.


##### Additional info (worksheets, data, screenshots, ...)





Discussion:

Resolving patch:
diff --git a/Orange/classification/elliptic_envelope.py b/Orange/classification/elliptic_envelope.py
--- a/Orange/classification/elliptic_envelope.py
+++ b/Orange/classification/elliptic_envelope.py
@@ -2,6 +2,7 @@
 
 from Orange.base import SklLearner, SklModel
 from Orange.data import Table
+from Orange.preprocess import Continuize, RemoveNaNColumns, SklImpute
 
 __all__ = ["EllipticEnvelopeLearner"]
 
@@ -27,6 +28,7 @@ def mahalanobis(self, observations):
 class EllipticEnvelopeLearner(SklLearner):
     __wraps__ = skl_covariance.EllipticEnvelope
     __returns__ = EllipticEnvelopeClassifier
+    preprocessors = [Continuize(), RemoveNaNColumns(), SklImpute()]
 
     def __init__(self, store_precision=True, assume_centered=False,
                  support_fraction=None, contamination=0.1,
diff --git a/Orange/widgets/data/owoutliers.py b/Orange/widgets/data/owoutliers.py
--- a/Orange/widgets/data/owoutliers.py
+++ b/Orange/widgets/data/owoutliers.py
@@ -43,7 +43,6 @@ class Outputs:
 
     class Error(widget.OWWidget.Error):
         singular_cov = Msg("Singular covariance matrix.")
-        multiclass_error = Msg("Multiple class data is not supported")
         memory_error = Msg("Not enough memory")
 
     def __init__(self):
@@ -149,6 +148,7 @@ def _get_outliers(self):
         except ValueError:
             self.Error.singular_cov()
             self.in_out_info_label.setText(self.in_out_info_default)
+            return None, None
         except MemoryError:
             self.Error.memory_error()
             return None, None
@@ -170,10 +170,7 @@ def commit(self):
         inliers = outliers = None
         self.n_inliers = self.n_outliers = None
         if self.data is not None and len(self.data) > 0:
-            if self.data.Y.ndim > 1 and self.data.Y.shape[1] > 1:
-                self.Error.multiclass_error()
-            else:
-                inliers, outliers = self._get_outliers()
+            inliers, outliers = self._get_outliers()
 
         self.Outputs.inliers.send(inliers)
         self.Outputs.outliers.send(outliers)
@@ -188,8 +185,9 @@ def detect_outliers(self):
                 support_fraction=self.support_fraction
                 if self.empirical_covariance else None,
                 contamination=self.cont / 100.)
-        model = learner(self.data)
-        y_pred = model(self.data)
+        data = self.data.transform(Domain(self.data.domain.attributes))
+        model = learner(data)
+        y_pred = model(data)
         self.add_metas(model)
         return np.array(y_pred)
 


Test patch:
diff --git a/Orange/widgets/data/tests/test_owoutliers.py b/Orange/widgets/data/tests/test_owoutliers.py
--- a/Orange/widgets/data/tests/test_owoutliers.py
+++ b/Orange/widgets/data/tests/test_owoutliers.py
@@ -5,7 +5,7 @@
 
 import numpy as np
 
-from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable
+from Orange.data import Table
 from Orange.widgets.data.owoutliers import OWOutliers
 from Orange.widgets.tests.base import WidgetTest
 
@@ -25,20 +25,6 @@ def test_data(self):
         self.assertEqual(self.widget.data, None)
         self.assertIsNone(self.get_output("Data"))
 
-    def test_multiclass(self):
-        """Check widget for multiclass dataset"""
-        attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")]
-        class_vars = [DiscreteVariable("cls", ["a", "b", "c"]),
-                      DiscreteVariable("cls", ["aa", "bb", "cc"])]
-        domain = Domain(attrs, class_vars)
-        X = np.arange(12).reshape(6, 2)
-        Y = np.array([[0, 1], [2, 1], [0, 2], [1, 1], [1, 2], [2, 0]])
-        data = Table(domain, X, Y)
-        self.send_signal(self.widget.Inputs.data, data)
-        self.assertTrue(self.widget.Error.multiclass_error.is_shown())
-        self.send_signal(self.widget.Inputs.data, None)
-        self.assertFalse(self.widget.Error.multiclass_error.is_shown())
-
     def test_memory_error(self):
         """
         Handling memory error.
@@ -51,3 +37,11 @@ def test_memory_error(self):
             side_effect=MemoryError):
             self.send_signal("Data", data)
             self.assertTrue(self.widget.Error.memory_error.is_shown())
+
+    def test_nans(self):
+        """Widget does not crash with nans"""
+        a = np.arange(20, dtype=float).reshape(4, 5)
+        a[0, 0] = np.nan
+        data = Table(a)
+        self.send_signal(self.widget.Inputs.data, data)
+        self.assertIsNot(self.get_output(self.widget.Outputs.inliers), None)