Skip to content

Commit df27712

Browse files
committed
OWSieve: Fix crash for attribute with no values
1 parent 5ff92a9 commit df27712

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

Orange/widgets/visualize/owsieve.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,29 @@ class ChiSqStats:
2929
pair of attributes. The class is also used for ranking.
3030
"""
3131
def __init__(self, data, attr1, attr2):
32-
self.observed = get_contingency(data, attr1, attr2)
33-
self.n = np.sum(self.observed)
34-
self.probs_x = self.observed.sum(axis=0) / self.n
35-
self.probs_y = self.observed.sum(axis=1) / self.n
36-
self.expected = np.outer(self.probs_y, self.probs_x) * self.n
32+
attr1 = data.domain[attr1]
33+
attr2 = data.domain[attr2]
34+
if attr1.is_discrete and not attr1.values or \
35+
attr2.is_discrete and not data.domain[attr2].values:
36+
self.observed, self.n = np.nan, len(data)
37+
self.probs_x, self.probs_y = [], []
38+
if attr1.values:
39+
observed_x = np.unique(data.get_column_view(
40+
data.domain.index(attr1))[0], return_counts=True)[1]
41+
self.probs_x = observed_x / self.n
42+
self.observed = observed_x
43+
if attr2.values:
44+
observed_y = np.unique(data.get_column_view(
45+
data.domain.index(attr2))[0], return_counts=True)[1]
46+
self.probs_y = observed_y / self.n
47+
self.observed = observed_y
48+
self.expected = self.observed
49+
else:
50+
self.observed = get_contingency(data, attr1, attr2)
51+
self.n = np.sum(self.observed)
52+
self.probs_x = self.observed.sum(axis=0) / self.n
53+
self.probs_y = self.observed.sum(axis=1) / self.n
54+
self.expected = np.outer(self.probs_y, self.probs_x) * self.n
3755
self.residuals = \
3856
(self.observed - self.expected) / np.sqrt(self.expected)
3957
self.chisqs = self.residuals ** 2
@@ -447,6 +465,20 @@ def _oper(attr, txt):
447465
max_xlabel_h = max(int(xl.boundingRect().height()), max_xlabel_h)
448466
curr_x += width
449467

468+
if not disc_x.values and disc_y.values:
469+
curr_y = y_off
470+
for y in range(len(chi.probs_y) - 1, -1, -1):
471+
py = chi.probs_y[y]
472+
if py == 0:
473+
continue
474+
text(disc_y.values[y], x_off, curr_y + square_size * py / 2,
475+
Qt.AlignRight | Qt.AlignVCenter)
476+
curr_y += square_size * py
477+
478+
if not disc_x.values or not disc_y.values:
479+
text("No data", square_size / 2 + x_off + 30,
480+
square_size / 2 + y_off, Qt.AlignRight | Qt.AlignVCenter)
481+
450482
bottom = y_off + square_size + max_xlabel_h
451483
text(attr_y.name, 0, y_off + square_size / 2,
452484
Qt.AlignLeft | Qt.AlignVCenter, bold=True, vertical=True)

Orange/widgets/visualize/tests/test_owsieve.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Test methods with long descriptive names can omit docstrings
22
# pylint: disable=missing-docstring
3+
import numpy as np
4+
35
from AnyQt.QtCore import QEvent, QPoint, Qt
46
from AnyQt.QtGui import QMouseEvent
57

8+
from Orange.data import DiscreteVariable, Domain, Table
69
from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin
710
from Orange.widgets.visualize.owsieve import OWSieveDiagram
811

@@ -26,3 +29,11 @@ def _select_data(self):
2629
QEvent.MouseButtonPress, QPoint(), Qt.LeftButton,
2730
Qt.LeftButton, Qt.KeyboardModifiers()))
2831
return [0, 4, 6, 7, 11, 17, 19, 21, 22, 24, 26, 39, 40, 43, 44, 46]
32+
33+
def test_missing_values(self):
34+
"""Check widget for dataset with missing values"""
35+
attrs = [DiscreteVariable("c1", ["a", "b", "c"])]
36+
class_var = DiscreteVariable("cls", [])
37+
X = np.array([1, 2, 0, 1, 0, 2])[:, None]
38+
data = Table(Domain(attrs, class_var), X, np.array([np.nan] * 6))
39+
self.send_signal("Data", data)

0 commit comments

Comments
 (0)