Repository: biolab/orange3

Issue:
Table widget could output sorted data
#### Write a clear and concise description of what the problem is.

I sorted a table by some column (i.e. I sorted countries by number of confirmed Covid-19 cases per million). Then I wanted to know the rank of Slovenia. The table's horizontal header shows row numbers from the original data, which is correct, but not helpful in this case. So I hoped that if I connect another table widget to this one, I get re-ordered data. This is not the case.

#### Describe the solution you'd like

I'd like the output data in the some order as presented in the table, if this is not too difficult.



Discussion:
+1

Resolving patch:
diff --git a/Orange/widgets/data/owtable.py b/Orange/widgets/data/owtable.py
--- a/Orange/widgets/data/owtable.py
+++ b/Orange/widgets/data/owtable.py
@@ -602,6 +602,7 @@ def _setup_table_view(self, view, data):
         header = view.horizontalHeader()
         header.setSectionsClickable(is_sortable(data))
         header.setSortIndicatorShown(is_sortable(data))
+        header.sortIndicatorChanged.connect(self.update_selection)
 
         view.setModel(datamodel)
 
@@ -856,7 +857,6 @@ def get_selection(view):
         rows = numpy.array(rows, dtype=numpy.intp)
         # map the rows through the applied sorting (if any)
         rows = model.mapToSourceRows(rows)
-        rows.sort()
         rows = rows.tolist()
         return rows, cols
 
@@ -887,21 +887,6 @@ def commit(self):
             rowsel, colsel = self.get_selection(view)
             self.selected_rows, self.selected_cols = rowsel, colsel
 
-            def select(data, rows, domain):
-                """
-                Select the data subset with specified rows and domain subsets.
-
-                If either rows or domain is None they mean select all.
-                """
-                if rows is not None and domain is not None:
-                    return data.from_table(domain, data, rows)
-                elif rows is not None:
-                    return data.from_table(data.domain, rows)
-                elif domain is not None:
-                    return data.from_table(domain, data)
-                else:
-                    return data
-
             domain = table.domain
 
             if len(colsel) < len(domain) + len(domain.metas):
@@ -924,13 +909,11 @@ def select_vars(role):
                 metas = select_vars(TableModel.Meta)
                 domain = Orange.data.Domain(attrs, class_vars, metas)
 
-            # Avoid a copy if all/none rows are selected.
+            # Avoid a copy if none rows are selected.
             if not rowsel:
                 selected_data = None
-            elif len(rowsel) == len(table):
-                selected_data = select(table, None, domain)
             else:
-                selected_data = select(table, rowsel, domain)
+                selected_data = table.from_table(domain, table, rowsel)
 
         self.Outputs.selected_data.send(selected_data)
         self.Outputs.annotated_data.send(create_annotated_table(table, rowsel))
@@ -1097,21 +1080,6 @@ def is_sortable(table):
         return False
 
 
-def test_model():
-    app = QApplication([])
-    view = QTableView(
-        sortingEnabled=True
-    )
-    data = Orange.data.Table("lenses")
-    model = TableModel(data)
-
-    view.setModel(model)
-
-    view.show()
-    view.raise_()
-    return app.exec()
-
-
 if __name__ == "__main__":  # pragma: no cover
     WidgetPreview(OWDataTable).run(
         [(Table("iris"), "iris"),


Test patch:
diff --git a/Orange/widgets/data/tests/test_owtable.py b/Orange/widgets/data/tests/test_owtable.py
--- a/Orange/widgets/data/tests/test_owtable.py
+++ b/Orange/widgets/data/tests/test_owtable.py
@@ -1,5 +1,8 @@
 import unittest
+
+
 from unittest.mock import Mock, patch
+from AnyQt.QtCore import Qt
 
 from Orange.widgets.data.owtable import OWDataTable
 from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin
@@ -75,6 +78,29 @@ def test_pending_selection(self):
         output = self.get_output(widget.Outputs.selected_data)
         self.assertEqual(5, len(output))
 
+    def test_sorting(self):
+        self.send_signal(self.widget.Inputs.data, self.data)
+        self.widget.selected_rows = [0, 1, 2, 3, 4]
+        self.widget.selected_cols = list(range(len(self.data.domain)))
+        self.widget.set_selection()
+
+        output = self.get_output(self.widget.Outputs.selected_data)
+        output, _ = output.get_column_view(0)
+        output_original = output.tolist()
+
+        self.widget.tabs.currentWidget().sortByColumn(1, Qt.AscendingOrder)
+
+        output = self.get_output(self.widget.Outputs.selected_data)
+        output, _ = output.get_column_view(0)
+        output_sorted = output.tolist()
+        
+        # the two outputs should not be the same.
+        self.assertTrue(output_original != output_sorted)
+
+        # check if output after sorting is actually sorted.
+        self.assertTrue(sorted(output_original) == output_sorted)
+        self.assertTrue(sorted(output_sorted) == output_sorted)
+
 
 if __name__ == "__main__":
     unittest.main()