Repository: biolab/orange3

Issue:
BUG: Test & Score dialog Evaluation Results grid does not auto sort
Test & Score dialog Evaluation Results grid does not auto sort values based on selected column ordering. 

Environment: Orange 3.10, Windows 10 64bit Home, Anaconda

Thank you.

![orange3-autosort-not-working-annotated](https://user-images.githubusercontent.com/32625394/36818553-25ff0060-1cab-11e8-9f4a-83024f93bdbe.png)



Discussion:
I can't reproduce this on a simple iris example. Could you perhaps provide the entire workflow and/or see if this happens on some Orange dataset? Thank you!
I managed to reproduce it with the following workflow on heart-disease:

<img width="510" alt="screen shot 2018-03-01 at 10 42 32" src="https://user-images.githubusercontent.com/588601/36837675-560eafac-1d3d-11e8-821b-0c5fd3d7ccf7.png">

Upon resampling, scores change, but the table does not get re-sorted.
Thanks @astaric - that's exactly what I have, Data Sampler feeding T&S.

Resolving patch:
diff --git a/Orange/widgets/evaluate/owtestlearners.py b/Orange/widgets/evaluate/owtestlearners.py
--- a/Orange/widgets/evaluate/owtestlearners.py
+++ b/Orange/widgets/evaluate/owtestlearners.py
@@ -586,6 +586,13 @@ def _update_stats_model(self):
 
             model.appendRow(row)
 
+        # Resort rows based on current sorting
+        header = self.view.horizontalHeader()
+        model.sort(
+            header.sortIndicatorSection(),
+            header.sortIndicatorOrder()
+        )
+
         self.error("\n".join(errors), shown=bool(errors))
         self.Warning.scores_not_computed(shown=has_missing_scores)
 


Test patch:
diff --git a/Orange/widgets/evaluate/tests/test_owtestlearners.py b/Orange/widgets/evaluate/tests/test_owtestlearners.py
--- a/Orange/widgets/evaluate/tests/test_owtestlearners.py
+++ b/Orange/widgets/evaluate/tests/test_owtestlearners.py
@@ -5,9 +5,11 @@
 
 import numpy as np
 from AnyQt.QtWidgets import QMenu
-from AnyQt.QtCore import QPoint
+from AnyQt.QtCore import QPoint, Qt
+from AnyQt.QtTest import QTest
 
 from Orange.classification import MajorityLearner, LogisticRegressionLearner
+from Orange.classification.majority import ConstantModel
 from Orange.data import Table, Domain, DiscreteVariable, ContinuousVariable
 from Orange.evaluation import Results, TestOnTestData
 from Orange.evaluation.scoring import ClassificationScore, RegressionScore, \
@@ -19,6 +21,7 @@
 from Orange.widgets.settings import (
     ClassValuesContextHandler, PerfectDomainContextHandler)
 from Orange.widgets.tests.base import WidgetTest
+from Orange.widgets.tests.utils import simulate
 
 
 class TestOWTestLearners(WidgetTest):
@@ -258,16 +261,13 @@ def test_target_changing(self):
 
         average_auc = float(w.view.model().item(0, 1).text())
 
-        w.class_selection = "Iris-setosa"
-        w._on_target_class_changed()
+        simulate.combobox_activate_item(w.controls.class_selection, "Iris-setosa")
         setosa_auc = float(w.view.model().item(0, 1).text())
 
-        w.class_selection = "Iris-versicolor"
-        w._on_target_class_changed()
+        simulate.combobox_activate_item(w.controls.class_selection, "Iris-versicolor")
         versicolor_auc = float(w.view.model().item(0, 1).text())
 
-        w.class_selection = "Iris-virginica"
-        w._on_target_class_changed()
+        simulate.combobox_activate_item(w.controls.class_selection, "Iris-virginica")
         virginica_auc = float(w.view.model().item(0, 1).text())
 
         self.assertGreater(average_auc, versicolor_auc)
@@ -276,6 +276,51 @@ def test_target_changing(self):
         self.assertGreater(setosa_auc, versicolor_auc)
         self.assertGreater(setosa_auc, virginica_auc)
 
+    def test_resort_on_data_change(self):
+        iris = Table("iris")
+        # one example is included from the other class
+        # to keep F1 from complaining
+        setosa = iris[:51]
+        versicolor = iris[49:100]
+
+        class SetosaLearner:
+            def __call__(self, data):
+                model = ConstantModel([1., 0, 0])
+                model.domain = iris.domain
+                return model
+
+        class VersicolorLearner:
+            def __call__(self, data):
+                model = ConstantModel([0, 1., 0])
+                model.domain = iris.domain
+                return model
+
+        # this is done manually to avoid multiple computations
+        self.widget.resampling = 5
+        self.widget.set_train_data(iris)
+        self.widget.set_learner(SetosaLearner(), 1)
+        self.widget.set_learner(VersicolorLearner(), 2)
+
+        self.send_signal(self.widget.Inputs.test_data, setosa, wait=5000)
+
+        self.widget.show()
+        header = self.widget.view.horizontalHeader()
+        QTest.mouseClick(header.viewport(), Qt.LeftButton)
+
+        # Ensure that the click on header caused an ascending sort
+        # Ascending sort means that wrong model should be listed first
+        self.assertEqual(header.sortIndicatorOrder(), Qt.AscendingOrder)
+        self.assertEqual(
+            self.widget.view.model().item(0, 0).text(),
+            "VersicolorLearner")
+
+        self.send_signal(self.widget.Inputs.test_data, versicolor, wait=5000)
+        self.assertEqual(
+            self.widget.view.model().item(0, 0).text(),
+            "SetosaLearner")
+
+        self.widget.hide()
+
 
 class TestHelpers(unittest.TestCase):
     def test_results_one_vs_rest(self):