Skip to content

Commit 6d8d85e

Browse files
authored
Merge pull request #7123 from janezd/predictions-no-literals
[FIX] Predictions: allow loading of workflows saved in a localized version (target class setting fix)
2 parents 5f5dcc8 + a57c769 commit 6d8d85e

3 files changed

Lines changed: 73 additions & 7 deletions

File tree

Orange/widgets/evaluate/owpredictions.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class OWPredictions(OWWidget):
6767
description = "Display predictions of models for an input dataset."
6868
keywords = "predictions"
6969

70-
settings_version = 2
70+
settings_version = 3
7171

7272
want_control_area = False
7373

@@ -105,13 +105,13 @@ class Error(OWWidget.Error):
105105
"Show probabilities for classes in data that are also\n"
106106
"known to the model"
107107
]
108+
TARGET_AVERAGE = "(Average over classes)"
108109

109110
NO_PROBS, DATA_PROBS, MODEL_PROBS, BOTH_PROBS = range(4)
110111
shown_probs = settings.ContextSetting(NO_PROBS)
111112
selection = settings.Setting([], schema_only=True)
112113
show_scores = settings.Setting(True)
113-
TARGET_AVERAGE = "(Average over classes)"
114-
target_class = settings.ContextSetting(TARGET_AVERAGE)
114+
target_class = settings.ContextSetting("")
115115
show_probability_errors = settings.ContextSetting(True)
116116
show_reg_errors = settings.ContextSetting(DIFF_ERROR)
117117

@@ -174,7 +174,8 @@ def __init__(self):
174174
gui.widgetLabel(scoreopts, "Target class:"),
175175
gui.comboBox(
176176
scoreopts, self, "target_class", items=[], contentsLength=30,
177-
sendSelectedValue=True, callback=self._on_target_changed)
177+
sendSelectedValue=True, callback=self._on_target_changed,
178+
emptyString=self.TARGET_AVERAGE)
178179
]
179180
gui.rubber(scoreopts)
180181

@@ -311,7 +312,7 @@ def _set_target_combos(self):
311312
for i, tip in enumerate(self.PROB_TOOLTIPS):
312313
prob_combo.setItemData(i, tip, Qt.ToolTipRole)
313314
self.shown_probs = self.DATA_PROBS
314-
self.target_class = self.TARGET_AVERAGE
315+
self.target_class = ""
315316
else:
316317
self.shown_probs = self.NO_PROBS
317318
model = prob_combo.model()
@@ -433,7 +434,7 @@ def _call_predictors(self):
433434

434435
def _update_scores(self):
435436
model = self.score_table.model
436-
if self.is_discrete_class and self.target_class != self.TARGET_AVERAGE:
437+
if self.is_discrete_class and self.target_class:
437438
target = self.class_var.values.index(self.target_class)
438439
else:
439440
target = None
@@ -971,7 +972,8 @@ def merge_data_with_predictions():
971972

972973
self.report_name("Scores")
973974
if self.is_discrete_class:
974-
self.report_items([("Target class", self.target_class)])
975+
self.report_items([("Target class",
976+
self.target_class or self.TARGET_AVERAGE)])
975977
self.report_table(self.score_table.view)
976978

977979
def resizeEvent(self, event):
@@ -988,6 +990,19 @@ def migrate_settings(cls, settings, version):
988990
if "score_table" in settings:
989991
ScoreTable.migrate_to_show_scores_hints(settings["score_table"])
990992

993+
@classmethod
994+
def migrate_context(cls, context, version):
995+
if version < 3:
996+
target_class = context.values.get("target_class")
997+
# The second condition is a workaround if the workflow is opened
998+
# in a wrong language. Assuming that contexts (and other code) works
999+
# target_class will always appear among values, and if it doesn't,
1000+
# it must be because of averaging.
1001+
# The first condition is also covered by the second, but let it
1002+
# be there for clarity.
1003+
if target_class == cls.TARGET_AVERAGE \
1004+
or target_class not in context.classes:
1005+
context.values["target_class"] = ""
9911006

9921007
class ItemDelegate(TableDataDelegate):
9931008
def initStyleOption(self, option, index):

Orange/widgets/evaluate/tests/test_owpredictions.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from AnyQt.QtCore import QItemSelectionModel, QItemSelection, Qt, QRect
1414
from AnyQt.QtWidgets import QToolTip
1515

16+
from orangewidget.settings import Context
17+
1618
from Orange.base import Model
1719
from Orange.classification import LogisticRegressionLearner, NaiveBayesLearner
1820
from Orange.classification.majority import ConstantModel, MajorityLearner
@@ -1288,6 +1290,53 @@ def test_migrate_shown_scores(self):
12881290
self.widget.migrate_settings(settings, 1)
12891291
self.assertTrue(settings["score_table"]["show_score_hints"]["Sensitivity"])
12901292

1293+
def test_migrate_context_2_3(self):
1294+
settings = {
1295+
'controlAreaVisible': True, 'selection': [],
1296+
'show_scores': True,
1297+
'score_table': {
1298+
'show_score_hints': {
1299+
'Model_': True, 'Train_': False, 'Test_': False,
1300+
'CA': True, 'PrecisionRecallFSupport': True,
1301+
'TargetScore': True, 'Precision': True,
1302+
'Recall': True, 'F1': True, 'AUC': True,
1303+
'LogLoss': False, 'Specificity': False,
1304+
'MatthewsCorrCoefficient': True, 'MSE': True,
1305+
'RMSE': True, 'MAE': True, 'MAPE': True, 'R2': True,
1306+
'CVRMSE': False, 'ClusteringScore': True,
1307+
'Silhouette': True, 'AdjustedMutualInfoScore': True}},
1308+
'context_settings': [
1309+
Context(
1310+
classes=('Iris-setosa',
1311+
'Iris-versicolor',
1312+
'Iris-virginica'),
1313+
values={'show_probability_errors': True,
1314+
'show_reg_errors': 1,
1315+
'shown_probs': 1,
1316+
'score_table': {},
1317+
'target_class': '(Average over classes)',
1318+
'__version__': 2})],
1319+
'__version__': 2,
1320+
}
1321+
1322+
widget = self.create_widget(OWPredictions, stored_settings=settings)
1323+
self.send_signal(widget.Inputs.data, self.iris)
1324+
self.assertEqual(widget.target_class, "")
1325+
1326+
settings["context_settings"][0].values["target_class"] = "Iris-versicolor"
1327+
settings["__version__"] = 2
1328+
widget = self.create_widget(OWPredictions, stored_settings=settings)
1329+
self.send_signal(widget.Inputs.data, self.iris)
1330+
self.assertEqual(widget.target_class, "Iris-versicolor")
1331+
1332+
# Test fallback for older workflows opened in wrong language
1333+
settings["context_settings"][0].values["target_class"] = "Povprečje"
1334+
settings["__version__"] = 2
1335+
widget = self.create_widget(OWPredictions, stored_settings=settings)
1336+
self.send_signal(widget.Inputs.data, self.iris)
1337+
self.assertEqual(widget.target_class, "")
1338+
1339+
12911340
def test_output_error_reg(self):
12921341
data = self.housing
12931342
lin_reg = LinearRegressionLearner()

i18n/si/msgs.jaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9363,6 +9363,8 @@ widgets/evaluate/owpredictions.py:
93639363
Target class: Ciljni razred
93649364
def `migrate_settings`:
93659365
score_table: false
9366+
def `migrate_context`:
9367+
target_class: false
93669368
class `ClassificationItemDelegate`:
93679369
def `__init__`:
93689370
' : ': false

0 commit comments

Comments
 (0)