diff --git a/Orange/widgets/classify/owclassificationtree.py b/Orange/widgets/classify/owclassificationtree.py
index f0a1accf7c2..eb95da3306c 100644
--- a/Orange/widgets/classify/owclassificationtree.py
+++ b/Orange/widgets/classify/owclassificationtree.py
@@ -2,8 +2,10 @@
from Orange.data import Table
from Orange.modelling.tree import TreeLearner
+from Orange.classification.tree import TreeLearner as ClassificationTreeLearner
from Orange.widgets.model.owtree import OWTreeLearner
from Orange.widgets.utils.owlearnerwidget import OWBaseLearner
+from Orange.widgets.widget import Msg
class OWTreeLearner(OWTreeLearner):
@@ -21,6 +23,29 @@ class OWTreeLearner(OWTreeLearner):
"limit_majority", "sufficient_majority", 51, 100),) + \
OWTreeLearner.spin_boxes[-1:]
+ class Error(OWTreeLearner.Error):
+ cannot_binarize = Msg("Binarization cannot handle '{}'\n"
+ "because it has {} values. "
+ "Binarization can handle up to {}.\n"
+ "Disable 'Induce binary tree' to proceed.")
+
+ def check_data(self):
+ self.Error.cannot_binarize.clear()
+ if not super().check_data():
+ return False
+ if not self.binary_trees:
+ return True
+ max_values, max_attr = max(
+ ((len(attr.values), attr)
+ for attr in self.data.domain.attributes if attr.is_discrete),
+ default=(0, None))
+ MAX_BINARIZATION = ClassificationTreeLearner.MAX_BINARIZATION
+ if max_values > MAX_BINARIZATION:
+ self.Error.cannot_binarize(
+ max_attr.name, max_values, MAX_BINARIZATION)
+ return False
+ return True
+
def learner_kwargs(self):
opts = super().learner_kwargs()
opts['sufficient_majority'] = \
diff --git a/Orange/widgets/classify/tests/test_owclassificationtree.py b/Orange/widgets/classify/tests/test_owclassificationtree.py
index 24e2af13e18..0445023d7d4 100644
--- a/Orange/widgets/classify/tests/test_owclassificationtree.py
+++ b/Orange/widgets/classify/tests/test_owclassificationtree.py
@@ -1,5 +1,7 @@
# Test methods with long descriptive names can omit docstrings
# pylint: disable=missing-docstring
+from Orange.data import Table, Domain, DiscreteVariable
+from Orange.classification.tree import TreeLearner as ClassificationTreeLearner
from Orange.base import Model
from Orange.widgets.classify.owclassificationtree import OWTreeLearner
from Orange.widgets.tests.base import (WidgetTest, DefaultParameterMapping,
@@ -7,6 +9,11 @@
class TestOWClassificationTree(WidgetTest, WidgetLearnerTestMixin):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.iris = Table("iris")
+
def setUp(self):
self.widget = self.create_widget(
OWTreeLearner, stored_settings={"auto_apply": False})
@@ -34,3 +41,50 @@ def test_parameters_unchecked(self):
for par, val in zip(self.parameters, (None, 2, 1))]
self.test_parameters()
+ def test_cannot_binarize(self):
+ widget = self.widget
+ error_shown = widget.Error.cannot_binarize.is_shown
+ self.assertFalse(error_shown())
+ self.send_signal("Data", self.iris)
+
+ # The widget outputs ClassificationTreeLearner.
+ # If not, below tests may not make sense
+ learner = self.get_output("Learner")
+ dlearner = learner.get_learner(learner.CLASSIFICATION)
+ self.assertTrue(dlearner, ClassificationTreeLearner)
+
+ # No error on Iris
+ max_binarization = dlearner.MAX_BINARIZATION
+ self.assertFalse(error_shown())
+
+ # Error when too many values
+ domain = Domain([
+ DiscreteVariable(
+ values=[str(x) for x in range(max_binarization + 1)])],
+ DiscreteVariable(values="01"))
+ self.send_signal("Data", Table(domain, [[0, 0], [1, 1]]))
+ self.assertTrue(error_shown())
+ # No more error on Iris
+ self.send_signal("Data", self.iris)
+ self.assertFalse(error_shown())
+
+ # Checking and unchecking binarization works
+ widget.controls.binary_trees.click()
+ self.assertFalse(widget.binary_trees)
+ widget.unconditional_apply()
+ self.send_signal("Data", Table(domain, [[0, 0], [1, 1]]))
+ self.assertFalse(error_shown())
+ widget.controls.binary_trees.click()
+ widget.unconditional_apply()
+ self.assertTrue(error_shown())
+ widget.controls.binary_trees.click()
+ widget.unconditional_apply()
+ self.assertFalse(error_shown())
+
+ # If something is wrong with the data, no error appears
+ domain = Domain([
+ DiscreteVariable(
+ values=[str(x) for x in range(max_binarization + 1)])],
+ DiscreteVariable(values="01"))
+ self.send_signal("Data", Table(domain))
+ self.assertFalse(error_shown())
diff --git a/Orange/widgets/utils/messages.py b/Orange/widgets/utils/messages.py
index a8ef0b20e79..d7109f59c9e 100644
--- a/Orange/widgets/utils/messages.py
+++ b/Orange/widgets/utils/messages.py
@@ -335,7 +335,7 @@ def update_message_state(self):
elif self.message_bar is not None:
font_size = self.message_bar.fontInfo().pixelSize()
group = messages[0].group
- text = str(messages[0]) if len(messages) == 1 \
+ text = str(messages[0]).split("\n")[0] if len(messages) == 1 \
else "{} problems during execution".format(len(messages))
# TODO: fix tooltip background color - it is not white
tooltip = ''.join(
@@ -346,7 +346,8 @@ def update_message_state(self):