|
9 | 9 | ) |
10 | 10 |
|
11 | 11 | from Orange.widgets import gui, widget |
12 | | -from Orange.widgets.data.contexthandlers import \ |
13 | | - SelectAttributesDomainContextHandler |
14 | | -from Orange.widgets.settings import ContextSetting, Setting |
15 | | -from Orange.widgets.utils.listfilter import VariablesListItemView, slices, variables_filter |
| 12 | +from Orange.widgets.settings import ( |
| 13 | + ContextSetting, Setting, DomainContextHandler |
| 14 | +) |
| 15 | +from Orange.widgets.utils import vartype |
| 16 | +from Orange.widgets.utils.listfilter import ( |
| 17 | + VariablesListItemView, slices, variables_filter |
| 18 | +) |
16 | 19 | from Orange.widgets.utils.widgetpreview import WidgetPreview |
17 | 20 | from Orange.widgets.utils.state_summary import format_summary_details |
18 | 21 | from Orange.widgets.widget import Input, Output, AttributeList, Msg |
19 | 22 | from Orange.data.table import Table |
20 | | -from Orange.widgets.utils import vartype |
21 | 23 | from Orange.widgets.utils.itemmodels import VariableListModel |
22 | 24 | import Orange |
23 | 25 |
|
@@ -99,6 +101,45 @@ def dropMimeData(self, mime, action, row, column, parent): |
99 | 101 | return True |
100 | 102 |
|
101 | 103 |
|
| 104 | +class SelectAttributesDomainContextHandler(DomainContextHandler): |
| 105 | + def encode_setting(self, context, setting, value): |
| 106 | + if setting.name == 'domain_role_hints': |
| 107 | + value = {(var.name, vartype(var)): role_i |
| 108 | + for var, role_i in value.items()} |
| 109 | + return super().encode_setting(context, setting, value) |
| 110 | + |
| 111 | + def decode_setting(self, setting, value, domain=None): |
| 112 | + decoded = super().decode_setting(setting, value, domain) |
| 113 | + if setting.name == 'domain_role_hints': |
| 114 | + decoded = {domain[name]: role_i |
| 115 | + for (name, _), role_i in decoded.items()} |
| 116 | + return decoded |
| 117 | + |
| 118 | + def match(self, context, domain, attrs, metas): |
| 119 | + if not "domain_role_hints" in context.values: |
| 120 | + return self.NO_MATCH |
| 121 | + |
| 122 | + all_vars = attrs.copy() |
| 123 | + all_vars.update(metas) |
| 124 | + value = context.values["domain_role_hints"][0] |
| 125 | + assigned = [desc for desc, (role, _) in value.items() |
| 126 | + if role != "available"] |
| 127 | + return assigned and \ |
| 128 | + sum(all_vars.get(attr) == vtype for attr, vtype in assigned) \ |
| 129 | + / len(assigned) |
| 130 | + |
| 131 | + def filter_value(self, setting, data, domain, attrs, metas): |
| 132 | + if setting.name != "domain_role_hints": |
| 133 | + return super().filter_value(setting, data, domain, attrs, metas) |
| 134 | + |
| 135 | + all_vars = attrs.copy() |
| 136 | + all_vars.update(metas) |
| 137 | + value = data["domain_role_hints"][0].items() |
| 138 | + data["domain_role_hints"] = {desc: role_i |
| 139 | + for desc, role_i in value |
| 140 | + if all_vars.get(desc[0]) == desc[1]} |
| 141 | + |
| 142 | + |
102 | 143 | class OWSelectAttributes(widget.OWWidget): |
103 | 144 | # pylint: disable=too-many-instance-attributes |
104 | 145 | name = "Select Columns" |
@@ -305,68 +346,52 @@ def __used_attrs_changed(self): |
305 | 346 | def set_data(self, data=None): |
306 | 347 | self.update_domain_role_hints() |
307 | 348 | self.closeContext() |
| 349 | + self.domain_role_hints = {} |
| 350 | + |
308 | 351 | self.data = data |
309 | | - if data is not None: |
310 | | - self.openContext(data) |
311 | | - all_vars = data.domain.variables + data.domain.metas |
312 | | - |
313 | | - var_sig = lambda attr: (attr.name, vartype(attr)) |
314 | | - |
315 | | - domain_hints = {var_sig(attr): ("attribute", i) |
316 | | - for i, attr in enumerate(data.domain.attributes)} |
317 | | - |
318 | | - domain_hints.update({var_sig(attr): ("meta", i) |
319 | | - for i, attr in enumerate(data.domain.metas)}) |
320 | | - |
321 | | - if data.domain.class_vars: |
322 | | - domain_hints.update( |
323 | | - {var_sig(attr): ("class", i) |
324 | | - for i, attr in enumerate(data.domain.class_vars)}) |
325 | | - |
326 | | - # update the hints from context settings |
327 | | - domain_hints.update(self.domain_role_hints) |
328 | | - |
329 | | - attrs_for_role = lambda role: [ |
330 | | - (domain_hints[var_sig(attr)][1], attr) |
331 | | - for attr in all_vars if domain_hints[var_sig(attr)][0] == role] |
332 | | - |
333 | | - attributes = [ |
334 | | - attr for place, attr in sorted(attrs_for_role("attribute"), |
335 | | - key=lambda a: a[0])] |
336 | | - classes = [ |
337 | | - attr for place, attr in sorted(attrs_for_role("class"), |
338 | | - key=lambda a: a[0])] |
339 | | - metas = [ |
340 | | - attr for place, attr in sorted(attrs_for_role("meta"), |
341 | | - key=lambda a: a[0])] |
342 | | - available = [ |
343 | | - attr for place, attr in sorted(attrs_for_role("available"), |
344 | | - key=lambda a: a[0])] |
345 | | - |
346 | | - self.used_attrs[:] = attributes |
347 | | - self.class_attrs[:] = classes |
348 | | - self.meta_attrs[:] = metas |
349 | | - self.available_attrs[:] = available |
350 | | - self.info.set_input_summary(len(data), format_summary_details(data)) |
351 | | - else: |
| 352 | + if data is None: |
352 | 353 | self.used_attrs[:] = [] |
353 | 354 | self.class_attrs[:] = [] |
354 | 355 | self.meta_attrs[:] = [] |
355 | 356 | self.available_attrs[:] = [] |
356 | 357 | self.info.set_input_summary(self.info.NoInput) |
| 358 | + return |
| 359 | + |
| 360 | + self.openContext(data) |
| 361 | + all_vars = data.domain.variables + data.domain.metas |
| 362 | + |
| 363 | + def attrs_for_role(role): |
| 364 | + return [attr for _, attr in sorted( |
| 365 | + (domain_hints[attr][1], attr) |
| 366 | + for attr in all_vars if domain_hints[attr][0] == role)] |
| 367 | + |
| 368 | + domain = data.domain |
| 369 | + domain_hints = {} |
| 370 | + domain_hints.update(self._hints_from_seq("attribute", domain.attributes)) |
| 371 | + domain_hints.update(self._hints_from_seq("meta", domain.metas)) |
| 372 | + domain_hints.update(self._hints_from_seq("class", domain.class_vars)) |
| 373 | + domain_hints.update(self.domain_role_hints) |
| 374 | + |
| 375 | + self.used_attrs[:] = attrs_for_role("attribute") |
| 376 | + self.class_attrs[:] = attrs_for_role("class") |
| 377 | + self.meta_attrs[:] = attrs_for_role("meta") |
| 378 | + self.available_attrs[:] = attrs_for_role("available") |
| 379 | + self.info.set_input_summary(len(data), format_summary_details(data)) |
357 | 380 |
|
358 | 381 | def update_domain_role_hints(self): |
359 | 382 | """ Update the domain hints to be stored in the widgets settings. |
360 | 383 | """ |
361 | | - hints_from_model = lambda role, model: [ |
362 | | - ((attr.name, vartype(attr)), (role, i)) |
363 | | - for i, attr in enumerate(model)] |
364 | | - hints = dict(hints_from_model("available", self.available_attrs)) |
365 | | - hints.update(hints_from_model("attribute", self.used_attrs)) |
366 | | - hints.update(hints_from_model("class", self.class_attrs)) |
367 | | - hints.update(hints_from_model("meta", self.meta_attrs)) |
| 384 | + hints = {} |
| 385 | + hints.update(self._hints_from_seq("available", self.available_attrs)) |
| 386 | + hints.update(self._hints_from_seq("attribute", self.used_attrs)) |
| 387 | + hints.update(self._hints_from_seq("class", self.class_attrs)) |
| 388 | + hints.update(self._hints_from_seq("meta", self.meta_attrs)) |
368 | 389 | self.domain_role_hints = hints |
369 | 390 |
|
| 391 | + @staticmethod |
| 392 | + def _hints_from_seq(role, model): |
| 393 | + return [(attr, (role, i)) for i, attr in enumerate(model)] |
| 394 | + |
370 | 395 | @Inputs.features |
371 | 396 | def set_features(self, features): |
372 | 397 | self.features = features |
|
0 commit comments