Skip to content

Commit

Permalink
Merge pull request biolab#1886 from markotoplak/concatenate_bugfix
Browse files Browse the repository at this point in the history
[FIX] Concatenate bugfix
(cherry picked from commit aafacce)
  • Loading branch information
lanzagar authored and astaric committed Jan 18, 2017
1 parent 9712459 commit a24da41
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 9 deletions.
24 changes: 15 additions & 9 deletions Orange/widgets/data/owconcatenate.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class OWConcatenate(widget.OWWidget):
icon = "icons/Concatenate.svg"

inputs = [("Primary Data", Orange.data.Table,
"set_primary_data", widget.Default),
"set_primary_data"),
("Additional Data", Orange.data.Table,
"set_more_data", widget.Multiple)]
"set_more_data", widget.Multiple | widget.Default)]
outputs = [("Data", Orange.data.Table)]

#: Domain merging operations
Expand Down Expand Up @@ -64,9 +64,9 @@ def __init__(self):
self.primary_data = None
self.more_data = OrderedDict()

mergebox = gui.vBox(self.controlArea, "Domain Merging")
self.mergebox = gui.vBox(self.controlArea, "Domain Merging")
box = gui.radioButtons(
mergebox, self, "merge_type",
self.mergebox, self, "merge_type",
callback=self._merge_type_changed)

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

cb = gui.checkBox(
box, self, "append_source_column",
self.tr("Append data source IDs"))
self.tr("Append data source IDs"),
callback=self._source_changed)

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

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

form.addRow(
self.tr("Feature name:"),
gui.lineEdit(ibox, self, "source_attr_name", valueType=str))
gui.lineEdit(ibox, self, "source_attr_name", valueType=str,
callback=self._source_changed))

form.addRow(
self.tr("Place:"),
gui.comboBox(ibox, self, "source_column_role", items=self.id_roles)
)
gui.comboBox(ibox, self, "source_column_role", items=self.id_roles,
callback=self._source_changed))

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

def handleNewSignals(self):
self.mergebox.setDisabled(self.primary_data is not None)
self.apply()

def apply(self):
Expand Down Expand Up @@ -180,6 +183,9 @@ def _merge_type_changed(self, ):
if self.primary_data is None and self.more_data:
self.apply()

def _source_changed(self):
self.apply()

def send_report(self):
items = OrderedDict()
if self.primary_data is not None:
Expand Down Expand Up @@ -261,7 +267,7 @@ def ascolumn(array):
metas = [ascolumn(col) for _, col in metas]

X = numpy.hstack((data.X,) + tuple(attr_cols))
Y = numpy.hstack((data.Y,) + tuple(class_cols))
Y = numpy.hstack((data._Y,) + tuple(class_cols))
metas = numpy.hstack((data.metas,) + tuple(metas))

new_data = Orange.data.Table.from_numpy(new_domain, X, Y, metas)
Expand Down
98 changes: 98 additions & 0 deletions Orange/widgets/data/tests/test_owconcatenate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Test methods with long descriptive names can omit docstrings
# pylint: disable=missing-docstring

import numpy as np

from Orange.data import Table, Domain
from Orange.widgets.data.owconcatenate import OWConcatenate
from Orange.widgets.tests.base import WidgetTest


class TestOWConcatenate(WidgetTest):

def setUp(self):
self.widget = self.create_widget(OWConcatenate)
self.iris = Table("iris")
self.titanic = Table("titanic")

def test_single_input(self):
self.assertIsNone(self.get_output("Data"))
self.send_signal("Primary Data", self.iris)
output = self.get_output("Data")
self.assertEqual(list(output), list(self.iris))
self.send_signal("Primary Data", None)
self.assertIsNone(self.get_output("Data"))
self.send_signal("Additional Data", self.iris)
output = self.get_output("Data")
self.assertEqual(list(output), list(self.iris))
self.send_signal("Additional Data", None)
self.assertIsNone(self.get_output("Data"))

def test_two_inputs_union(self):
self.send_signal("Additional Data", self.iris, 0)
self.send_signal("Additional Data", self.titanic, 1)
output = self.get_output("Data")
# needs to contain all instances
self.assertEqual(len(output), len(self.iris) + len(self.titanic))
# needs to contain all variables
outvars = output.domain.variables
self.assertLess(set(self.iris.domain.variables), set(outvars))
self.assertLess(set(self.titanic.domain.variables), set(outvars))
# the first part of the data set is iris, the second part is titanic
np.testing.assert_equal(self.iris.X, output.X[:len(self.iris), :-3])
self.assertTrue(np.isnan(output.X[:len(self.iris), -3:]).all())
np.testing.assert_equal(self.titanic.X, output.X[len(self.iris):, -3:])
self.assertTrue(np.isnan(output.X[len(self.iris):, :-3]).all())

def test_two_inputs_intersection(self):
self.send_signal("Additional Data", self.iris, 0)
self.send_signal("Additional Data", self.titanic, 1)
self.widget.controls.merge_type.buttons[1].click()
output = self.get_output("Data")
# needs to contain all instances
self.assertEqual(len(output), len(self.iris) + len(self.titanic))
# no common variables
outvars = output.domain.variables
self.assertEqual(0, len(outvars))

def test_source(self):
self.send_signal("Additional Data", self.iris, 0)
self.send_signal("Additional Data", self.titanic, 1)
outputb = self.get_output("Data")
outvarsb = outputb.domain.variables
def get_source():
output = self.get_output("Data")
outvars = output.domain.variables + output.domain.metas
return (set(outvars) - set(outvarsb)).pop()
# test adding source
self.widget.controls.append_source_column.toggle()
source = get_source()
self.assertEquals(source.name, "Source ID")
# test name changing
self.widget.controls.source_attr_name.setText("Source")
self.widget.controls.source_attr_name.callback()
source = get_source()
self.assertEquals(source.name, "Source")
# test source_column role
places = ["class_vars", "attributes", "metas"]
for i, place in enumerate(places):
self.widget.source_column_role = i
self.widget.apply()
source = get_source()
output = self.get_output("Data")
self.assertTrue(source in getattr(output.domain, place))
data = Table(Domain([source]), output)
np.testing.assert_equal(data[:len(self.iris)].X, 0)
np.testing.assert_equal(data[len(self.iris):].X, 1)

def test_singleclass_source_class(self):
self.send_signal("Primary Data", self.iris)
# add source into a class variable
self.widget.controls.append_source_column.toggle()

def test_disable_merging_on_primary(self):
self.assertTrue(self.widget.mergebox.isEnabled())
self.send_signal("Primary Data", self.iris)
self.assertFalse(self.widget.mergebox.isEnabled())
self.send_signal("Primary Data", None)
self.assertTrue(self.widget.mergebox.isEnabled())

0 comments on commit a24da41

Please sign in to comment.