diff --git a/Orange/widgets/visualize/owsieve.py b/Orange/widgets/visualize/owsieve.py index 7ed4b88ee21..374b197b71f 100644 --- a/Orange/widgets/visualize/owsieve.py +++ b/Orange/widgets/visualize/owsieve.py @@ -29,6 +29,12 @@ class ChiSqStats: pair of attributes. The class is also used for ranking. """ def __init__(self, data, attr1, attr2): + attr1 = data.domain[attr1] + attr2 = data.domain[attr2] + if attr1.is_discrete and not attr1.values or \ + attr2.is_discrete and not attr2.values: + self.p = np.nan + return self.observed = get_contingency(data, attr1, attr2) self.n = np.sum(self.observed) self.probs_x = self.observed.sum(axis=0) / self.n @@ -403,15 +409,22 @@ def _oper(attr, txt): view = self.canvasView chi = ChiSqStats(self.discrete_data, disc_x, disc_y) - n = chi.n max_ylabel_w = max((width(val) for val in disc_y.values), default=0) max_ylabel_w = min(max_ylabel_w, 200) x_off = width(attr_x.name) + max_ylabel_w y_off = 15 - square_size = min(view.width() - x_off - 35, view.height() - y_off - 50) + square_size = min(view.width() - x_off - 35, view.height() - y_off - 80) square_size = max(square_size, 10) self.canvasView.setSceneRect(0, 0, view.width(), view.height()) - + if not disc_x.values or not disc_y.values: + text_ = "Features {} and {} have no values".format(disc_x, disc_y) \ + if not disc_x.values and not disc_y.values and \ + disc_x != disc_y else "Feature {} has no values".format( + disc_x if not disc_x.values else disc_y) + text(text_, view.width() / 2 + 70, view.height() / 2, + Qt.AlignRight | Qt.AlignVCenter) + return + n = chi.n curr_x = x_off max_xlabel_h = 0 self.areas = [] @@ -452,6 +465,7 @@ def _oper(attr, txt): Qt.AlignLeft | Qt.AlignVCenter, bold=True, vertical=True) text(attr_x.name, x_off + square_size / 2, bottom, Qt.AlignHCenter | Qt.AlignTop, bold=True) + bottom += 30 xl = text("χ²={:.2f}, p={:.3f}".format(chi.chisq, chi.p), 0, bottom) # Assume similar height for both lines diff --git a/Orange/widgets/visualize/tests/test_owsieve.py b/Orange/widgets/visualize/tests/test_owsieve.py index 5f849ac3c12..9b644464cef 100644 --- a/Orange/widgets/visualize/tests/test_owsieve.py +++ b/Orange/widgets/visualize/tests/test_owsieve.py @@ -1,8 +1,11 @@ # Test methods with long descriptive names can omit docstrings # pylint: disable=missing-docstring +import numpy as np + from AnyQt.QtCore import QEvent, QPoint, Qt from AnyQt.QtGui import QMouseEvent +from Orange.data import DiscreteVariable, Domain, Table from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin from Orange.widgets.visualize.owsieve import OWSieveDiagram @@ -26,3 +29,11 @@ def _select_data(self): QEvent.MouseButtonPress, QPoint(), Qt.LeftButton, Qt.LeftButton, Qt.KeyboardModifiers())) return [0, 4, 6, 7, 11, 17, 19, 21, 22, 24, 26, 39, 40, 43, 44, 46] + + def test_missing_values(self): + """Check widget for dataset with missing values""" + attrs = [DiscreteVariable("c1", ["a", "b", "c"])] + class_var = DiscreteVariable("cls", []) + X = np.array([1, 2, 0, 1, 0, 2])[:, None] + data = Table(Domain(attrs, class_var), X, np.array([np.nan] * 6)) + self.send_signal("Data", data)