diff --git a/Orange/widgets/data/owtable.py b/Orange/widgets/data/owtable.py index ad3a46a3095..f5dbdc0f5cc 100644 --- a/Orange/widgets/data/owtable.py +++ b/Orange/widgets/data/owtable.py @@ -34,6 +34,8 @@ from Orange.widgets.settings import (Setting, ContextSetting, DomainContextHandler) from Orange.widgets.utils import datacaching +from Orange.widgets.utils.annotated_data import (create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME) from Orange.widgets.utils.itemmodels import TableModel @@ -367,7 +369,7 @@ class OWDataTable(widget.OWWidget): inputs = [("Data", Table, "set_dataset", widget.Multiple)] outputs = [("Selected Data", Table, widget.Default), - ("Other Data", Table)] + (ANNOTATED_DATA_SIGNAL_NAME, Table)] show_distributions = Setting(False) dist_color_RGB = Setting((220, 220, 220, 255)) @@ -506,6 +508,7 @@ def update(f): self.selected_cols = [] self.openContext(data) self.set_selection() + self.commit() def _setup_table_view(self, view, data): """Setup the `view` (QTableView) with `data` (Orange.data.Table) @@ -785,7 +788,7 @@ def commit(self): """ Commit/send the current selected row/column selection. """ - selected_data = other_data = None + selected_data = table = rowsel = None view = self.tabs.currentWidget() if view and view.model() is not None: model = self._get_model(view) @@ -795,7 +798,7 @@ def commit(self): # for SqlTables if isinstance(table, SqlTable): self.send("Selected Data", selected_data) - self.send("Other Data", other_data) + self.send(ANNOTATED_DATA_SIGNAL_NAME, None) return rowsel, colsel = self.get_selection(view) @@ -841,19 +844,14 @@ def select_vars(role): # Avoid a copy if all/none rows are selected. if not rowsel: selected_data = None - other_data = select(table, None, domain) elif len(rowsel) == len(table): selected_data = select(table, None, domain) - other_data = None else: selected_data = select(table, rowsel, domain) - selmask = numpy.ones((len(table),), dtype=bool) - selmask[rowsel] = False - - other_data = select(table, numpy.flatnonzero(selmask), domain) self.send("Selected Data", selected_data) - self.send("Other Data", other_data) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(table, rowsel)) def copy(self): """ diff --git a/Orange/widgets/data/tests/test_owtable.py b/Orange/widgets/data/tests/test_owtable.py index a62f5ed2ffc..95aa75910b4 100644 --- a/Orange/widgets/data/tests/test_owtable.py +++ b/Orange/widgets/data/tests/test_owtable.py @@ -1,22 +1,37 @@ -from Orange.data import Table +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring from Orange.widgets.data.owtable import OWDataTable -from Orange.widgets.tests.base import WidgetTest +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin -class TestOWDataTable(WidgetTest): +class TestOWDataTable(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + def setUp(self): self.widget = self.create_widget(OWDataTable) - self.iris = Table("iris") def test_input_data(self): """Check number of tabs with data on the input""" - self.send_signal("Data", self.iris, 1) + self.send_signal("Data", self.data, 1) self.assertEqual(self.widget.tabs.count(), 1) - self.send_signal("Data", self.iris, 2) + self.send_signal("Data", self.data, 2) self.assertEqual(self.widget.tabs.count(), 2) self.send_signal("Data", None, 1) self.assertEqual(self.widget.tabs.count(), 1) def test_data_model(self): - self.send_signal("Data", self.iris, 1) - self.assertEqual(self.widget.tabs.widget(0).model().rowCount(), len(self.iris)) + self.send_signal("Data", self.data, 1) + self.assertEqual(self.widget.tabs.widget(0).model().rowCount(), + len(self.data)) + + def _select_data(self): + self.widget.selected_cols = list(range(len(self.data.domain))) + self.widget.selected_rows = list(range(0, len(self.data.domain), 10)) + self.widget.set_selection() + return self.widget.selected_rows diff --git a/Orange/widgets/evaluate/tests/test_owconfusionmatrix.py b/Orange/widgets/evaluate/tests/test_owconfusionmatrix.py index 03573e90b1a..c3019926295 100644 --- a/Orange/widgets/evaluate/tests/test_owconfusionmatrix.py +++ b/Orange/widgets/evaluate/tests/test_owconfusionmatrix.py @@ -53,4 +53,4 @@ def _select_data(self): selected = [i for i, t in enumerate(zip( self.widget.results.actual, self.widget.results.predicted[0])) if t in indices] - self.selected_indices = self.widget.results.row_indices[selected] + return self.widget.results.row_indices[selected] diff --git a/Orange/widgets/tests/base.py b/Orange/widgets/tests/base.py index dcb01983a6d..c789fc01a75 100644 --- a/Orange/widgets/tests/base.py +++ b/Orange/widgets/tests/base.py @@ -503,7 +503,6 @@ class WidgetOutputsTestMixin: def init(self): self.data = Table("iris") self.same_input_output_domain = True - self.selected_indices = [] def test_outputs(self): self.send_signal(self.signal_name, self.signal_data) @@ -523,7 +522,7 @@ def test_outputs(self): self.assertEqual(0, np.sum([i[feature_name] for i in annotated])) # select data instances - self._select_data() + selected_indices = self._select_data() # check selected data output selected = self.get_output("Selected Data") @@ -532,7 +531,7 @@ def test_outputs(self): self.assertEqual(selected.domain == self.data.domain, self.same_input_output_domain) np.testing.assert_array_equal(selected.X[:, :n_attr], - self.data.X[self.selected_indices]) + self.data.X[selected_indices]) # check annotated data output annotated = self.get_output(ANNOTATED_DATA_SIGNAL_NAME) @@ -552,4 +551,4 @@ def _select_data(self): def _compare_selected_annotated_domains(self, selected, annotated): selected_vars = selected.domain.variables + selected.domain.metas annotated_vars = annotated.domain.variables + annotated.domain.metas - self.assertTrue(all((var in annotated_vars for var in selected_vars))) + self.assertLess(set(selected_vars), set(annotated_vars)) diff --git a/Orange/widgets/unsupervised/owhierarchicalclustering.py b/Orange/widgets/unsupervised/owhierarchicalclustering.py index c68e038a4d7..64d17e3ca70 100644 --- a/Orange/widgets/unsupervised/owhierarchicalclustering.py +++ b/Orange/widgets/unsupervised/owhierarchicalclustering.py @@ -1101,7 +1101,7 @@ def commit(self): if not selected_indices: self.send("Selected Data", None) - annotated_data = create_annotated_table(items, selected_indices) \ + annotated_data = create_annotated_table(items, []) \ if self.selection_method == 0 and self.matrix.axis else None self.send(ANNOTATED_DATA_SIGNAL_NAME, annotated_data) return @@ -1148,7 +1148,7 @@ def commit(self): selected_data = data[mask] if self.append_clusters: def remove_other_value(vars_): - vars_ = [var for var in vars_] + vars_ = list(vars_) clust_var = vars_[-1].copy() clust_var.values.pop() vars_[-1] = clust_var diff --git a/Orange/widgets/unsupervised/tests/test_owdistancemap.py b/Orange/widgets/unsupervised/tests/test_owdistancemap.py index e50a5454473..dc5c4394a2f 100644 --- a/Orange/widgets/unsupervised/tests/test_owdistancemap.py +++ b/Orange/widgets/unsupervised/tests/test_owdistancemap.py @@ -20,6 +20,7 @@ def setUp(self): def _select_data(self): random.seed(42) - self.selected_indices = random.sample(range(0, len(self.data)), 20) - self.widget._selection = self.selected_indices + selected_indices = random.sample(range(0, len(self.data)), 20) + self.widget._selection = selected_indices self.widget.commit() + return selected_indices diff --git a/Orange/widgets/unsupervised/tests/test_owhierarchicalclustering.py b/Orange/widgets/unsupervised/tests/test_owhierarchicalclustering.py index b439b2c2295..e32b5c2e261 100644 --- a/Orange/widgets/unsupervised/tests/test_owhierarchicalclustering.py +++ b/Orange/widgets/unsupervised/tests/test_owhierarchicalclustering.py @@ -25,16 +25,15 @@ def _select_data(self): items = self.widget.dendrogram._items cluster = items[sorted(list(items.keys()))[4]] self.widget.dendrogram.set_selected_items([cluster]) - self.selected_indices = [14, 15, 32, 33] + return [14, 15, 32, 33] def _compare_selected_annotated_domains(self, selected, annotated): - self.assertTrue(all((var in annotated.domain.variables - for var in selected.domain.variables))) + self.assertEqual(annotated.domain.variables, + selected.domain.variables) self.assertNotIn("Other", selected.domain.metas[0].values) self.assertIn("Other", annotated.domain.metas[0].values) - self.assertTrue( - all((var in [var.name for var in annotated.domain.metas] - for var in [var.name for var in selected.domain.metas]))) + self.assertLess(set(var.name for var in selected.domain.metas), + set(var.name for var in annotated.domain.metas)) def test_selection_box_output(self): """Check output if Selection method changes""" diff --git a/Orange/widgets/unsupervised/tests/test_owmds.py b/Orange/widgets/unsupervised/tests/test_owmds.py index baa9d629ce2..af34998ff14 100644 --- a/Orange/widgets/unsupervised/tests/test_owmds.py +++ b/Orange/widgets/unsupervised/tests/test_owmds.py @@ -25,4 +25,4 @@ def _select_data(self): points = random.sample(range(0, len(self.data)), 20) self.widget.select_indices(points) self.widget.commit() - self.selected_indices = sorted(points) + return sorted(points) diff --git a/Orange/widgets/visualize/owlinearprojection.py b/Orange/widgets/visualize/owlinearprojection.py index 2641cc57637..eef1240f897 100644 --- a/Orange/widgets/visualize/owlinearprojection.py +++ b/Orange/widgets/visualize/owlinearprojection.py @@ -31,6 +31,9 @@ from Orange.data.sql.table import SqlTable from Orange.widgets import widget, gui, settings from Orange.widgets.utils import itemmodels, colorpalette +from Orange.widgets.utils.annotated_data import ( + create_annotated_table, ANNOTATED_DATA_SIGNAL_NAME +) from .owscatterplotgraph import LegendItem, legend_anchor_pos from Orange.widgets.utils import classdensity from Orange.canvas import report @@ -238,7 +241,8 @@ class OWLinearProjection(widget.OWWidget): ("Data Subset", Table, "set_subset_data")] # #TODO: Allow for axes to be supplied from an external source. # ("Projection", numpy.ndarray, "set_axes"),] - outputs = [("Selected Data", Table)] + outputs = [("Selected Data", Table, widget.Default), + (ANNOTATED_DATA_SIGNAL_NAME, Table)] settingsHandler = settings.DomainContextHandler() @@ -1064,12 +1068,15 @@ def select_indices(self, indices, modifiers=Qt.NoModifier): def commit(self): subset = None + indices = None if self.data is not None and self._selection_mask is not None: indices = numpy.flatnonzero(self._selection_mask) if len(indices) > 0: subset = self.data[indices] self.send("Selected Data", subset) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.data, indices)) def send_report(self): self.report_plot(name="", plot=self.viewbox.getViewBox()) diff --git a/Orange/widgets/visualize/owmosaic.py b/Orange/widgets/visualize/owmosaic.py index aa3689e4cd2..c74fd5b4098 100644 --- a/Orange/widgets/visualize/owmosaic.py +++ b/Orange/widgets/visualize/owmosaic.py @@ -13,10 +13,12 @@ from Orange.preprocess import Discretize from Orange.preprocess.discretize import EqualFreq from Orange.statistics.distribution import get_distribution -from Orange.widgets import gui +from Orange.widgets import gui, widget from Orange.widgets.settings import ( Setting, DomainContextHandler, ContextSetting) from Orange.widgets.utils import to_html, get_variable_values_sorted +from Orange.widgets.utils.annotated_data import (create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME) from Orange.widgets.visualize.utils import ( CanvasText, CanvasRectangle, ViewWithPress) from Orange.widgets.widget import OWWidget, Default, Msg @@ -30,7 +32,8 @@ class OWMosaicDisplay(OWWidget): inputs = [("Data", Table, "set_data", Default), ("Data Subset", Table, "set_subset_data")] - outputs = [("Selected Data", Table)] + outputs = [("Selected Data", Table, widget.Default), + (ANNOTATED_DATA_SIGNAL_NAME, Table)] settingsHandler = DomainContextHandler() use_boxes = Setting(True) @@ -218,6 +221,8 @@ def select_area(self, index, ev): def send_selection(self): if not self.selection or self.data is None: self.send("Selected Data", None) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.data, [])) return filters = [] self.Warning.no_cont_selection_sql.clear() @@ -235,12 +240,13 @@ def send_selection(self): else: filters = filters[0] selection = filters(self.discrete_data) + idset = set(selection.ids) + sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] if self.discrete_data is not self.data: - idset = set(selection.ids) - sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] selection = self.data[sel_idx] self.send("Selected Data", selection) - + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.data, sel_idx)) def send_report(self): self.report_plot(self.canvas) diff --git a/Orange/widgets/visualize/owpythagorastree.py b/Orange/widgets/visualize/owpythagorastree.py index 9ca3d96a6eb..3f0ace5196f 100644 --- a/Orange/widgets/visualize/owpythagorastree.py +++ b/Orange/widgets/visualize/owpythagorastree.py @@ -35,8 +35,12 @@ ) from Orange.data.table import Table -from Orange.widgets import gui, settings +from Orange.widgets import gui, settings, widget from Orange.widgets.utils import to_html +from Orange.widgets.utils.annotated_data import ( + create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME +) from Orange.widgets.utils.colorpalette import ContinuousPaletteGenerator from Orange.widgets.visualize.pythagorastreeviewer import ( PythagorasTreeViewer, @@ -60,7 +64,8 @@ class OWPythagorasTree(OWWidget): priority = 1000 inputs = [('Tree', TreeModel, 'set_tree')] - outputs = [('Selected Data', Table)] + outputs = [('Selected Data', Table, widget.Default), + (ANNOTATED_DATA_SIGNAL_NAME, Table)] # Enable the save as feature graph_name = 'scene' @@ -228,6 +233,8 @@ def set_tree(self, model=None): # if hasattr(model, 'meta_depth_limit'): # self.depth_limit = model.meta_depth_limit # self.update_depth() + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.instances, None)) def clear(self): """Clear all relevant data from the widget.""" @@ -343,14 +350,16 @@ def commit(self): """Commit the selected data to output.""" if self.instances is None: self.send('Selected Data', None) + self.send(ANNOTATED_DATA_SIGNAL_NAME, None) return - # this is taken almost directly from the owclassificationtreegraph.py - items = filter(lambda x: isinstance(x, SquareGraphicsItem), - self.scene.selectedItems()) - + nodes = [i.tree_node.label for i in self.scene.selectedItems() + if isinstance(i, SquareGraphicsItem)] data = self.tree_adapter.get_instances_in_nodes( - self.clf_dataset, [item.tree_node.label for item in items]) + self.clf_dataset, nodes) self.send('Selected Data', data) + selected_indices = self.model.get_indices(nodes) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.instances, selected_indices)) def send_report(self): """Send report.""" diff --git a/Orange/widgets/visualize/owruleviewer.py b/Orange/widgets/visualize/owruleviewer.py index cec025dca0e..27a03c6f945 100644 --- a/Orange/widgets/visualize/owruleviewer.py +++ b/Orange/widgets/visualize/owruleviewer.py @@ -1,9 +1,5 @@ import numpy as np -from Orange.data import Table -from Orange.widgets import widget, gui, settings -from Orange.classification.rules import _RuleClassifier - from AnyQt.QtCore import ( Qt, QLineF, QSize, QAbstractTableModel, QModelIndex, QSortFilterProxyModel ) @@ -12,6 +8,12 @@ QItemDelegate, QHeaderView, QPushButton, QApplication ) +from Orange.data import Table +from Orange.classification.rules import _RuleClassifier +from Orange.widgets import widget, gui, settings +from Orange.widgets.utils.annotated_data import (create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME) + class OWRuleViewer(widget.OWWidget): name = "CN2 Rule Viewer" @@ -22,8 +24,9 @@ class OWRuleViewer(widget.OWWidget): inputs = [("Data", Table, 'set_data'), ("Classifier", _RuleClassifier, 'set_classifier')] - data_output_identifier = "Filtered data" - outputs = [(data_output_identifier, Table)] + data_output_identifier = "Selected Data" + outputs = [(data_output_identifier, Table, widget.Default), + (ANNOTATED_DATA_SIGNAL_NAME, Table)] compact_view = settings.Setting(False) @@ -140,6 +143,7 @@ def copy_to_clipboard(self): def commit(self): data_output = None self._save_selected(actual=True) + selected_indices = [] data = self.data or self.classifier and self.classifier.instances if (self.selected is not None and @@ -153,9 +157,13 @@ def commit(self): rule = self.classifier.rule_list[i] status &= rule.evaluate_data(data.X) - data_output = data.from_table_rows(data, status.nonzero()[0]) + selected_indices = status.nonzero()[0] + data_output = data.from_table_rows(data, selected_indices) \ + if len(selected_indices) else None self.send(OWRuleViewer.data_output_identifier, data_output) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(data, selected_indices)) def send_report(self): if self.classifier is not None: @@ -364,8 +372,18 @@ def paint(self, painter, option, index): painter.restore() if __name__ == "__main__": + from PyQt4.QtGui import QApplication + + from Orange.classification import CN2Learner + + data = Table("iris") + learner = CN2Learner() + model = learner(data) + model.instances = data + a = QApplication([]) ow = OWRuleViewer() + ow.set_classifier(model) ow.show() a.exec() diff --git a/Orange/widgets/visualize/owsieve.py b/Orange/widgets/visualize/owsieve.py index df3435cdcb1..bea3d20827c 100644 --- a/Orange/widgets/visualize/owsieve.py +++ b/Orange/widgets/visualize/owsieve.py @@ -12,9 +12,11 @@ from Orange.preprocess import Discretize from Orange.preprocess.discretize import EqualFreq from Orange.statistics.contingency import get_contingency -from Orange.widgets import gui +from Orange.widgets import gui, widget from Orange.widgets.settings import DomainContextHandler, ContextSetting from Orange.widgets.utils import to_html as to_html +from Orange.widgets.utils.annotated_data import (create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME) from Orange.widgets.utils.itemmodels import VariableListModel from Orange.widgets.visualize.utils import ( CanvasText, CanvasRectangle, ViewWithPress, VizRankDialogAttrPair) @@ -60,7 +62,8 @@ class OWSieveDiagram(OWWidget): inputs = [("Data", Table, "set_data", Default), ("Features", AttributeList, "set_input_features")] - outputs = [("Selection", Table)] + outputs = [("Selected Data", Table, widget.Default), + (ANNOTATED_DATA_SIGNAL_NAME, Table)] graph_name = "canvas" @@ -244,7 +247,9 @@ def update_selection(self): Filter and output the data. """ if self.areas is None or not self.selection: - self.send("Selection", None) + self.send("Selected Data", None) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.data, [])) return filts = [] @@ -267,11 +272,13 @@ def update_selection(self): else: filts = filter.Values(filts, conjunction=False) selection = filts(self.discrete_data) + idset = set(selection.ids) + sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] if self.discrete_data is not self.data: - idset = set(selection.ids) - sel_idx = [i for i, id in enumerate(self.data.ids) if id in idset] selection = self.data[sel_idx] - self.send("Selection", selection) + self.send("Selected Data", selection) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(self.data, sel_idx)) def update_graph(self): # Function uses weird names like r, g, b, but it does it with utmost diff --git a/Orange/widgets/visualize/owsilhouetteplot.py b/Orange/widgets/visualize/owsilhouetteplot.py index a2344660a14..31b2c667856 100644 --- a/Orange/widgets/visualize/owsilhouetteplot.py +++ b/Orange/widgets/visualize/owsilhouetteplot.py @@ -24,6 +24,8 @@ from Orange.widgets import widget, gui, settings from Orange.widgets.utils import itemmodels +from Orange.widgets.utils.annotated_data import (create_annotated_table, + ANNOTATED_DATA_SIGNAL_NAME) from Orange.widgets.utils.sql import check_sql_input from Orange.widgets.unsupervised.owhierarchicalclustering import \ WrapperLayoutItem @@ -40,7 +42,7 @@ class OWSilhouettePlot(widget.OWWidget): inputs = [("Data", Orange.data.Table, "set_data")] outputs = [("Selected Data", Orange.data.Table, widget.Default), - ("Other Data", Orange.data.Table)] + (ANNOTATED_DATA_SIGNAL_NAME, Orange.data.Table)] replaces = [ "orangecontrib.prototypes.widgets.owsilhouetteplot.OWSilhouettePlot", @@ -311,7 +313,7 @@ def commit(self): """ Commit/send the current selection to the output. """ - selected = other = None + selected = indices = data = None if self.data is not None: selectedmask = numpy.full(len(self.data), False, dtype=bool) if self._silplot is not None: @@ -327,25 +329,24 @@ def commit(self): self.data.domain.attributes, self.data.domain.class_vars, self.data.domain.metas + (silhouette_var, )) + data = self.data.from_table( + domain, self.data) else: domain = self.data.domain + data = self.data if numpy.count_nonzero(selectedmask): selected = self.data.from_table( domain, self.data, numpy.flatnonzero(selectedmask)) - if numpy.count_nonzero(~selectedmask): - other = self.data.from_table( - domain, self.data, numpy.flatnonzero(~selectedmask)) - if self.add_scores: if selected is not None: selected[:, silhouette_var] = numpy.c_[scores[selectedmask]] - if other is not None: - other[:, silhouette_var] = numpy.c_[scores[~selectedmask]] + data[:, silhouette_var] = numpy.c_[scores] self.send("Selected Data", selected) - self.send("Other Data", other) + self.send(ANNOTATED_DATA_SIGNAL_NAME, + create_annotated_table(data, indices)) def send_report(self): if not len(self.cluster_var_model): diff --git a/Orange/widgets/visualize/owtreeviewer.py b/Orange/widgets/visualize/owtreeviewer.py index 6afa1fa0bf7..c406dff18d3 100644 --- a/Orange/widgets/visualize/owtreeviewer.py +++ b/Orange/widgets/visualize/owtreeviewer.py @@ -274,7 +274,7 @@ def ctree(self, model=None): self.setup_scene() self.send("Selected Data", None) self.send(ANNOTATED_DATA_SIGNAL_NAME, - create_annotated_table(self.dataset, None)) + create_annotated_table(self.dataset, [])) def walkcreate(self, node_inst, parent=None): """Create a structure of tree nodes from the given model""" diff --git a/Orange/widgets/visualize/tests/test_owheatmap.py b/Orange/widgets/visualize/tests/test_owheatmap.py index dbe96c5915c..6db0a0330ac 100644 --- a/Orange/widgets/visualize/tests/test_owheatmap.py +++ b/Orange/widgets/visualize/tests/test_owheatmap.py @@ -68,6 +68,7 @@ def test_settings_changed(self): self.assertIsNone(self.get_output("Selected Data")) def _select_data(self): - self.selected_indices = list(range(10, 31)) - self.widget.selection_manager.select_rows(self.selected_indices) + selected_indices = list(range(10, 31)) + self.widget.selection_manager.select_rows(selected_indices) self.widget.on_selection_finished() + return selected_indices diff --git a/Orange/widgets/visualize/tests/test_owlinearprojection.py b/Orange/widgets/visualize/tests/test_owlinearprojection.py new file mode 100644 index 00000000000..adfac960618 --- /dev/null +++ b/Orange/widgets/visualize/tests/test_owlinearprojection.py @@ -0,0 +1,25 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import random + +from Orange.widgets.visualize.owlinearprojection import OWLinearProjection +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin + + +class TestOWLinearProjection(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + + def setUp(self): + self.widget = self.create_widget(OWLinearProjection) + + def _select_data(self): + random.seed(42) + points = random.sample(range(0, len(self.data)), 20) + self.widget.select_indices(points) + return sorted(points) diff --git a/Orange/widgets/visualize/tests/test_owmosaic.py b/Orange/widgets/visualize/tests/test_owmosaic.py new file mode 100644 index 00000000000..930b86bf2bc --- /dev/null +++ b/Orange/widgets/visualize/tests/test_owmosaic.py @@ -0,0 +1,26 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +from PyQt4.QtCore import QEvent, QPoint, Qt +from PyQt4.QtGui import QMouseEvent + +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin +from Orange.widgets.visualize.owmosaic import OWMosaicDisplay + + +class TestOWMosaicDisplay(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + + def setUp(self): + self.widget = self.create_widget(OWMosaicDisplay) + + def _select_data(self): + self.widget.select_area(1, QMouseEvent( + QEvent.MouseButtonPress, QPoint(), Qt.LeftButton, + Qt.LeftButton, Qt.KeyboardModifiers())) + return [2, 3, 9, 23, 29, 30, 34, 35, 37, 42, 47, 49] diff --git a/Orange/widgets/visualize/tests/test_owpythagorastree.py b/Orange/widgets/visualize/tests/test_owpythagorastree.py index 555ee70d0ed..40ad9c71c37 100644 --- a/Orange/widgets/visualize/tests/test_owpythagorastree.py +++ b/Orange/widgets/visualize/tests/test_owpythagorastree.py @@ -2,7 +2,11 @@ import math import unittest +from Orange.classification import TreeLearner +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin +from Orange.widgets.visualize.owpythagorastree import OWPythagorasTree from Orange.widgets.visualize.pythagorastreeviewer import ( + SquareGraphicsItem, PythagorasTree, Point, Square, @@ -73,3 +77,26 @@ def test_compute_center_with_complex_square_angle_with_base_angle(self): expected_point = Point(1.43, 3.98) self.assertAlmostEqual(point.x, expected_point.x, places=1) self.assertAlmostEqual(point.y, expected_point.y, places=1) + + +class TestOWPythagorasTree(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + tree = TreeLearner() + cls.model = tree(cls.data) + cls.model.instances = cls.data + + cls.signal_name = "Tree" + cls.signal_data = cls.model + + def setUp(self): + self.widget = self.create_widget(OWPythagorasTree) + + def _select_data(self): + item = [i for i in self.widget.scene.items() if + isinstance(i, SquareGraphicsItem)][3] + item.setSelected(True) + return item.tree_node.label.subset diff --git a/Orange/widgets/visualize/tests/test_owruleviewer.py b/Orange/widgets/visualize/tests/test_owruleviewer.py index 0c3709e1f15..a4121a159a3 100644 --- a/Orange/widgets/visualize/tests/test_owruleviewer.py +++ b/Orange/widgets/visualize/tests/test_owruleviewer.py @@ -4,19 +4,29 @@ from AnyQt.QtWidgets import QApplication from Orange.data import Table -from Orange.widgets.tests.base import WidgetTest +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin from Orange.classification import CN2Learner from Orange.widgets.visualize.owruleviewer import OWRuleViewer -class TestOWRuleViewer(WidgetTest): - def setUp(self): - self.titanic = Table('titanic') - self.learner = CN2Learner() - self.classifier = self.learner(self.titanic) +class TestOWRuleViewer(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.titanic = Table('titanic') + cls.learner = CN2Learner() + cls.classifier = cls.learner(cls.titanic) # CN2Learner does not add `instances` attribute to the model, but # the Rules widget does. We simulate the model we get from the widget. - self.classifier.instances = self.titanic + cls.classifier.instances = cls.titanic + + cls.signal_name = "Classifier" + cls.signal_data = cls.classifier + cls.data = cls.titanic + + def setUp(self): self.widget = self.create_widget(OWRuleViewer) def test_set_data(self): @@ -139,3 +149,9 @@ def test_selection_compact_view(self): # test that the selection persists self.assertEqual(temp, self.widget.selected) + + def _select_data(self): + selection_model = self.widget.view.selectionModel() + selection_model.select(self.widget.proxy_model.index(2, 0), + selection_model.Select | selection_model.Rows) + return list(range(586, 597)) diff --git a/Orange/widgets/visualize/tests/test_owscatterplot.py b/Orange/widgets/visualize/tests/test_owscatterplot.py index dac1c7423f0..08c59933b3e 100644 --- a/Orange/widgets/visualize/tests/test_owscatterplot.py +++ b/Orange/widgets/visualize/tests/test_owscatterplot.py @@ -80,4 +80,4 @@ def test_optional_combos(self): def _select_data(self): self.widget.graph.select_by_rectangle(QRectF(4, 3, 3, 1)) - self.selected_indices = self.widget.graph.get_selection() + return self.widget.graph.get_selection() diff --git a/Orange/widgets/visualize/tests/test_owsieve.py b/Orange/widgets/visualize/tests/test_owsieve.py new file mode 100644 index 00000000000..67b54d17a3b --- /dev/null +++ b/Orange/widgets/visualize/tests/test_owsieve.py @@ -0,0 +1,27 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +from PyQt4.QtCore import QEvent, QPoint, Qt +from PyQt4.QtGui import QMouseEvent + +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin +from Orange.widgets.visualize.owsieve import OWSieveDiagram + + +class TestOWSieveDiagram(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + + def setUp(self): + self.widget = self.create_widget(OWSieveDiagram) + + def _select_data(self): + area = self.widget.areas[0] + self.widget.select_area(area, QMouseEvent( + QEvent.MouseButtonPress, QPoint(), Qt.LeftButton, + Qt.LeftButton, Qt.KeyboardModifiers())) + return [0, 4, 6, 7, 11, 17, 19, 21, 22, 24, 26, 39, 40, 43, 44, 46] diff --git a/Orange/widgets/visualize/tests/test_owsilhouetteplot.py b/Orange/widgets/visualize/tests/test_owsilhouetteplot.py new file mode 100644 index 00000000000..7d3afeff17c --- /dev/null +++ b/Orange/widgets/visualize/tests/test_owsilhouetteplot.py @@ -0,0 +1,41 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +import random + +import numpy as np + +from Orange.widgets.utils.annotated_data import ANNOTATED_DATA_SIGNAL_NAME +from Orange.widgets.visualize.owsilhouetteplot import OWSilhouettePlot +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin + + +class TestOWSilhouettePlot(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + + def setUp(self): + self.widget = self.create_widget(OWSilhouettePlot, + stored_settings={"auto_commit": True}) + + def test_outputs_add_scores(self): + # check output when appending scores + self.send_signal("Data", self.data) + self.widget.controlledAttributes["add_scores"][0].control.setChecked(1) + selected_indices = self._select_data() + name = "Silhouette ({})".format(self.data.domain.class_var.name) + selected = self.get_output("Selected Data") + annotated = self.get_output(ANNOTATED_DATA_SIGNAL_NAME) + self.assertEqual(name, selected.domain.metas[0].name) + self.assertEqual(name, annotated.domain.metas[0].name) + np.testing.assert_array_equal(selected.X, self.data.X[selected_indices]) + + def _select_data(self): + random.seed(42) + points = random.sample(range(0, len(self.data)), 20) + self.widget._silplot.setSelection(points) + return sorted(points) diff --git a/Orange/widgets/visualize/tests/test_owtreegraph.py b/Orange/widgets/visualize/tests/test_owtreegraph.py index 2d7ee75c61f..406ef23162a 100644 --- a/Orange/widgets/visualize/tests/test_owtreegraph.py +++ b/Orange/widgets/visualize/tests/test_owtreegraph.py @@ -25,4 +25,4 @@ def setUp(self): def _select_data(self): node = self.widget.scene.nodes()[0] node.setSelected(True) - self.selected_indices = self.model.get_indices([node.node_inst]) + return self.model.get_indices([node.node_inst])