Skip to content

Commit 0093685

Browse files
committed
Manifold Learning: Fix reseting of selected number of components
1 parent c807a41 commit 0093685

File tree

3 files changed

+65
-17
lines changed

3 files changed

+65
-17
lines changed

Orange/widgets/unsupervised/owmanifoldlearning.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def _create_spin_parameter(self, name, minv, maxv, label):
4343
width = QFontMetrics(self.font()).horizontalAdvance("0" * 10)
4444
control = gui.spin(
4545
self, self, name, minv, maxv,
46-
alignment=Qt.AlignRight, callbackOnReturn=True,
46+
alignment=Qt.AlignRight,
4747
addToLayout=False, controlWidth=width,
4848
callback=lambda f=self.__spin_parameter_update,
4949
p=name: self.__parameter_changed(f, p))
@@ -225,6 +225,9 @@ class Error(OWWidget.Error):
225225

226226
class Warning(OWWidget.Warning):
227227
graph_not_connected = Msg("Disconnected graph, embedding may not work")
228+
less_components = Msg(
229+
"Creating {} components\n"
230+
"The number of components is limited by the number of variables.")
228231

229232
@classmethod
230233
def migrate_settings(cls, settings, version):
@@ -269,14 +272,19 @@ def __init__(self):
269272
self.params_widget.show()
270273

271274
output_box = gui.vBox(self.controlArea, "Output")
272-
self.n_components_spin = gui.spin(
275+
gui.spin(
273276
output_box, self, "n_components", 1, 10, label="Components:",
274277
controlWidth=QFontMetrics(self.font()).horizontalAdvance("0" * 10),
275-
alignment=Qt.AlignRight, callbackOnReturn=True,
276-
callback=self.settings_changed)
277-
gui.rubber(self.n_components_spin.box)
278+
alignment=Qt.AlignRight,
279+
callback=self.settings_changed,
280+
maximum=99)
278281
self.apply_button = gui.auto_apply(self.buttonsArea, self)
279282

283+
@property
284+
def act_components(self):
285+
return min(self.n_components,
286+
len(self.data.domain.attributes) if self.data else 0)
287+
280288
def manifold_method_changed(self):
281289
self.params_widget.hide()
282290
self.params_widget = self.parameter_editors[self.manifold_method_index]
@@ -289,8 +297,6 @@ def settings_changed(self):
289297
@Inputs.data
290298
def set_data(self, data):
291299
self.data = data
292-
self.n_components_spin.setMaximum(len(self.data.domain.attributes)
293-
if self.data else 10)
294300
self.commit.now()
295301

296302
@gui.deferred
@@ -325,8 +331,8 @@ def _handle_disconnected_graph_warning(msg, *args, **kwargs):
325331
if e.args[0] == "for method='hessian', n_neighbors " \
326332
"must be greater than [n_components" \
327333
" * (n_components + 3) / 2]":
328-
n = self.n_components * (self.n_components + 3) / 2
329-
self.Error.n_neighbors_too_small("{}".format(n))
334+
n = self.act_components * (self.act_components + 3) / 2
335+
self.Error.n_neighbors_too_small(n)
330336
else:
331337
self.Error.manifold_error(e.args[0])
332338
except MemoryError:
@@ -338,6 +344,8 @@ def _handle_disconnected_graph_warning(msg, *args, **kwargs):
338344

339345
output = self._create_output_table(embedding)
340346
self.Outputs.transformed_data.send(output)
347+
if output and self.n_components != self.act_components:
348+
self.Warning.less_components(self.act_components)
341349

342350
def _create_output_table(self, embedding: np.ndarray) -> Optional[Table]:
343351
if embedding is None:
@@ -346,7 +354,7 @@ def _create_output_table(self, embedding: np.ndarray) -> Optional[Table]:
346354
data = self.data
347355
metas = list(data.domain.metas)
348356
names = [v.name for v in data.domain.variables + data.domain.metas]
349-
proposed = ["C{}".format(i) for i in range(self.n_components)]
357+
proposed = ["C{}".format(i) for i in range(self.act_components)]
350358
unique = get_unique_names(names, proposed)
351359
domain = Domain(data.domain.attributes, data.domain.class_vars,
352360
metas + [ContinuousVariable(name) for name in unique])
@@ -356,14 +364,14 @@ def _create_output_table(self, embedding: np.ndarray) -> Optional[Table]:
356364
return table
357365

358366
def get_method_parameters(self):
359-
parameters = dict(n_components=self.n_components)
367+
parameters = dict(n_components=self.act_components)
360368
parameters.update(self.params_widget.get_parameters())
361369
return parameters
362370

363371
def send_report(self):
364372
method = self.MANIFOLD_METHODS[self.manifold_method_index]
365373
self.report_items((("Method", method.name),))
366-
parameters = {"Number of components": self.n_components}
374+
parameters = {"Number of components": self.act_components}
367375
parameters.update(self.params_widget.get_report_parameters())
368376
self.report_items("Method parameters", parameters)
369377
if self.data:

Orange/widgets/unsupervised/tests/test_owmanifoldlearning.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,53 @@ def from_file(cls, filename, sheet=None):
8181
def test_n_components(self):
8282
"""Check the output for various numbers of components"""
8383
self.send_signal(self.widget.Inputs.data, self.iris)
84-
for i in range(self.widget.n_components_spin.minimum(),
85-
self.widget.n_components_spin.maximum()):
84+
for i in range(1, 5):
8685
self.assertEqual(self.widget.data, self.iris)
87-
self.widget.n_components_spin.setValue(i)
88-
self.widget.n_components_spin.onEnter()
86+
self.widget.controls.n_components.setValue(i)
8987
self.click_apply()
9088
self._compare_tables(self.get_output(self.widget.Outputs.transformed_data), i)
9189

90+
def test_too_few_attributes(self):
91+
widget = self.widget
92+
widget.auto_apply = True
93+
spin = widget.controls.n_components
94+
widget.n_components = 3
95+
96+
self.send_signal(self.iris)
97+
self.assertFalse(widget.Warning.less_components.is_shown())
98+
self.assertEqual(self.get_output().metas.shape[1], 3)
99+
self.assertEqual(widget.act_components, 3)
100+
101+
self.send_signal(self.iris[:, :2])
102+
self.assertTrue(widget.Warning.less_components.is_shown())
103+
self.assertEqual(self.get_output().metas.shape[1], 2)
104+
self.assertEqual(widget.act_components, 2)
105+
106+
self.send_signal(None)
107+
self.assertFalse(widget.Warning.less_components.is_shown())
108+
self.assertIsNone(self.get_output())
109+
110+
self.send_signal(self.iris[:, :2])
111+
self.assertTrue(widget.Warning.less_components.is_shown())
112+
self.assertEqual(self.get_output().metas.shape[1], 2)
113+
self.assertEqual(widget.act_components, 2)
114+
115+
self.send_signal(self.iris)
116+
self.assertFalse(widget.Warning.less_components.is_shown())
117+
self.assertEqual(self.get_output().metas.shape[1], 3)
118+
self.assertEqual(widget.act_components, 3)
119+
120+
spin.setValue(6)
121+
assert widget.n_components == 6
122+
self.assertTrue(widget.Warning.less_components.is_shown())
123+
self.assertEqual(self.get_output().metas.shape[1], 4)
124+
self.assertEqual(widget.act_components, 4)
125+
126+
spin.setValue(4)
127+
self.assertFalse(widget.Warning.less_components.is_shown())
128+
self.assertEqual(self.get_output().metas.shape[1], 4)
129+
self.assertEqual(widget.act_components, 4)
130+
92131
def test_manifold_methods(self):
93132
"""Check output for various manifold methods"""
94133
self.send_signal(self.widget.Inputs.data, self.iris)

i18n/si/msgs.jaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11779,6 +11779,8 @@ widgets/unsupervised/owmanifoldlearning.py:
1177911779
Out of memory: Premalo pomnilnika
1178011780
class `Warning`:
1178111781
Disconnected graph, embedding may not work: Graf je nepovezan, vložitev morda ne bo delovala.
11782+
Creating {} components\n: Računam {} komponent.\n
11783+
The number of components is limited by the number of variables.: Število komponent je omejeno s številom spremenljivk.
1178211784
def `migrate_settings`:
1178311785
tsne_editor: false
1178411786
init_index: false
@@ -11797,7 +11799,6 @@ widgets/unsupervised/owmanifoldlearning.py:
1179711799
"for method='hessian', n_neighbors ": false
1179811800
must be greater than [n_components: false
1179911801
' * (n_components + 3) / 2]': false
11800-
{}: false
1180111802
def `_create_output_table`:
1180211803
C{}: false
1180311804
def `send_report`:

0 commit comments

Comments
 (0)