diff --git a/orangecontrib/geo/widgets/owgeocoding.py b/orangecontrib/geo/widgets/owgeocoding.py index 0413dab..5100b12 100644 --- a/orangecontrib/geo/widgets/owgeocoding.py +++ b/orangecontrib/geo/widgets/owgeocoding.py @@ -64,7 +64,7 @@ class Outputs: autocommit = settings.Setting(True) is_decoding = settings.ContextSetting(0) str_attr = settings.ContextSetting(None) - str_type = settings.ContextSetting(next(iter(ID_TYPE))) + str_type = settings.ContextSetting(None) lat_attr = settings.ContextSetting(None) lon_attr = settings.ContextSetting(None) admin = settings.ContextSetting(0) @@ -106,13 +106,14 @@ def _radioChanged(): model = DomainModel(parent=self, valid_types=(StringVariable, DiscreteVariable)) self.domainmodels.append(model) - combo = gui.comboBox( + gui.comboBox( box, self, 'str_attr', label='Region identifier:', - orientation=Qt.Horizontal, callback=self.region_attr_changed, + orientation=Qt.Horizontal, callback=self.on_region_attr_changed, sendSelectedValue=True, model=model) - gui.comboBox( - box, self, 'str_type', label='Identifier type:', orientation=Qt.Horizontal, - items=tuple(self.ID_TYPE.keys()), callback=lambda: self.commit(), sendSelectedValue=True) + self.str_type_combo = gui.comboBox( + box, self, None, label='Identifier type:', orientation=Qt.Horizontal, + items=tuple(self.ID_TYPE)) + self.str_type_combo.textActivated.connect(self.on_region_type_changed) # Select first mode if any of its combos are changed for combo in box.findChildren(QComboBox): @@ -203,7 +204,15 @@ def save_and_commit(): box.layout().addWidget(view) self.setMainAreaVisibility(False) - def region_attr_changed(self): + def on_region_attr_changed(self): + self.guess_region_type() + self.commit() + + def on_region_type_changed(self, value): + self.str_type = value + self.commit() + + def guess_region_type(self): if self.data is None: return if self.str_attr: @@ -213,8 +222,8 @@ def region_attr_changed(self): str_type = next((k for k, v in self.ID_TYPE.items() if v == func), None) if str_type is not None and str_type != self.str_type: self.str_type = str_type + self.str_type_combo.setCurrentText(self.str_type) - self.commit() def commit(self): output = None @@ -330,8 +339,15 @@ def set_data(self, data): self.lat_attr, self.lon_attr = find_lat_lon(data) + self.str_type = None self.openContext(data) - self.region_attr_changed() + if self.str_type is None: + self.guess_region_type() + if self.str_type is None: + self.str_type = next(iter(self.ID_TYPE)) + self.str_type_combo.setCurrentText(self.str_type) + + self.commit() def clear(self): self.data = None diff --git a/orangecontrib/geo/widgets/tests/test_owgeocoding.py b/orangecontrib/geo/widgets/tests/test_owgeocoding.py index d8aa316..69167cb 100644 --- a/orangecontrib/geo/widgets/tests/test_owgeocoding.py +++ b/orangecontrib/geo/widgets/tests/test_owgeocoding.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access import unittest -from Orange.data import Table, Domain, DiscreteVariable +from Orange.data import Table, Domain, DiscreteVariable, StringVariable from Orange.widgets.tests.base import WidgetTest from orangecontrib.geo.widgets.owgeocoding import OWGeocoding from orangecontrib.geo.mapper import ToLatLon, CC_NAME_TO_CC_NAME @@ -73,6 +73,59 @@ def test_all_continuous(self): self.send_signal(self.widget.Inputs.data, housing) self.assertEqual(self.widget.is_decoding, 1) + def test_geo_region_guess(self): + countries = Table.from_list( + Domain([], [], [StringVariable("s")]), + [["Slovenia"], ["Germany"], ["France"], ["Italy"], ["Spain"]] + ) + cities = Table.from_list( + Domain([], [], [StringVariable("t")]), + [["Ljubljana"], ["Berlin"], ["Paris"], ["Rome"], ["Madrid"]] + ) + jibberish = Table.from_list( + Domain([], [], [StringVariable("u")]), + [["asdfas"], ["Adsfas"], ["agehra"]] + ) + jibberish_t = Table.from_list( + Domain([], [], [StringVariable("t")]), + [["asdfas"], ["Adsfas"], ["agehra"]] + ) + cities_u = Table.from_list( + Domain([], [], [StringVariable("u")]), + [["Ljubljana"], ["Berlin"], ["Paris"], ["Rome"], ["Madrid"]] + ) + + # check if the widget guesses the correct geo region + self.send_signal(self.widget.Inputs.data, countries) + self.assertEqual(self.widget.str_type, "Country name") + self.assertEqual(self.widget.str_type_combo.currentText(), "Country name") + m = self.get_output(self.widget.Outputs.coded_data).metas + self.assertAlmostEqual(m[0][1], 46.150207418500074) + self.assertAlmostEqual(m[4][2], -3.4893281046335867) + + # check if the widget guesses the correct geo region + self.send_signal(self.widget.Inputs.data, cities) + self.assertEqual(self.widget.str_type, "Major city (Europe)") + self.assertEqual(self.widget.str_type_combo.currentText(), "Major city (Europe)") + m = self.get_output(self.widget.Outputs.coded_data).metas + self.assertAlmostEqual(m[0][1], 46.150207418500074) + self.assertAlmostEqual(m[4][2], -3.4893281046335867) + + # cannot guess: use default, country name + self.send_signal(self.widget.Inputs.data, jibberish) + self.assertEqual(self.widget.str_type, "Country name") + self.assertEqual(self.widget.str_type_combo.currentText(), "Country name") + + # cannot guess, but can use context + self.send_signal(self.widget.Inputs.data, jibberish_t) + self.assertEqual(self.widget.str_type, "Major city (Europe)") + self.assertEqual(self.widget.str_type_combo.currentText(), "Major city (Europe)") + + # could guess, but context takes precedence + self.send_signal(self.widget.Inputs.data, cities_u) + self.assertEqual(self.widget.str_type, "Country name") + self.assertEqual(self.widget.str_type_combo.currentText(), "Country name") + def test_minimum_size(self): pass