Skip to content

Commit 4a0cd77

Browse files
ajdapretnarjanezd
authored andcommitted
Store settings as Variable
1 parent d4c1666 commit 4a0cd77

File tree

3 files changed

+97
-119
lines changed

3 files changed

+97
-119
lines changed

Orange/widgets/data/contexthandlers.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

Orange/widgets/data/owselectcolumns.py

Lines changed: 80 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@
99
)
1010

1111
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+
)
1619
from Orange.widgets.utils.widgetpreview import WidgetPreview
1720
from Orange.widgets.utils.state_summary import format_summary_details
1821
from Orange.widgets.widget import Input, Output, AttributeList, Msg
1922
from Orange.data.table import Table
20-
from Orange.widgets.utils import vartype
2123
from Orange.widgets.utils.itemmodels import VariableListModel
2224
import Orange
2325

@@ -99,6 +101,45 @@ def dropMimeData(self, mime, action, row, column, parent):
99101
return True
100102

101103

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+
102143
class OWSelectAttributes(widget.OWWidget):
103144
# pylint: disable=too-many-instance-attributes
104145
name = "Select Columns"
@@ -305,68 +346,52 @@ def __used_attrs_changed(self):
305346
def set_data(self, data=None):
306347
self.update_domain_role_hints()
307348
self.closeContext()
349+
self.domain_role_hints = {}
350+
308351
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:
352353
self.used_attrs[:] = []
353354
self.class_attrs[:] = []
354355
self.meta_attrs[:] = []
355356
self.available_attrs[:] = []
356357
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))
357380

358381
def update_domain_role_hints(self):
359382
""" Update the domain hints to be stored in the widgets settings.
360383
"""
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))
368389
self.domain_role_hints = hints
369390

391+
@staticmethod
392+
def _hints_from_seq(role, model):
393+
return [(attr, (role, i)) for i, attr in enumerate(model)]
394+
370395
@Inputs.features
371396
def set_features(self, features):
372397
self.features = features

Orange/widgets/data/tests/test_owselectcolumns.py

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66
from AnyQt.QtGui import QDragEnterEvent
77

88
from Orange.data import Table, ContinuousVariable, DiscreteVariable, Domain
9-
from Orange.widgets.data.contexthandlers import \
10-
SelectAttributesDomainContextHandler
119
from Orange.widgets.settings import ContextSetting
1210
from Orange.widgets.utils import vartype
1311
from Orange.widgets.utils.state_summary import format_summary_details
1412
from Orange.widgets.tests.base import WidgetTest
1513
from Orange.widgets.data.owselectcolumns \
16-
import OWSelectAttributes, VariablesListItemModel
14+
import OWSelectAttributes, VariablesListItemModel, \
15+
SelectAttributesDomainContextHandler
1716
from Orange.widgets.data.owrank import OWRank
1817
from Orange.widgets.widget import AttributeList
1918

@@ -56,20 +55,21 @@ def test_open_context(self):
5655

5756
widget = SimpleWidget()
5857
self.handler.initialize(widget)
59-
self.handler.open_context(widget, self.args[0])
58+
domain = self.args[0]
59+
self.handler.open_context(widget, domain)
6060
self.assertEqual(widget.domain_role_hints,
61-
{('d1', Discrete): ('available', 0),
62-
('d2', Discrete): ('meta', 0),
63-
('c1', Continuous): ('attribute', 0),
64-
('d3', Discrete): ('attribute', 1),
65-
('d4', Discrete): ('attribute', 2),
66-
('c2', Continuous): ('class', 0)})
61+
{domain['d1']: ('available', 0),
62+
domain['d2']: ('meta', 0),
63+
domain['c1']: ('attribute', 0),
64+
domain['d3']: ('attribute', 1),
65+
domain['d4']: ('attribute', 2),
66+
domain['c2']: ('class', 0)})
6767

6868
def test_open_context_with_imperfect_match(self):
6969
self.handler.bind(SimpleWidget)
7070
context1 = Mock(values=dict(
7171
domain_role_hints=({('d1', Discrete): ('attribute', 0),
72-
('m2', Discrete): ('meta', 0)})
72+
('m2', Discrete): ('meta', 0)}, -2)
7373
))
7474
context = Mock(values=dict(
7575
domain_role_hints=({('d1', Discrete): ('available', 0),
@@ -84,30 +84,14 @@ def test_open_context_with_imperfect_match(self):
8484

8585
widget = SimpleWidget()
8686
self.handler.initialize(widget)
87-
self.handler.open_context(widget, self.args[0])
87+
domain = self.args[0]
88+
self.handler.open_context(widget, domain)
8889

8990
self.assertEqual(widget.domain_role_hints,
90-
{('d1', Discrete): ('available', 0),
91-
('d2', Discrete): ('meta', 0),
92-
('c1', Continuous): ('attribute', 0),
93-
('c2', Continuous): ('class', 0)})
94-
95-
def test_open_context_with_no_match(self):
96-
self.handler.bind(SimpleWidget)
97-
context = Mock(values=dict(
98-
domain_role_hints=({('d1', Discrete): ('available', 0),
99-
('d2', Discrete): ('meta', 0),
100-
('c1', Continuous): ('attribute', 0),
101-
('d3', Discrete): ('attribute', 1),
102-
('d4', Discrete): ('attribute', 2),
103-
('c2', Continuous): ('class', 0)}, -2),
104-
required=('g1', Continuous),
105-
))
106-
self.handler.global_contexts = [context]
107-
widget = SimpleWidget()
108-
self.handler.initialize(widget)
109-
self.handler.open_context(widget, self.args[0])
110-
self.assertEqual(widget.domain_role_hints, {})
91+
{domain['d1']: ('available', 0),
92+
domain['d2']: ('meta', 0),
93+
domain['c1']: ('attribute', 0),
94+
domain['c2']: ('class', 0)})
11195

11296

11397
class TestModel(TestCase):

0 commit comments

Comments
 (0)