diff --git a/Orange/widgets/unsupervised/owpca.py b/Orange/widgets/unsupervised/owpca.py index 29611146fb2..9cc83323068 100644 --- a/Orange/widgets/unsupervised/owpca.py +++ b/Orange/widgets/unsupervised/owpca.py @@ -5,13 +5,15 @@ from AnyQt.QtCore import Qt from orangewidget.report import bool_str +from orangewidget.settings import Setting from Orange.data import Table, Domain, StringVariable, ContinuousVariable from Orange.data.util import get_unique_names from Orange.data.sql.table import SqlTable, AUTO_DL_LIMIT from Orange.preprocess import preprocess from Orange.projection import PCA -from Orange.widgets import widget, gui, settings +from Orange.widgets import widget, gui +from Orange.widgets.utils.annotated_data import add_columns from Orange.widgets.utils.concurrent import ConcurrentWidgetMixin from Orange.widgets.utils.slidergraph import SliderGraph from Orange.widgets.utils.widgetpreview import WidgetPreview @@ -38,12 +40,12 @@ class Outputs: components = Output("Components", Table) pca = Output("PCA", PCA, dynamic=False) - ncomponents = settings.Setting(2) - variance_covered = settings.Setting(100) - auto_commit = settings.Setting(True) - normalize = settings.Setting(True) - maxp = settings.Setting(20) - axis_labels = settings.Setting(10) + ncomponents = Setting(2) + variance_covered = Setting(100) + auto_commit = Setting(True) + normalize = Setting(True) + maxp = Setting(20) + axis_labels = Setting(10) graph_name = "plot.plotItem" # QGraphicsView (pg.PlotWidget -> SliderGraph) @@ -222,8 +224,7 @@ def _setup_plot(self): self._update_axis() def _on_cut_changed(self, components): - if components == self.ncomponents \ - or self.ncomponents == 0: + if self.ncomponents in (components, 0): return self.ncomponents = components @@ -333,9 +334,9 @@ def commit(self): proposed = [a.name for a in self._pca.orig_domain.attributes] meta_name = get_unique_names(proposed, 'components') meta_vars = [StringVariable(name=meta_name)] - metas = numpy.array([['PC{}'.format(i + 1) - for i in range(self.ncomponents)]], - dtype=object).T + metas = numpy.array( + [[f"PC{i + 1}"for i in range(self.ncomponents)]], dtype=object + ).T if self._variance_ratio is not None: variance_name = get_unique_names(proposed, "variance") meta_vars.append(ContinuousVariable(variance_name)) @@ -351,14 +352,8 @@ def commit(self): metas=metas) components.name = 'components' - data_dom = Domain( - self.data.domain.attributes, - self.data.domain.class_vars, - self.data.domain.metas + domain.attributes) - data = Table.from_numpy( - data_dom, self.data.X, self.data.Y, - numpy.hstack((self.data.metas, transformed.X)), - ids=self.data.ids) + data_dom = add_columns(self.data.domain, metas=domain.attributes) + data = self.data.transform(data_dom) self.Outputs.transformed_data.send(transformed) self.Outputs.components.send(components) @@ -371,7 +366,7 @@ def send_report(self): self.report_items(( ("Normalize data", bool_str(self.normalize)), ("Selected components", self.ncomponents), - ("Explained variance", "{:.3f} %".format(self.variance_covered)) + ("Explained variance", f"{self.variance_covered:.3f} %") )) self.report_plot() diff --git a/Orange/widgets/unsupervised/tests/test_owpca.py b/Orange/widgets/unsupervised/tests/test_owpca.py index 993871980a0..afb2ab41fc9 100644 --- a/Orange/widgets/unsupervised/tests/test_owpca.py +++ b/Orange/widgets/unsupervised/tests/test_owpca.py @@ -4,6 +4,8 @@ from unittest.mock import patch, Mock import numpy as np +from sklearn.utils import check_random_state +from sklearn.utils.extmath import svd_flip from Orange.data import Table, Domain, ContinuousVariable, TimeVariable from Orange.preprocess import preprocess @@ -11,8 +13,6 @@ from Orange.widgets.tests.utils import table_dense_sparse, possible_duplicate_table from Orange.widgets.unsupervised.owpca import OWPCA from Orange.tests import test_filename -from sklearn.utils import check_random_state -from sklearn.utils.extmath import svd_flip class TestOWPCA(WidgetTest): @@ -63,19 +63,19 @@ def test_limit_components(self): self.widget._setup_plot() # pylint: disable=protected-access def test_migrate_settings_limits_components(self): - settings = dict(ncomponents=10) + settings = {"ncomponents": 10} OWPCA.migrate_settings(settings, 0) self.assertEqual(settings['ncomponents'], 10) - settings = dict(ncomponents=101) + settings = {"ncomponents": 101} OWPCA.migrate_settings(settings, 0) self.assertEqual(settings['ncomponents'], 100) def test_migrate_settings_changes_variance_covered_to_int(self): - settings = dict(variance_covered=17.5) + settings = {"variance_covered": 17.5} OWPCA.migrate_settings(settings, 0) self.assertEqual(settings["variance_covered"], 17) - settings = dict(variance_covered=float('nan')) + settings = {"variance_covered": float('nan')} OWPCA.migrate_settings(settings, 0) self.assertEqual(settings["variance_covered"], 100) @@ -277,6 +277,21 @@ def test_output_data(self): output = self.get_output(widget.Outputs.data) self.assertIsNone(output) + def test_table_subclass(self): + """ + When input table is instance of Table's subclass (e.g. Corpus) resulting + tables should also be an instance subclasses + """ + class TableSub(Table): # pylint: disable=abstract-method + pass + + table_subclass = TableSub(self.iris) + self.send_signal(self.widget.Inputs.data, table_subclass) + data_out = self.get_output(self.widget.Outputs.data) + trans_data_out = self.get_output(self.widget.Outputs.transformed_data) + self.assertIsInstance(data_out, TableSub) + self.assertIsInstance(trans_data_out, TableSub) + if __name__ == "__main__": unittest.main()