We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PCA: retain all data (Unification of embedding methods )
**Issue:** PCA discards the original attributes and replaces them with PCs. Often (e.g. in scOrange), it is desirable to use the original features: annotate PCA plots,  compute differentially-occurring features in different PCA regions, etc. 

**Proposed solution**: Place PCs in meta attributes and rename output to *Data*. 


This would be consistent to *t-SNE* and *MDS*. The user could use *Select columns* to restore current behaviour. This is substantially easier (number of PCs is typically small) than merging original attributes with principal components, as it's possible in the current version. 
 
Such an improvement would also play nice with the new widget *Apply domain*, which enables projecting data to existing PCs and/or attributes. 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Orange/widgets/unsupervised/owpca.py`
Content:
```
1 import numbers
2 
3 import numpy
4 from AnyQt.QtWidgets import QFormLayout
5 from AnyQt.QtCore import Qt
6 
7 from Orange.data import Table, Domain, StringVariable, ContinuousVariable
8 from Orange.data.sql.table import SqlTable, AUTO_DL_LIMIT
9 from Orange.preprocess import preprocess
10 from Orange.projection import PCA
11 from Orange.widgets import widget, gui, settings
12 from Orange.widgets.utils.slidergraph import SliderGraph
13 from Orange.widgets.utils.widgetpreview import WidgetPreview
14 from Orange.widgets.widget import Input, Output
15 
16 
17 # Maximum number of PCA components that we can set in the widget
18 MAX_COMPONENTS = 100
19 LINE_NAMES = ["component variance", "cumulative variance"]
20 
21 
22 class OWPCA(widget.OWWidget):
23     name = "PCA"
24     description = "Principal component analysis with a scree-diagram."
25     icon = "icons/PCA.svg"
26     priority = 3050
27     keywords = ["principal component analysis", "linear transformation"]
28 
29     class Inputs:
30         data = Input("Data", Table)
31 
32     class Outputs:
33         transformed_data = Output("Transformed Data", Table, replaces=["Transformed data"])
34         components = Output("Components", Table)
35         pca = Output("PCA", PCA, dynamic=False)
36 
37     settingsHandler = settings.DomainContextHandler()
38 
39     ncomponents = settings.Setting(2)
40     variance_covered = settings.Setting(100)
41     auto_commit = settings.Setting(True)
42     normalize = settings.ContextSetting(True)
43     maxp = settings.Setting(20)
44     axis_labels = settings.Setting(10)
45 
46     graph_name = "plot.plotItem"
47 
48     class Warning(widget.OWWidget.Warning):
49         trivial_components = widget.Msg(
50             "All components of the PCA are trivial (explain 0 variance). "
51             "Input data is constant (or near constant).")
52 
53     class Error(widget.OWWidget.Error):
54         no_features = widget.Msg("At least 1 feature is required")
55         no_instances = widget.Msg("At least 1 data instance is required")
56 
57     def __init__(self):
58         super().__init__()
59         self.data = None
60 
61         self._pca = None
62         self._transformed = None
63         self._variance_ratio = None
64         self._cumulative = None
65         self._init_projector()
66 
67         # Components Selection
68         box = gui.vBox(self.controlArea, "Components Selection")
69         form = QFormLayout()
70         box.layout().addLayout(form)
71 
72         self.components_spin = gui.spin(
73             box, self, "ncomponents", 1, MAX_COMPONENTS,
74             callback=self._update_selection_component_spin,
75             keyboardTracking=False
76         )
77         self.components_spin.setSpecialValueText("All")
78 
79         self.variance_spin = gui.spin(
80             box, self, "variance_covered", 1, 100,
81             callback=self._update_selection_variance_spin,
82             keyboardTracking=False
83         )
84         self.variance_spin.setSuffix("%")
85 
86         form.addRow("Components:", self.components_spin)
87         form.addRow("Explained variance:", self.variance_spin)
88 
89         # Options
90         self.options_box = gui.vBox(self.controlArea, "Options")
91         self.normalize_box = gui.checkBox(
92             self.options_box, self, "normalize",
93             "Normalize variables", callback=self._update_normalize
94         )
95 
96         self.maxp_spin = gui.spin(
97             self.options_box, self, "maxp", 1, MAX_COMPONENTS,
98             label="Show only first", callback=self._setup_plot,
99             keyboardTracking=False
100         )
101 
102         self.controlArea.layout().addStretch()
103 
104         gui.auto_apply(self.controlArea, self, "auto_commit")
105 
106         self.plot = SliderGraph(
107             "Principal Components", "Proportion of variance",
108             self._on_cut_changed)
109 
110         self.mainArea.layout().addWidget(self.plot)
111         self._update_normalize()
112 
113     @Inputs.data
114     def set_data(self, data):
115         self.closeContext()
116         self.clear_messages()
117         self.clear()
118         self.information()
119         self.data = None
120         if isinstance(data, SqlTable):
121             if data.approx_len() < AUTO_DL_LIMIT:
122                 data = Table(data)
123             else:
124                 self.information("Data has been sampled")
125                 data_sample = data.sample_time(1, no_cache=True)
126                 data_sample.download_data(2000, partial=True)
127                 data = Table(data_sample)
128         if isinstance(data, Table):
129             if not data.domain.attributes:
130                 self.Error.no_features()
131                 self.clear_outputs()
132                 return
133             if not data:
134                 self.Error.no_instances()
135                 self.clear_outputs()
136                 return
137 
138         self.openContext(data)
139         self._init_projector()
140 
141         self.data = data
142         self.fit()
143 
144     def fit(self):
145         self.clear()
146         self.Warning.trivial_components.clear()
147         if self.data is None:
148             return
149 
150         data = self.data
151 
152         if self.normalize:
153             self._pca_projector.preprocessors = \
154                 self._pca_preprocessors + [preprocess.Normalize(center=False)]
155         else:
156             self._pca_projector.preprocessors = self._pca_preprocessors
157 
158         if not isinstance(data, SqlTable):
159             pca = self._pca_projector(data)
160             variance_ratio = pca.explained_variance_ratio_
161             cumulative = numpy.cumsum(variance_ratio)
162 
163             if numpy.isfinite(cumulative[-1]):
164                 self.components_spin.setRange(0, len(cumulative))
165                 self._pca = pca
166                 self._variance_ratio = variance_ratio
167                 self._cumulative = cumulative
168                 self._setup_plot()
169             else:
170                 self.Warning.trivial_components()
171 
172             self.unconditional_commit()
173 
174     def clear(self):
175         self._pca = None
176         self._transformed = None
177         self._variance_ratio = None
178         self._cumulative = None
179         self.plot.clear_plot()
180 
181     def clear_outputs(self):
182         self.Outputs.transformed_data.send(None)
183         self.Outputs.components.send(None)
184         self.Outputs.pca.send(self._pca_projector)
185 
186     def _setup_plot(self):
187         if self._pca is None:
188             self.plot.clear_plot()
189             return
190 
191         explained_ratio = self._variance_ratio
192         explained = self._cumulative
193         cutpos = self._nselected_components()
194         p = min(len(self._variance_ratio), self.maxp)
195 
196         self.plot.update(
197             numpy.arange(1, p+1), [explained_ratio[:p], explained[:p]],
198             [Qt.red, Qt.darkYellow], cutpoint_x=cutpos, names=LINE_NAMES)
199 
200         self._update_axis()
201 
202     def _on_cut_changed(self, components):
203         if components == self.ncomponents \
204                 or self.ncomponents == 0 \
205                 or self._pca is not None \
206                 and components == len(self._variance_ratio):
207             return
208 
209         self.ncomponents = components
210         if self._pca is not None:
211             var = self._cumulative[components - 1]
212             if numpy.isfinite(var):
213                 self.variance_covered = int(var * 100)
214 
215         self._invalidate_selection()
216 
217     def _update_selection_component_spin(self):
218         # cut changed by "ncomponents" spin.
219         if self._pca is None:
220             self._invalidate_selection()
221             return
222 
223         if self.ncomponents == 0:
224             # Special "All" value
225             cut = len(self._variance_ratio)
226         else:
227             cut = self.ncomponents
228 
229         var = self._cumulative[cut - 1]
230         if numpy.isfinite(var):
231             self.variance_covered = int(var * 100)
232 
233         self.plot.set_cut_point(cut)
234         self._invalidate_selection()
235 
236     def _update_selection_variance_spin(self):
237         # cut changed by "max variance" spin.
238         if self._pca is None:
239             return
240 
241         cut = numpy.searchsorted(self._cumulative,
242                                  self.variance_covered / 100.0) + 1
243         cut = min(cut, len(self._cumulative))
244         self.ncomponents = cut
245         self.plot.set_cut_point(cut)
246         self._invalidate_selection()
247 
248     def _update_normalize(self):
249         self.fit()
250         if self.data is None:
251             self._invalidate_selection()
252 
253     def _init_projector(self):
254         self._pca_projector = PCA(n_components=MAX_COMPONENTS, random_state=0)
255         self._pca_projector.component = self.ncomponents
256         self._pca_preprocessors = PCA.preprocessors
257 
258     def _nselected_components(self):
259         """Return the number of selected components."""
260         if self._pca is None:
261             return 0
262 
263         if self.ncomponents == 0:
264             # Special "All" value
265             max_comp = len(self._variance_ratio)
266         else:
267             max_comp = self.ncomponents
268 
269         var_max = self._cumulative[max_comp - 1]
270         if var_max != numpy.floor(self.variance_covered / 100.0):
271             cut = max_comp
272             assert numpy.isfinite(var_max)
273             self.variance_covered = int(var_max * 100)
274         else:
275             self.ncomponents = cut = numpy.searchsorted(
276                 self._cumulative, self.variance_covered / 100.0) + 1
277         return cut
278 
279     def _invalidate_selection(self):
280         self.commit()
281 
282     def _update_axis(self):
283         p = min(len(self._variance_ratio), self.maxp)
284         axis = self.plot.getAxis("bottom")
285         d = max((p-1)//(self.axis_labels-1), 1)
286         axis.setTicks([[(i, str(i)) for i in range(1, p + 1, d)]])
287 
288     def commit(self):
289         transformed = components = None
290         if self._pca is not None:
291             if self._transformed is None:
292                 # Compute the full transform (MAX_COMPONENTS components) once.
293                 self._transformed = self._pca(self.data)
294             transformed = self._transformed
295 
296             domain = Domain(
297                 transformed.domain.attributes[:self.ncomponents],
298                 self.data.domain.class_vars,
299                 self.data.domain.metas
300             )
301             transformed = transformed.from_table(domain, transformed)
302             # prevent caching new features by defining compute_value
303             dom = Domain(
304                 [ContinuousVariable(a.name, compute_value=lambda _: None)
305                  for a in self._pca.orig_domain.attributes],
306                 metas=[StringVariable(name='component')])
307             metas = numpy.array([['PC{}'.format(i + 1)
308                                   for i in range(self.ncomponents)]],
309                                 dtype=object).T
310             components = Table(dom, self._pca.components_[:self.ncomponents],
311                                metas=metas)
312             components.name = 'components'
313 
314         self._pca_projector.component = self.ncomponents
315         self.Outputs.transformed_data.send(transformed)
316         self.Outputs.components.send(components)
317         self.Outputs.pca.send(self._pca_projector)
318 
319     def send_report(self):
320         if self.data is None:
321             return
322         self.report_items((
323             ("Normalize data", str(self.normalize)),
324             ("Selected components", self.ncomponents),
325             ("Explained variance", "{:.3f} %".format(self.variance_covered))
326         ))
327         self.report_plot()
328 
329     @classmethod
330     def migrate_settings(cls, settings, version):
331         if "variance_covered" in settings:
332             # Due to the error in gh-1896 the variance_covered was persisted
333             # as a NaN value, causing a TypeError in the widgets `__init__`.
334             vc = settings["variance_covered"]
335             if isinstance(vc, numbers.Real):
336                 if numpy.isfinite(vc):
337                     vc = int(vc)
338                 else:
339                     vc = 100
340                 settings["variance_covered"] = vc
341         if settings.get("ncomponents", 0) > MAX_COMPONENTS:
342             settings["ncomponents"] = MAX_COMPONENTS
343 
344         # Remove old `decomposition_idx` when SVD was still included
345         settings.pop("decomposition_idx", None)
346 
347         # Remove RemotePCA settings
348         settings.pop("batch_size", None)
349         settings.pop("address", None)
350         settings.pop("auto_update", None)
351 
352 
353 if __name__ == "__main__":  # pragma: no cover
354     WidgetPreview(OWPCA).run(Table("housing"))
355
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Orange/widgets/unsupervised/owpca.py b/Orange/widgets/unsupervised/owpca.py
--- a/Orange/widgets/unsupervised/owpca.py
+++ b/Orange/widgets/unsupervised/owpca.py
@@ -31,6 +31,7 @@
 
     class Outputs:
         transformed_data = Output("Transformed Data", Table, replaces=["Transformed data"])
+        data = Output("Data", Table, default=True)
         components = Output("Components", Table)
         pca = Output("PCA", PCA, dynamic=False)
 
@@ -180,6 +181,7 @@
 
     def clear_outputs(self):
         self.Outputs.transformed_data.send(None)
+        self.Outputs.data.send(None)
         self.Outputs.components.send(None)
         self.Outputs.pca.send(self._pca_projector)
 
@@ -286,7 +288,7 @@
         axis.setTicks([[(i, str(i)) for i in range(1, p + 1, d)]])
 
     def commit(self):
-        transformed = components = None
+        transformed = data = components = None
         if self._pca is not None:
             if self._transformed is None:
                 # Compute the full transform (MAX_COMPONENTS components) once.
@@ -311,9 +313,18 @@
                                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)))
+
         self._pca_projector.component = self.ncomponents
         self.Outputs.transformed_data.send(transformed)
         self.Outputs.components.send(components)
+        self.Outputs.data.send(data)
         self.Outputs.pca.send(self._pca_projector)
 
     def send_report(self):

{"golden_diff": "diff --git a/Orange/widgets/unsupervised/owpca.py b/Orange/widgets/unsupervised/owpca.py\n--- a/Orange/widgets/unsupervised/owpca.py\n+++ b/Orange/widgets/unsupervised/owpca.py\n@@ -31,6 +31,7 @@\n \n     class Outputs:\n         transformed_data = Output(\"Transformed Data\", Table, replaces=[\"Transformed data\"])\n+        data = Output(\"Data\", Table, default=True)\n         components = Output(\"Components\", Table)\n         pca = Output(\"PCA\", PCA, dynamic=False)\n \n@@ -180,6 +181,7 @@\n \n     def clear_outputs(self):\n         self.Outputs.transformed_data.send(None)\n+        self.Outputs.data.send(None)\n         self.Outputs.components.send(None)\n         self.Outputs.pca.send(self._pca_projector)\n \n@@ -286,7 +288,7 @@\n         axis.setTicks([[(i, str(i)) for i in range(1, p + 1, d)]])\n \n     def commit(self):\n-        transformed = components = None\n+        transformed = data = components = None\n         if self._pca is not None:\n             if self._transformed is None:\n                 # Compute the full transform (MAX_COMPONENTS components) once.\n@@ -311,9 +313,18 @@\n                                metas=metas)\n             components.name = 'components'\n \n+            data_dom = Domain(\n+                self.data.domain.attributes,\n+                self.data.domain.class_vars,\n+                self.data.domain.metas + domain.attributes)\n+            data = Table.from_numpy(\n+                data_dom, self.data.X, self.data.Y,\n+                numpy.hstack((self.data.metas, transformed.X)))\n+\n         self._pca_projector.component = self.ncomponents\n         self.Outputs.transformed_data.send(transformed)\n         self.Outputs.components.send(components)\n+        self.Outputs.data.send(data)\n         self.Outputs.pca.send(self._pca_projector)\n \n     def send_report(self):\n", "issue": "PCA: retain all data (Unification of embedding methods )\n**Issue:** PCA discards the original attributes and replaces them with PCs. Often (e.g. in scOrange), it is desirable to use the original features: annotate PCA plots,  compute differentially-occurring features in different PCA regions, etc. \r\n\r\n**Proposed solution**: Place PCs in meta attributes and rename output to *Data*. \r\n\r\n\r\nThis would be consistent to *t-SNE* and *MDS*. The user could use *Select columns* to restore current behaviour. This is substantially easier (number of PCs is typically small) than merging original attributes with principal components, as it's possible in the current version. \r\n \r\nSuch an improvement would also play nice with the new widget *Apply domain*, which enables projecting data to existing PCs and/or attributes. \r\n\n", "before_files": [{"content": "import numbers\n\nimport numpy\nfrom AnyQt.QtWidgets import QFormLayout\nfrom AnyQt.QtCore import Qt\n\nfrom Orange.data import Table, Domain, StringVariable, ContinuousVariable\nfrom Orange.data.sql.table import SqlTable, AUTO_DL_LIMIT\nfrom Orange.preprocess import preprocess\nfrom Orange.projection import PCA\nfrom Orange.widgets import widget, gui, settings\nfrom Orange.widgets.utils.slidergraph import SliderGraph\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.widget import Input, Output\n\n\n# Maximum number of PCA components that we can set in the widget\nMAX_COMPONENTS = 100\nLINE_NAMES = [\"component variance\", \"cumulative variance\"]\n\n\nclass OWPCA(widget.OWWidget):\n    name = \"PCA\"\n    description = \"Principal component analysis with a scree-diagram.\"\n    icon = \"icons/PCA.svg\"\n    priority = 3050\n    keywords = [\"principal component analysis\", \"linear transformation\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n\n    class Outputs:\n        transformed_data = Output(\"Transformed Data\", Table, replaces=[\"Transformed data\"])\n        components = Output(\"Components\", Table)\n        pca = Output(\"PCA\", PCA, dynamic=False)\n\n    settingsHandler = settings.DomainContextHandler()\n\n    ncomponents = settings.Setting(2)\n    variance_covered = settings.Setting(100)\n    auto_commit = settings.Setting(True)\n    normalize = settings.ContextSetting(True)\n    maxp = settings.Setting(20)\n    axis_labels = settings.Setting(10)\n\n    graph_name = \"plot.plotItem\"\n\n    class Warning(widget.OWWidget.Warning):\n        trivial_components = widget.Msg(\n            \"All components of the PCA are trivial (explain 0 variance). \"\n            \"Input data is constant (or near constant).\")\n\n    class Error(widget.OWWidget.Error):\n        no_features = widget.Msg(\"At least 1 feature is required\")\n        no_instances = widget.Msg(\"At least 1 data instance is required\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n\n        self._pca = None\n        self._transformed = None\n        self._variance_ratio = None\n        self._cumulative = None\n        self._init_projector()\n\n        # Components Selection\n        box = gui.vBox(self.controlArea, \"Components Selection\")\n        form = QFormLayout()\n        box.layout().addLayout(form)\n\n        self.components_spin = gui.spin(\n            box, self, \"ncomponents\", 1, MAX_COMPONENTS,\n            callback=self._update_selection_component_spin,\n            keyboardTracking=False\n        )\n        self.components_spin.setSpecialValueText(\"All\")\n\n        self.variance_spin = gui.spin(\n            box, self, \"variance_covered\", 1, 100,\n            callback=self._update_selection_variance_spin,\n            keyboardTracking=False\n        )\n        self.variance_spin.setSuffix(\"%\")\n\n        form.addRow(\"Components:\", self.components_spin)\n        form.addRow(\"Explained variance:\", self.variance_spin)\n\n        # Options\n        self.options_box = gui.vBox(self.controlArea, \"Options\")\n        self.normalize_box = gui.checkBox(\n            self.options_box, self, \"normalize\",\n            \"Normalize variables\", callback=self._update_normalize\n        )\n\n        self.maxp_spin = gui.spin(\n            self.options_box, self, \"maxp\", 1, MAX_COMPONENTS,\n            label=\"Show only first\", callback=self._setup_plot,\n            keyboardTracking=False\n        )\n\n        self.controlArea.layout().addStretch()\n\n        gui.auto_apply(self.controlArea, self, \"auto_commit\")\n\n        self.plot = SliderGraph(\n            \"Principal Components\", \"Proportion of variance\",\n            self._on_cut_changed)\n\n        self.mainArea.layout().addWidget(self.plot)\n        self._update_normalize()\n\n    @Inputs.data\n    def set_data(self, data):\n        self.closeContext()\n        self.clear_messages()\n        self.clear()\n        self.information()\n        self.data = None\n        if isinstance(data, SqlTable):\n            if data.approx_len() < AUTO_DL_LIMIT:\n                data = Table(data)\n            else:\n                self.information(\"Data has been sampled\")\n                data_sample = data.sample_time(1, no_cache=True)\n                data_sample.download_data(2000, partial=True)\n                data = Table(data_sample)\n        if isinstance(data, Table):\n            if not data.domain.attributes:\n                self.Error.no_features()\n                self.clear_outputs()\n                return\n            if not data:\n                self.Error.no_instances()\n                self.clear_outputs()\n                return\n\n        self.openContext(data)\n        self._init_projector()\n\n        self.data = data\n        self.fit()\n\n    def fit(self):\n        self.clear()\n        self.Warning.trivial_components.clear()\n        if self.data is None:\n            return\n\n        data = self.data\n\n        if self.normalize:\n            self._pca_projector.preprocessors = \\\n                self._pca_preprocessors + [preprocess.Normalize(center=False)]\n        else:\n            self._pca_projector.preprocessors = self._pca_preprocessors\n\n        if not isinstance(data, SqlTable):\n            pca = self._pca_projector(data)\n            variance_ratio = pca.explained_variance_ratio_\n            cumulative = numpy.cumsum(variance_ratio)\n\n            if numpy.isfinite(cumulative[-1]):\n                self.components_spin.setRange(0, len(cumulative))\n                self._pca = pca\n                self._variance_ratio = variance_ratio\n                self._cumulative = cumulative\n                self._setup_plot()\n            else:\n                self.Warning.trivial_components()\n\n            self.unconditional_commit()\n\n    def clear(self):\n        self._pca = None\n        self._transformed = None\n        self._variance_ratio = None\n        self._cumulative = None\n        self.plot.clear_plot()\n\n    def clear_outputs(self):\n        self.Outputs.transformed_data.send(None)\n        self.Outputs.components.send(None)\n        self.Outputs.pca.send(self._pca_projector)\n\n    def _setup_plot(self):\n        if self._pca is None:\n            self.plot.clear_plot()\n            return\n\n        explained_ratio = self._variance_ratio\n        explained = self._cumulative\n        cutpos = self._nselected_components()\n        p = min(len(self._variance_ratio), self.maxp)\n\n        self.plot.update(\n            numpy.arange(1, p+1), [explained_ratio[:p], explained[:p]],\n            [Qt.red, Qt.darkYellow], cutpoint_x=cutpos, names=LINE_NAMES)\n\n        self._update_axis()\n\n    def _on_cut_changed(self, components):\n        if components == self.ncomponents \\\n                or self.ncomponents == 0 \\\n                or self._pca is not None \\\n                and components == len(self._variance_ratio):\n            return\n\n        self.ncomponents = components\n        if self._pca is not None:\n            var = self._cumulative[components - 1]\n            if numpy.isfinite(var):\n                self.variance_covered = int(var * 100)\n\n        self._invalidate_selection()\n\n    def _update_selection_component_spin(self):\n        # cut changed by \"ncomponents\" spin.\n        if self._pca is None:\n            self._invalidate_selection()\n            return\n\n        if self.ncomponents == 0:\n            # Special \"All\" value\n            cut = len(self._variance_ratio)\n        else:\n            cut = self.ncomponents\n\n        var = self._cumulative[cut - 1]\n        if numpy.isfinite(var):\n            self.variance_covered = int(var * 100)\n\n        self.plot.set_cut_point(cut)\n        self._invalidate_selection()\n\n    def _update_selection_variance_spin(self):\n        # cut changed by \"max variance\" spin.\n        if self._pca is None:\n            return\n\n        cut = numpy.searchsorted(self._cumulative,\n                                 self.variance_covered / 100.0) + 1\n        cut = min(cut, len(self._cumulative))\n        self.ncomponents = cut\n        self.plot.set_cut_point(cut)\n        self._invalidate_selection()\n\n    def _update_normalize(self):\n        self.fit()\n        if self.data is None:\n            self._invalidate_selection()\n\n    def _init_projector(self):\n        self._pca_projector = PCA(n_components=MAX_COMPONENTS, random_state=0)\n        self._pca_projector.component = self.ncomponents\n        self._pca_preprocessors = PCA.preprocessors\n\n    def _nselected_components(self):\n        \"\"\"Return the number of selected components.\"\"\"\n        if self._pca is None:\n            return 0\n\n        if self.ncomponents == 0:\n            # Special \"All\" value\n            max_comp = len(self._variance_ratio)\n        else:\n            max_comp = self.ncomponents\n\n        var_max = self._cumulative[max_comp - 1]\n        if var_max != numpy.floor(self.variance_covered / 100.0):\n            cut = max_comp\n            assert numpy.isfinite(var_max)\n            self.variance_covered = int(var_max * 100)\n        else:\n            self.ncomponents = cut = numpy.searchsorted(\n                self._cumulative, self.variance_covered / 100.0) + 1\n        return cut\n\n    def _invalidate_selection(self):\n        self.commit()\n\n    def _update_axis(self):\n        p = min(len(self._variance_ratio), self.maxp)\n        axis = self.plot.getAxis(\"bottom\")\n        d = max((p-1)//(self.axis_labels-1), 1)\n        axis.setTicks([[(i, str(i)) for i in range(1, p + 1, d)]])\n\n    def commit(self):\n        transformed = components = None\n        if self._pca is not None:\n            if self._transformed is None:\n                # Compute the full transform (MAX_COMPONENTS components) once.\n                self._transformed = self._pca(self.data)\n            transformed = self._transformed\n\n            domain = Domain(\n                transformed.domain.attributes[:self.ncomponents],\n                self.data.domain.class_vars,\n                self.data.domain.metas\n            )\n            transformed = transformed.from_table(domain, transformed)\n            # prevent caching new features by defining compute_value\n            dom = Domain(\n                [ContinuousVariable(a.name, compute_value=lambda _: None)\n                 for a in self._pca.orig_domain.attributes],\n                metas=[StringVariable(name='component')])\n            metas = numpy.array([['PC{}'.format(i + 1)\n                                  for i in range(self.ncomponents)]],\n                                dtype=object).T\n            components = Table(dom, self._pca.components_[:self.ncomponents],\n                               metas=metas)\n            components.name = 'components'\n\n        self._pca_projector.component = self.ncomponents\n        self.Outputs.transformed_data.send(transformed)\n        self.Outputs.components.send(components)\n        self.Outputs.pca.send(self._pca_projector)\n\n    def send_report(self):\n        if self.data is None:\n            return\n        self.report_items((\n            (\"Normalize data\", str(self.normalize)),\n            (\"Selected components\", self.ncomponents),\n            (\"Explained variance\", \"{:.3f} %\".format(self.variance_covered))\n        ))\n        self.report_plot()\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        if \"variance_covered\" in settings:\n            # Due to the error in gh-1896 the variance_covered was persisted\n            # as a NaN value, causing a TypeError in the widgets `__init__`.\n            vc = settings[\"variance_covered\"]\n            if isinstance(vc, numbers.Real):\n                if numpy.isfinite(vc):\n                    vc = int(vc)\n                else:\n                    vc = 100\n                settings[\"variance_covered\"] = vc\n        if settings.get(\"ncomponents\", 0) > MAX_COMPONENTS:\n            settings[\"ncomponents\"] = MAX_COMPONENTS\n\n        # Remove old `decomposition_idx` when SVD was still included\n        settings.pop(\"decomposition_idx\", None)\n\n        # Remove RemotePCA settings\n        settings.pop(\"batch_size\", None)\n        settings.pop(\"address\", None)\n        settings.pop(\"auto_update\", None)\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    WidgetPreview(OWPCA).run(Table(\"housing\"))\n", "path": "Orange/widgets/unsupervised/owpca.py"}], "after_files": [{"content": "import numbers\n\nimport numpy\nfrom AnyQt.QtWidgets import QFormLayout\nfrom AnyQt.QtCore import Qt\n\nfrom Orange.data import Table, Domain, StringVariable, ContinuousVariable\nfrom Orange.data.sql.table import SqlTable, AUTO_DL_LIMIT\nfrom Orange.preprocess import preprocess\nfrom Orange.projection import PCA\nfrom Orange.widgets import widget, gui, settings\nfrom Orange.widgets.utils.slidergraph import SliderGraph\nfrom Orange.widgets.utils.widgetpreview import WidgetPreview\nfrom Orange.widgets.widget import Input, Output\n\n\n# Maximum number of PCA components that we can set in the widget\nMAX_COMPONENTS = 100\nLINE_NAMES = [\"component variance\", \"cumulative variance\"]\n\n\nclass OWPCA(widget.OWWidget):\n    name = \"PCA\"\n    description = \"Principal component analysis with a scree-diagram.\"\n    icon = \"icons/PCA.svg\"\n    priority = 3050\n    keywords = [\"principal component analysis\", \"linear transformation\"]\n\n    class Inputs:\n        data = Input(\"Data\", Table)\n\n    class Outputs:\n        transformed_data = Output(\"Transformed Data\", Table, replaces=[\"Transformed data\"])\n        data = Output(\"Data\", Table, default=True)\n        components = Output(\"Components\", Table)\n        pca = Output(\"PCA\", PCA, dynamic=False)\n\n    settingsHandler = settings.DomainContextHandler()\n\n    ncomponents = settings.Setting(2)\n    variance_covered = settings.Setting(100)\n    auto_commit = settings.Setting(True)\n    normalize = settings.ContextSetting(True)\n    maxp = settings.Setting(20)\n    axis_labels = settings.Setting(10)\n\n    graph_name = \"plot.plotItem\"\n\n    class Warning(widget.OWWidget.Warning):\n        trivial_components = widget.Msg(\n            \"All components of the PCA are trivial (explain 0 variance). \"\n            \"Input data is constant (or near constant).\")\n\n    class Error(widget.OWWidget.Error):\n        no_features = widget.Msg(\"At least 1 feature is required\")\n        no_instances = widget.Msg(\"At least 1 data instance is required\")\n\n    def __init__(self):\n        super().__init__()\n        self.data = None\n\n        self._pca = None\n        self._transformed = None\n        self._variance_ratio = None\n        self._cumulative = None\n        self._init_projector()\n\n        # Components Selection\n        box = gui.vBox(self.controlArea, \"Components Selection\")\n        form = QFormLayout()\n        box.layout().addLayout(form)\n\n        self.components_spin = gui.spin(\n            box, self, \"ncomponents\", 1, MAX_COMPONENTS,\n            callback=self._update_selection_component_spin,\n            keyboardTracking=False\n        )\n        self.components_spin.setSpecialValueText(\"All\")\n\n        self.variance_spin = gui.spin(\n            box, self, \"variance_covered\", 1, 100,\n            callback=self._update_selection_variance_spin,\n            keyboardTracking=False\n        )\n        self.variance_spin.setSuffix(\"%\")\n\n        form.addRow(\"Components:\", self.components_spin)\n        form.addRow(\"Explained variance:\", self.variance_spin)\n\n        # Options\n        self.options_box = gui.vBox(self.controlArea, \"Options\")\n        self.normalize_box = gui.checkBox(\n            self.options_box, self, \"normalize\",\n            \"Normalize variables\", callback=self._update_normalize\n        )\n\n        self.maxp_spin = gui.spin(\n            self.options_box, self, \"maxp\", 1, MAX_COMPONENTS,\n            label=\"Show only first\", callback=self._setup_plot,\n            keyboardTracking=False\n        )\n\n        self.controlArea.layout().addStretch()\n\n        gui.auto_apply(self.controlArea, self, \"auto_commit\")\n\n        self.plot = SliderGraph(\n            \"Principal Components\", \"Proportion of variance\",\n            self._on_cut_changed)\n\n        self.mainArea.layout().addWidget(self.plot)\n        self._update_normalize()\n\n    @Inputs.data\n    def set_data(self, data):\n        self.closeContext()\n        self.clear_messages()\n        self.clear()\n        self.information()\n        self.data = None\n        if isinstance(data, SqlTable):\n            if data.approx_len() < AUTO_DL_LIMIT:\n                data = Table(data)\n            else:\n                self.information(\"Data has been sampled\")\n                data_sample = data.sample_time(1, no_cache=True)\n                data_sample.download_data(2000, partial=True)\n                data = Table(data_sample)\n        if isinstance(data, Table):\n            if not data.domain.attributes:\n                self.Error.no_features()\n                self.clear_outputs()\n                return\n            if not data:\n                self.Error.no_instances()\n                self.clear_outputs()\n                return\n\n        self.openContext(data)\n        self._init_projector()\n\n        self.data = data\n        self.fit()\n\n    def fit(self):\n        self.clear()\n        self.Warning.trivial_components.clear()\n        if self.data is None:\n            return\n\n        data = self.data\n\n        if self.normalize:\n            self._pca_projector.preprocessors = \\\n                self._pca_preprocessors + [preprocess.Normalize(center=False)]\n        else:\n            self._pca_projector.preprocessors = self._pca_preprocessors\n\n        if not isinstance(data, SqlTable):\n            pca = self._pca_projector(data)\n            variance_ratio = pca.explained_variance_ratio_\n            cumulative = numpy.cumsum(variance_ratio)\n\n            if numpy.isfinite(cumulative[-1]):\n                self.components_spin.setRange(0, len(cumulative))\n                self._pca = pca\n                self._variance_ratio = variance_ratio\n                self._cumulative = cumulative\n                self._setup_plot()\n            else:\n                self.Warning.trivial_components()\n\n            self.unconditional_commit()\n\n    def clear(self):\n        self._pca = None\n        self._transformed = None\n        self._variance_ratio = None\n        self._cumulative = None\n        self.plot.clear_plot()\n\n    def clear_outputs(self):\n        self.Outputs.transformed_data.send(None)\n        self.Outputs.data.send(None)\n        self.Outputs.components.send(None)\n        self.Outputs.pca.send(self._pca_projector)\n\n    def _setup_plot(self):\n        if self._pca is None:\n            self.plot.clear_plot()\n            return\n\n        explained_ratio = self._variance_ratio\n        explained = self._cumulative\n        cutpos = self._nselected_components()\n        p = min(len(self._variance_ratio), self.maxp)\n\n        self.plot.update(\n            numpy.arange(1, p+1), [explained_ratio[:p], explained[:p]],\n            [Qt.red, Qt.darkYellow], cutpoint_x=cutpos, names=LINE_NAMES)\n\n        self._update_axis()\n\n    def _on_cut_changed(self, components):\n        if components == self.ncomponents \\\n                or self.ncomponents == 0 \\\n                or self._pca is not None \\\n                and components == len(self._variance_ratio):\n            return\n\n        self.ncomponents = components\n        if self._pca is not None:\n            var = self._cumulative[components - 1]\n            if numpy.isfinite(var):\n                self.variance_covered = int(var * 100)\n\n        self._invalidate_selection()\n\n    def _update_selection_component_spin(self):\n        # cut changed by \"ncomponents\" spin.\n        if self._pca is None:\n            self._invalidate_selection()\n            return\n\n        if self.ncomponents == 0:\n            # Special \"All\" value\n            cut = len(self._variance_ratio)\n        else:\n            cut = self.ncomponents\n\n        var = self._cumulative[cut - 1]\n        if numpy.isfinite(var):\n            self.variance_covered = int(var * 100)\n\n        self.plot.set_cut_point(cut)\n        self._invalidate_selection()\n\n    def _update_selection_variance_spin(self):\n        # cut changed by \"max variance\" spin.\n        if self._pca is None:\n            return\n\n        cut = numpy.searchsorted(self._cumulative,\n                                 self.variance_covered / 100.0) + 1\n        cut = min(cut, len(self._cumulative))\n        self.ncomponents = cut\n        self.plot.set_cut_point(cut)\n        self._invalidate_selection()\n\n    def _update_normalize(self):\n        self.fit()\n        if self.data is None:\n            self._invalidate_selection()\n\n    def _init_projector(self):\n        self._pca_projector = PCA(n_components=MAX_COMPONENTS, random_state=0)\n        self._pca_projector.component = self.ncomponents\n        self._pca_preprocessors = PCA.preprocessors\n\n    def _nselected_components(self):\n        \"\"\"Return the number of selected components.\"\"\"\n        if self._pca is None:\n            return 0\n\n        if self.ncomponents == 0:\n            # Special \"All\" value\n            max_comp = len(self._variance_ratio)\n        else:\n            max_comp = self.ncomponents\n\n        var_max = self._cumulative[max_comp - 1]\n        if var_max != numpy.floor(self.variance_covered / 100.0):\n            cut = max_comp\n            assert numpy.isfinite(var_max)\n            self.variance_covered = int(var_max * 100)\n        else:\n            self.ncomponents = cut = numpy.searchsorted(\n                self._cumulative, self.variance_covered / 100.0) + 1\n        return cut\n\n    def _invalidate_selection(self):\n        self.commit()\n\n    def _update_axis(self):\n        p = min(len(self._variance_ratio), self.maxp)\n        axis = self.plot.getAxis(\"bottom\")\n        d = max((p-1)//(self.axis_labels-1), 1)\n        axis.setTicks([[(i, str(i)) for i in range(1, p + 1, d)]])\n\n    def commit(self):\n        transformed = data = components = None\n        if self._pca is not None:\n            if self._transformed is None:\n                # Compute the full transform (MAX_COMPONENTS components) once.\n                self._transformed = self._pca(self.data)\n            transformed = self._transformed\n\n            domain = Domain(\n                transformed.domain.attributes[:self.ncomponents],\n                self.data.domain.class_vars,\n                self.data.domain.metas\n            )\n            transformed = transformed.from_table(domain, transformed)\n            # prevent caching new features by defining compute_value\n            dom = Domain(\n                [ContinuousVariable(a.name, compute_value=lambda _: None)\n                 for a in self._pca.orig_domain.attributes],\n                metas=[StringVariable(name='component')])\n            metas = numpy.array([['PC{}'.format(i + 1)\n                                  for i in range(self.ncomponents)]],\n                                dtype=object).T\n            components = Table(dom, self._pca.components_[:self.ncomponents],\n                               metas=metas)\n            components.name = 'components'\n\n            data_dom = Domain(\n                self.data.domain.attributes,\n                self.data.domain.class_vars,\n                self.data.domain.metas + domain.attributes)\n            data = Table.from_numpy(\n                data_dom, self.data.X, self.data.Y,\n                numpy.hstack((self.data.metas, transformed.X)))\n\n        self._pca_projector.component = self.ncomponents\n        self.Outputs.transformed_data.send(transformed)\n        self.Outputs.components.send(components)\n        self.Outputs.data.send(data)\n        self.Outputs.pca.send(self._pca_projector)\n\n    def send_report(self):\n        if self.data is None:\n            return\n        self.report_items((\n            (\"Normalize data\", str(self.normalize)),\n            (\"Selected components\", self.ncomponents),\n            (\"Explained variance\", \"{:.3f} %\".format(self.variance_covered))\n        ))\n        self.report_plot()\n\n    @classmethod\n    def migrate_settings(cls, settings, version):\n        if \"variance_covered\" in settings:\n            # Due to the error in gh-1896 the variance_covered was persisted\n            # as a NaN value, causing a TypeError in the widgets `__init__`.\n            vc = settings[\"variance_covered\"]\n            if isinstance(vc, numbers.Real):\n                if numpy.isfinite(vc):\n                    vc = int(vc)\n                else:\n                    vc = 100\n                settings[\"variance_covered\"] = vc\n        if settings.get(\"ncomponents\", 0) > MAX_COMPONENTS:\n            settings[\"ncomponents\"] = MAX_COMPONENTS\n\n        # Remove old `decomposition_idx` when SVD was still included\n        settings.pop(\"decomposition_idx\", None)\n\n        # Remove RemotePCA settings\n        settings.pop(\"batch_size\", None)\n        settings.pop(\"address\", None)\n        settings.pop(\"auto_update\", None)\n\n\nif __name__ == \"__main__\":  # pragma: no cover\n    WidgetPreview(OWPCA).run(Table(\"housing\"))\n", "path": "Orange/widgets/unsupervised/owpca.py"}]}