diff --git a/Orange/base.py b/Orange/base.py index eb3a46f4c59..4ffe4d0dea4 100644 --- a/Orange/base.py +++ b/Orange/base.py @@ -259,13 +259,13 @@ def backmap_value(self, value, mapped_probs, n_values, backmappers): value = backmapper(value) nans = np.isnan(value) - if not np.any(nans): + if not np.any(nans) or n_values[0] < 2: return value if mapped_probs is not None: value[nans] = np.argmax(mapped_probs[nans], axis=1) else: - value[nans] = np.RandomState(0).choice( - backmapper(np.arange(0, n_values[0] - 1)) + value[nans] = np.random.RandomState(0).choice( + backmapper(np.arange(0, n_values[0] - 1)), (np.sum(nans), )) return value diff --git a/Orange/widgets/evaluate/owconfusionmatrix.py b/Orange/widgets/evaluate/owconfusionmatrix.py index cb982fcea94..914daf55332 100644 --- a/Orange/widgets/evaluate/owconfusionmatrix.py +++ b/Orange/widgets/evaluate/owconfusionmatrix.py @@ -118,6 +118,7 @@ class Outputs: class Error(widget.OWWidget.Error): no_regression = Msg("Confusion Matrix cannot show regression results.") invalid_values = Msg("Evaluation Results input contains invalid values") + empty_input = widget.Msg("Empty result on input. Nothing to display.") def __init__(self): super().__init__() @@ -245,11 +246,14 @@ def set_results(self, results): if results is not None and results.data is not None: data = results.data[results.row_indices] + self.Error.no_regression.clear() + self.Error.empty_input.clear() if data is not None and not data.domain.has_discrete_class: self.Error.no_regression() data = results = None - else: - self.Error.no_regression.clear() + elif results is not None and not results.actual.size: + self.Error.empty_input() + data = results = None nan_values = False if results is not None: diff --git a/Orange/widgets/evaluate/owrocanalysis.py b/Orange/widgets/evaluate/owrocanalysis.py index 361c36cbfd1..44779baaf05 100644 --- a/Orange/widgets/evaluate/owrocanalysis.py +++ b/Orange/widgets/evaluate/owrocanalysis.py @@ -303,10 +303,6 @@ class OWROCAnalysis(widget.OWWidget): class Inputs: evaluation_results = Input("Evaluation Results", Orange.evaluation.Results) - class Warning(widget.OWWidget.Warning): - empty_results = widget.Msg( - "Empty results on input. There is nothing to display.") - target_index = settings.Setting(0) selected_classifiers = [] diff --git a/Orange/widgets/evaluate/tests/test_owpredictions.py b/Orange/widgets/evaluate/tests/test_owpredictions.py index a4139069d0b..9318f370b45 100644 --- a/Orange/widgets/evaluate/tests/test_owpredictions.py +++ b/Orange/widgets/evaluate/tests/test_owpredictions.py @@ -7,8 +7,12 @@ from Orange.data.io import TabReader from Orange.widgets.tests.base import WidgetTest from Orange.widgets.evaluate.owpredictions import OWPredictions +from Orange.widgets.evaluate.owcalibrationplot import OWCalibrationPlot +from Orange.widgets.evaluate.owconfusionmatrix import OWConfusionMatrix +from Orange.widgets.evaluate.owliftcurve import OWLiftCurve +from Orange.widgets.evaluate.owrocanalysis import OWROCAnalysis -from Orange.data import Table, Domain +from Orange.data import Table, Domain, DiscreteVariable from Orange.modelling import ConstantLearner, TreeLearner from Orange.evaluation import Results from Orange.widgets.tests.utils import excepthook_catch @@ -49,6 +53,38 @@ def test_nan_target_input(self): evres = self.get_output(self.widget.Outputs.evaluation_results) self.assertEqual(len(evres.data), 0) + def test_no_values_target(self): + train = Table("titanic") + model = ConstantLearner()(train) + self.send_signal(self.widget.Inputs.predictors, model) + domain = Domain([DiscreteVariable("status", values=["first", "third"]), + DiscreteVariable("age", values=["adult", "child"]), + DiscreteVariable("sex", values=["female", "male"])], + [DiscreteVariable("survived", values=[])]) + test = Table(domain, np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]]), + np.full((3, 1), np.nan)) + self.send_signal(self.widget.Inputs.data, test) + pred = self.get_output(self.widget.Outputs.predictions) + self.assertEqual(len(pred), len(test)) + + results = self.get_output(self.widget.Outputs.evaluation_results) + + cm_widget = self.create_widget(OWConfusionMatrix) + self.send_signal(cm_widget.Inputs.evaluation_results, results, + widget=cm_widget) + + ra_widget = self.create_widget(OWROCAnalysis) + self.send_signal(ra_widget.Inputs.evaluation_results, results, + widget=ra_widget) + + lc_widget = self.create_widget(OWLiftCurve) + self.send_signal(lc_widget.Inputs.evaluation_results, results, + widget=lc_widget) + + cp_widget = self.create_widget(OWCalibrationPlot) + self.send_signal(cp_widget.Inputs.evaluation_results, results, + widget=cp_widget) + def test_mismatching_targets(self): warning = self.widget.Warning diff --git a/Orange/widgets/evaluate/utils.py b/Orange/widgets/evaluate/utils.py index 730982743a2..eb93c8583d0 100644 --- a/Orange/widgets/evaluate/utils.py +++ b/Orange/widgets/evaluate/utils.py @@ -32,6 +32,9 @@ def anynan(a): elif not results.data.domain.has_discrete_class: error_group.invalid_results( "Discrete outcome variable is required") + elif not results.actual.size: + error_group.invalid_results( + "Empty result on input. Nothing to display.") elif check_nan and (anynan(results.actual) or anynan(results.predicted) or (results.probabilities is not None and