Skip to content

Commit 3929c05

Browse files
lanzagarastaric
authored andcommitted
Merge pull request biolab#1886 from markotoplak/concatenate_bugfix
[FIX] Concatenate bugfix (cherry picked from commit aafacce)
1 parent 0c46ac9 commit 3929c05

File tree

2 files changed

+113
-9
lines changed

2 files changed

+113
-9
lines changed

Orange/widgets/data/owconcatenate.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ class OWConcatenate(widget.OWWidget):
2828
icon = "icons/Concatenate.svg"
2929

3030
inputs = [("Primary Data", Orange.data.Table,
31-
"set_primary_data", widget.Default),
31+
"set_primary_data"),
3232
("Additional Data", Orange.data.Table,
33-
"set_more_data", widget.Multiple)]
33+
"set_more_data", widget.Multiple | widget.Default)]
3434
outputs = [("Data", Orange.data.Table)]
3535

3636
#: Domain merging operations
@@ -64,9 +64,9 @@ def __init__(self):
6464
self.primary_data = None
6565
self.more_data = OrderedDict()
6666

67-
mergebox = gui.vBox(self.controlArea, "Domain Merging")
67+
self.mergebox = gui.vBox(self.controlArea, "Domain Merging")
6868
box = gui.radioButtons(
69-
mergebox, self, "merge_type",
69+
self.mergebox, self, "merge_type",
7070
callback=self._merge_type_changed)
7171

7272
gui.widgetLabel(
@@ -91,7 +91,8 @@ def __init__(self):
9191

9292
cb = gui.checkBox(
9393
box, self, "append_source_column",
94-
self.tr("Append data source IDs"))
94+
self.tr("Append data source IDs"),
95+
callback=self._source_changed)
9596

9697
ibox = gui.indentedBox(box, sep=gui.checkButtonOffsetHint(cb))
9798

@@ -104,12 +105,13 @@ def __init__(self):
104105

105106
form.addRow(
106107
self.tr("Feature name:"),
107-
gui.lineEdit(ibox, self, "source_attr_name", valueType=str))
108+
gui.lineEdit(ibox, self, "source_attr_name", valueType=str,
109+
callback=self._source_changed))
108110

109111
form.addRow(
110112
self.tr("Place:"),
111-
gui.comboBox(ibox, self, "source_column_role", items=self.id_roles)
112-
)
113+
gui.comboBox(ibox, self, "source_column_role", items=self.id_roles,
114+
callback=self._source_changed))
113115

114116
ibox.layout().addLayout(form)
115117
mleft, mtop, mright, _ = ibox.layout().getContentsMargins()
@@ -135,6 +137,7 @@ def set_more_data(self, data=None, id=None):
135137
del self.more_data[id]
136138

137139
def handleNewSignals(self):
140+
self.mergebox.setDisabled(self.primary_data is not None)
138141
self.apply()
139142

140143
def apply(self):
@@ -180,6 +183,9 @@ def _merge_type_changed(self, ):
180183
if self.primary_data is None and self.more_data:
181184
self.apply()
182185

186+
def _source_changed(self):
187+
self.apply()
188+
183189
def send_report(self):
184190
items = OrderedDict()
185191
if self.primary_data is not None:
@@ -261,7 +267,7 @@ def ascolumn(array):
261267
metas = [ascolumn(col) for _, col in metas]
262268

263269
X = numpy.hstack((data.X,) + tuple(attr_cols))
264-
Y = numpy.hstack((data.Y,) + tuple(class_cols))
270+
Y = numpy.hstack((data._Y,) + tuple(class_cols))
265271
metas = numpy.hstack((data.metas,) + tuple(metas))
266272

267273
new_data = Orange.data.Table.from_numpy(new_domain, X, Y, metas)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Test methods with long descriptive names can omit docstrings
2+
# pylint: disable=missing-docstring
3+
4+
import numpy as np
5+
6+
from Orange.data import Table, Domain
7+
from Orange.widgets.data.owconcatenate import OWConcatenate
8+
from Orange.widgets.tests.base import WidgetTest
9+
10+
11+
class TestOWConcatenate(WidgetTest):
12+
13+
def setUp(self):
14+
self.widget = self.create_widget(OWConcatenate)
15+
self.iris = Table("iris")
16+
self.titanic = Table("titanic")
17+
18+
def test_single_input(self):
19+
self.assertIsNone(self.get_output("Data"))
20+
self.send_signal("Primary Data", self.iris)
21+
output = self.get_output("Data")
22+
self.assertEqual(list(output), list(self.iris))
23+
self.send_signal("Primary Data", None)
24+
self.assertIsNone(self.get_output("Data"))
25+
self.send_signal("Additional Data", self.iris)
26+
output = self.get_output("Data")
27+
self.assertEqual(list(output), list(self.iris))
28+
self.send_signal("Additional Data", None)
29+
self.assertIsNone(self.get_output("Data"))
30+
31+
def test_two_inputs_union(self):
32+
self.send_signal("Additional Data", self.iris, 0)
33+
self.send_signal("Additional Data", self.titanic, 1)
34+
output = self.get_output("Data")
35+
# needs to contain all instances
36+
self.assertEqual(len(output), len(self.iris) + len(self.titanic))
37+
# needs to contain all variables
38+
outvars = output.domain.variables
39+
self.assertLess(set(self.iris.domain.variables), set(outvars))
40+
self.assertLess(set(self.titanic.domain.variables), set(outvars))
41+
# the first part of the data set is iris, the second part is titanic
42+
np.testing.assert_equal(self.iris.X, output.X[:len(self.iris), :-3])
43+
self.assertTrue(np.isnan(output.X[:len(self.iris), -3:]).all())
44+
np.testing.assert_equal(self.titanic.X, output.X[len(self.iris):, -3:])
45+
self.assertTrue(np.isnan(output.X[len(self.iris):, :-3]).all())
46+
47+
def test_two_inputs_intersection(self):
48+
self.send_signal("Additional Data", self.iris, 0)
49+
self.send_signal("Additional Data", self.titanic, 1)
50+
self.widget.controls.merge_type.buttons[1].click()
51+
output = self.get_output("Data")
52+
# needs to contain all instances
53+
self.assertEqual(len(output), len(self.iris) + len(self.titanic))
54+
# no common variables
55+
outvars = output.domain.variables
56+
self.assertEqual(0, len(outvars))
57+
58+
def test_source(self):
59+
self.send_signal("Additional Data", self.iris, 0)
60+
self.send_signal("Additional Data", self.titanic, 1)
61+
outputb = self.get_output("Data")
62+
outvarsb = outputb.domain.variables
63+
def get_source():
64+
output = self.get_output("Data")
65+
outvars = output.domain.variables + output.domain.metas
66+
return (set(outvars) - set(outvarsb)).pop()
67+
# test adding source
68+
self.widget.controls.append_source_column.toggle()
69+
source = get_source()
70+
self.assertEquals(source.name, "Source ID")
71+
# test name changing
72+
self.widget.controls.source_attr_name.setText("Source")
73+
self.widget.controls.source_attr_name.callback()
74+
source = get_source()
75+
self.assertEquals(source.name, "Source")
76+
# test source_column role
77+
places = ["class_vars", "attributes", "metas"]
78+
for i, place in enumerate(places):
79+
self.widget.source_column_role = i
80+
self.widget.apply()
81+
source = get_source()
82+
output = self.get_output("Data")
83+
self.assertTrue(source in getattr(output.domain, place))
84+
data = Table(Domain([source]), output)
85+
np.testing.assert_equal(data[:len(self.iris)].X, 0)
86+
np.testing.assert_equal(data[len(self.iris):].X, 1)
87+
88+
def test_singleclass_source_class(self):
89+
self.send_signal("Primary Data", self.iris)
90+
# add source into a class variable
91+
self.widget.controls.append_source_column.toggle()
92+
93+
def test_disable_merging_on_primary(self):
94+
self.assertTrue(self.widget.mergebox.isEnabled())
95+
self.send_signal("Primary Data", self.iris)
96+
self.assertFalse(self.widget.mergebox.isEnabled())
97+
self.send_signal("Primary Data", None)
98+
self.assertTrue(self.widget.mergebox.isEnabled())

0 commit comments

Comments
 (0)