Skip to content

Commit 2130ec3

Browse files
jernejumstrazar
authored andcommitted
Mosaic - change the variable used for coloring
biolabGH-2133 biolabGH-2036
1 parent 635f507 commit 2130ec3

File tree

2 files changed

+114
-19
lines changed

2 files changed

+114
-19
lines changed

Orange/widgets/visualize/owmosaic.py

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# pylint: disable=too-many-lines
12
from collections import defaultdict
23
from functools import reduce
34
from itertools import product, chain
@@ -10,7 +11,7 @@
1011
from AnyQt.QtGui import QColor, QPainter, QPen, QStandardItem
1112
from AnyQt.QtWidgets import QGraphicsScene, QGraphicsLineItem
1213

13-
from Orange.data import Table, filter, Variable
14+
from Orange.data import Table, filter, Variable, Domain
1415
from Orange.data.sql.table import SqlTable, LARGE_TABLE, DEFAULT_SAMPLE_TIME
1516
from Orange.preprocess import Discretize
1617
from Orange.preprocess.discretize import EqualFreq
@@ -23,6 +24,7 @@
2324
from Orange.widgets.utils import to_html, get_variable_values_sorted
2425
from Orange.widgets.utils.annotated_data import (create_annotated_table,
2526
ANNOTATED_DATA_SIGNAL_NAME)
27+
from Orange.widgets.utils.itemmodels import DomainModel
2628
from Orange.widgets.visualize.utils import (
2729
CanvasText, CanvasRectangle, ViewWithPress, VizRankDialog)
2830
from Orange.widgets.widget import OWWidget, Default, Msg
@@ -118,7 +120,7 @@ def check_preconditions(self):
118120
def compute_attr_order(self):
119121
"""
120122
Order attributes by Relief if there is a target variable. In case of
121-
ties or without target, other by name.
123+
ties or without target, order by name.
122124
123125
Add the class variable at the beginning when not coloring by class
124126
distribution.
@@ -250,7 +252,7 @@ def on_selection_changed(self, selected, deselected):
250252
def row_for_state(self, score, state):
251253
"""The row consists of attributes sorted by name; class is at the
252254
beginning, if present, so it's on the x-axis and not lost somewhere."""
253-
class_var = self.master.data.domain.class_var
255+
class_var = self.master.color_data.domain.class_var
254256
attrs = tuple(
255257
sorted((self.attr_ordering[x] for x in state),
256258
key=lambda attr: (1 - (attr is class_var), attr.name)))
@@ -271,8 +273,6 @@ class OWMosaicDisplay(OWWidget):
271273
(ANNOTATED_DATA_SIGNAL_NAME, Table)]
272274

273275
PEARSON, CLASS_DISTRIBUTION = 0, 1
274-
interior_coloring_opts = ["Pearson residuals",
275-
"Class distribution"]
276276

277277
settingsHandler = DomainContextHandler()
278278
use_boxes = Setting(True)
@@ -281,6 +281,7 @@ class OWMosaicDisplay(OWWidget):
281281
variable2 = ContextSetting("", exclude_metas=False)
282282
variable3 = ContextSetting("", exclude_metas=False)
283283
variable4 = ContextSetting("", exclude_metas=False)
284+
variable_color = ContextSetting("", exclude_metas=False)
284285
selection = ContextSetting(set())
285286

286287
BAR_WIDTH = 5
@@ -310,6 +311,8 @@ def __init__(self):
310311
self.unprocessed_subset_data = None
311312
self.subset_data = None
312313

314+
self.color_data = None
315+
313316
self.areas = []
314317

315318
self.canvas = QGraphicsScene()
@@ -331,13 +334,18 @@ def __init__(self):
331334
self.vizrank, self.vizrank_button = MosaicVizRank.add_vizrank(
332335
box, self, "Find Informative Mosaics", self.set_attr)
333336

334-
self.rb_colors = gui.radioButtonsInBox(
335-
self.controlArea, self, "interior_coloring",
336-
self.interior_coloring_opts, box="Interior Coloring",
337-
callback=self.coloring_changed)
337+
box2 = gui.vBox(self.controlArea, box="Interior Coloring")
338+
dmod = DomainModel
339+
self.color_model = DomainModel(order=dmod.MIXED,
340+
valid_types=dmod.PRIMITIVE,
341+
placeholder="(Pearson residuals)")
342+
self.cb_attr_color = gui.comboBox(
343+
box2, self, value="variable_color",
344+
orientation=Qt.Horizontal, contentsLength=12, labelWidth=50,
345+
callback=self.set_color_data,
346+
sendSelectedValue=True, model=self.color_model, valueType=str)
338347
self.bar_button = gui.checkBox(
339-
gui.indentedBox(self.rb_colors),
340-
self, 'use_boxes', label='Compare with total',
348+
box2, self, 'use_boxes', label='Compare with total',
341349
callback=self._compare_with_total)
342350
gui.rubber(self.controlArea)
343351

@@ -380,7 +388,7 @@ def init_combos(self, data):
380388

381389
icons = gui.attributeIconDict
382390
for attr in chain(data.domain, data.domain.metas):
383-
if attr.is_discrete or attr.is_continuous:
391+
if attr.is_primitive:
384392
for combo in self.attr_combos:
385393
combo.addItem(icons[attr], attr.name)
386394

@@ -390,6 +398,12 @@ def init_combos(self, data):
390398
2 * (self.attr_combos[1].count() > 2))
391399
self.variable3 = self.attr_combos[2].itemText(0)
392400
self.variable4 = self.attr_combos[3].itemText(0)
401+
if self.data.domain.class_var:
402+
self.variable_color = self.data.domain.class_var.name
403+
idx = self.cb_attr_color.findText(self.variable_color)
404+
else:
405+
idx = 0
406+
self.cb_attr_color.setCurrentIndex(idx)
393407

394408
def get_attr_list(self):
395409
return [
@@ -416,8 +430,6 @@ def set_data(self, data):
416430

417431
self.closeContext()
418432
self.data = data
419-
self.init_combos(self.data)
420-
self.discrete_data = self._get_discrete_data(self.data)
421433

422434
self.vizrank.stop_and_reset()
423435
self.vizrank_button.setEnabled(
@@ -427,10 +439,8 @@ def set_data(self, data):
427439
if self.data is None:
428440
return
429441

430-
has_class = self.data.domain.class_var is not None
431-
self.rb_colors.setDisabled(not has_class)
432-
self.interior_coloring = \
433-
self.CLASS_DISTRIBUTION if has_class else self.PEARSON
442+
self.color_model.set_domain(self.data.domain)
443+
self.init_combos(self.data)
434444

435445
self.openContext(self.data)
436446

@@ -439,6 +449,8 @@ def set_data(self, data):
439449
self.set_subset_data(self.unprocessed_subset_data)
440450
self.unprocessed_subset_data = None
441451

452+
self.set_color_data()
453+
442454
def set_subset_data(self, data):
443455
self.Warning.incompatible_subset.clear()
444456
if self.data is None:
@@ -468,6 +480,26 @@ def reset_graph(self):
468480
self.clear_selection()
469481
self.update_graph()
470482

483+
def set_color_data(self):
484+
if self.data is None or len(self.data) < 2 or len(self.data.domain.attributes) < 1:
485+
return
486+
if self.cb_attr_color.currentIndex() <= 0:
487+
color_var = None
488+
self.interior_coloring = self.PEARSON
489+
self.bar_button.setEnabled(False)
490+
else:
491+
color_var = self.data.domain[self.cb_attr_color.currentText()]
492+
self.interior_coloring = self.CLASS_DISTRIBUTION
493+
self.bar_button.setEnabled(True)
494+
attributes = [v for v in self.data.domain if v != color_var]
495+
metas = [v for v in self.data.domain.metas if v != color_var]
496+
domain = Domain(attributes, color_var, metas)
497+
self.color_data = color_data = self.data.from_table(domain, self.data)
498+
self.discrete_data = self._get_discrete_data(color_data)
499+
self.vizrank.stop_and_reset()
500+
self.vizrank_button.setEnabled(True)
501+
self.coloring_changed()
502+
471503
def update_selection_rects(self):
472504
for i, (_, _, area) in enumerate(self.areas):
473505
if i in self.selection:

Orange/widgets/visualize/tests/test_owmosaic.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
StringVariable
1111
from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin
1212
from Orange.widgets.visualize.owmosaic import OWMosaicDisplay
13-
13+
from Orange.widgets.tests.utils import simulate
1414

1515
class TestOWMosaicDisplay(WidgetTest, WidgetOutputsTestMixin):
1616
@classmethod
@@ -227,3 +227,66 @@ def test_nan_column(self):
227227
])
228228
)
229229
self.send_signal("Data", table)
230+
231+
def test_color_combo(self):
232+
"""
233+
Color combo enables to select class values. Checks if class values
234+
are selected correctly.
235+
GH-2133
236+
GH-2036
237+
"""
238+
table = Table("iris")
239+
self.send_signal("Data", table)
240+
color_vars = ["(Pearson residuals)"] + [str(x) for x in table.domain]
241+
for i in range(0, len(color_vars)):
242+
idx = self.widget.cb_attr_color.findText(color_vars[i])
243+
self.widget.cb_attr_color.setCurrentIndex(idx)
244+
color = self.widget.cb_attr_color.currentText()
245+
simulate.combobox_activate_index(self.widget.controls.variable_color, idx, 0)
246+
discrete_data = self.widget.discrete_data
247+
248+
if color == "(Pearson residuals)":
249+
self.assertIsNone(discrete_data.domain.class_var)
250+
else:
251+
self.assertEqual(color, str(discrete_data.domain.class_var))
252+
output = self.get_output("Data")
253+
self.assertEqual(output.domain.class_var, table.domain.class_var)
254+
255+
def test_vizrank(self):
256+
"""
257+
Tests if vizrank works accordingly to selected color value.
258+
GH-2133
259+
GH-2036
260+
"""
261+
def test(i):
262+
self.send_signal("Data", table)
263+
idx = self.widget.cb_attr_color.findText(color_vars[i])
264+
self.widget.cb_attr_color.setCurrentIndex(idx)
265+
color = self.widget.cb_attr_color.currentText()
266+
simulate.combobox_activate_index(self.widget.controls.variable_color, idx, 0)
267+
self.widget.vizrank.button.click()
268+
time.sleep(.5)
269+
model = self.widget.vizrank.rank_model
270+
nrows = model.rowCount()
271+
all_data = []
272+
self.assertTrue((nrows == 7 and i != 0) or (nrows == 10 and i == 0))
273+
for row in range(nrows):
274+
data = []
275+
for column in range(model.columnCount()):
276+
index = model.index(row, column)
277+
data.append(str(model.data(index)))
278+
all_data = all_data + str(model.data(index)).replace(',', '').split()
279+
for text in data:
280+
self.assertNotIn(color, text)
281+
self.assertEqual(len(set(all_data)), 3 if color != "(Pearson residuals)" else 4)
282+
self.vizrank.stop_and_reset()
283+
self.vizrank.toggle()
284+
285+
table = Table("titanic")
286+
self.send_signal("Data", table)
287+
self.widget.vizrank.max_attrs = 4
288+
color_vars = ["(Pearson residuals)"] + [str(x) for x in table.domain]
289+
290+
for i in range(len(color_vars)):
291+
self.widget = self.create_widget(OWMosaicDisplay)
292+
test(i)

0 commit comments

Comments
 (0)