Skip to content

Commit

Permalink
Merge pull request #1647 from astaric/fix-boxplot
Browse files Browse the repository at this point in the history
[FIX] BoxPlot crashes on variables with no known values (Fixes #1568)
  • Loading branch information
kernc committed Oct 7, 2016
2 parents 3f82460 + 953278e commit bf51f51
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 6 deletions.
17 changes: 11 additions & 6 deletions Orange/widgets/visualize/owboxplot.py
Expand Up @@ -497,8 +497,11 @@ def mean_label(self, stat, attr, val_name):

def draw_axis(self):
"""Draw the horizontal axis and sets self.scale_x"""
bottom = min(stat.a_min for stat in self.stats)
top = max(stat.a_max for stat in self.stats)
misssing_stats = not self.stats
stats = self.stats or [BoxData(np.array([[0.], [1.]]))]
mean_labels = self.mean_labels or [self.mean_label(stats[0], self.attribute, "")]
bottom = min(stat.a_min for stat in stats)
top = max(stat.a_max for stat in stats)

first_val, step = compute_scale(bottom, top)
while bottom <= first_val:
Expand All @@ -507,8 +510,8 @@ def draw_axis(self):
no_ticks = math.ceil((top - first_val) / step) + 1
top = max(top, first_val + no_ticks * step)

gbottom = min(bottom, min(stat.mean - stat.dev for stat in self.stats))
gtop = max(top, max(stat.mean + stat.dev for stat in self.stats))
gbottom = min(bottom, min(stat.mean - stat.dev for stat in stats))
gtop = max(top, max(stat.mean + stat.dev for stat in stats))

bv = self.box_view
viewrect = bv.viewport().rect().adjusted(15, 15, -15, -30)
Expand All @@ -517,7 +520,7 @@ def draw_axis(self):
# In principle we should repeat this until convergence since the new
# scaling is too conservative. (No chance am I doing this.)
mlb = min(stat.mean + mean_lab.min_x / scale_x
for stat, mean_lab in zip(self.stats, self.mean_labels))
for stat, mean_lab in zip(stats, mean_labels))
if mlb < gbottom:
gbottom = mlb
self.scale_x = scale_x = viewrect.width() / (gtop - gbottom)
Expand All @@ -530,8 +533,10 @@ def draw_axis(self):
l = self.box_scene.addLine(val * scale_x, -1, val * scale_x, 1,
self._pen_axis_tick)
l.setZValue(100)

t = self.box_scene.addSimpleText(
self.attribute.repr_val(val), self._axis_font)
self.attribute.repr_val(val) if not misssing_stats else "?",
self._axis_font)
t.setFlags(
t.flags() | QtGui.QGraphicsItem.ItemIgnoresTransformations)
r = t.boundingRect()
Expand Down
55 changes: 55 additions & 0 deletions Orange/widgets/visualize/tests/test_owboxplot.py
@@ -0,0 +1,55 @@
# Test methods with long descriptive names can omit docstrings
# pylint: disable=missing-docstring
from unittest import skip

import numpy as np
from Orange.data import Table, ContinuousVariable
from Orange.widgets.visualize.owboxplot import OWBoxPlot
from Orange.widgets.tests.base import WidgetTest


class TestOWBoxPlot(WidgetTest):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.iris = Table("iris")
cls.zoo = Table("zoo")
cls.housing = Table("housing")

def setUp(self):
self.widget = self.create_widget(OWBoxPlot)

@skip("Known bug, FIXME!")
def test_input_data(self):
"""Check widget's data"""
self.send_signal("Data", self.iris)
self.assertGreater(len(self.widget.attrs), 0)
self.send_signal("Data", None)
self.assertEqual(len(self.widget.attrs), 0)

def test_input_data_missings_cont_group_var(self):
"""Check widget with continuous data with missing values and group variable"""
data = self.iris
data.X[:, 0] = np.nan
self.send_signal("Data", data)
# used to crash, see #1568

def test_input_data_missings_cont_no_group_var(self):
"""Check widget with continuous data with missing values and no group variable"""
data = self.housing
data.X[:, 0] = np.nan
self.send_signal("Data", data)
# used to crash, see #1568

def test_input_data_missings_disc_group_var(self):
"""Check widget with discrete data with missing values and group variable"""
data = self.zoo
data.X[:, 0] = np.nan
self.send_signal("Data", data)

def test_input_data_missings_disc_no_group_var(self):
"""Check widget discrete data with missing values and no group variable"""
data = self.zoo
data.domain.class_var = ContinuousVariable("cls")
data.X[:, 0] = np.nan
self.send_signal("Data", data)

0 comments on commit bf51f51

Please sign in to comment.