Skip to content

Commit

Permalink
Test and Score: Sort numerically, not alphabetically
Browse files Browse the repository at this point in the history
  • Loading branch information
janezd committed Jul 30, 2019
1 parent 6e7e534 commit 53bf9af
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Orange/widgets/evaluate/tests/test_owtestlearners.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,10 @@ def __call__(self, data):
# 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(view.model().item(0, 0).text(), "VersicolorLearner")
self.assertEqual(view.model().index(0, 0).data(), "VersicolorLearner")

self.send_signal(self.widget.Inputs.test_data, versicolor, wait=5000)
self.assertEqual(view.model().item(0, 0).text(), "SetosaLearner")
self.assertEqual(view.model().index(0, 0).data(), "SetosaLearner")

self.widget.hide()

Expand Down
44 changes: 43 additions & 1 deletion Orange/widgets/evaluate/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import collections

from AnyQt.QtWidgets import QMenu
from AnyQt.QtCore import QPoint
from AnyQt.QtGui import QStandardItem
from AnyQt.QtCore import QPoint, Qt

from Orange.widgets.evaluate.utils import ScoreTable
from Orange.widgets.tests.base import GuiTest
Expand Down Expand Up @@ -70,5 +71,46 @@ def test_update_shown_columns(self):
not header.isSectionHidden(i),
msg="error in section {}({})".format(i, name))

def test_sorting(self):
def order(n=5):
return "".join(model.index(i, 0).data() for i in range(n))

score_table = ScoreTable(None)

data = [
["D", 11, 15.3],
["C", 5, -15.4],
["b", 20, None],
["A", None, None],
["E", "", 0]
]
for data_row in data:
row = [QStandardItem() if x is None
else QStandardItem(f"{x:.3f}") if isinstance(x, (int, float))
else QStandardItem(x)
for x in data_row]
score_table.model.appendRow(row)

model = score_table.view.model()

model.sort(0, Qt.AscendingOrder)
self.assertEqual(order(), "AbCDE")

model.sort(0, Qt.DescendingOrder)
self.assertEqual(order(), "EDCbA")

model.sort(1, Qt.AscendingOrder)
self.assertEqual(order(3), "CDb")

model.sort(1, Qt.DescendingOrder)
self.assertEqual(order(3), "bDC")

model.sort(2, Qt.AscendingOrder)
self.assertEqual(order(3), "CED")

model.sort(2, Qt.DescendingOrder)
self.assertEqual(order(3), "DEC")


if __name__ == "__main__":
unittest.main()
28 changes: 26 additions & 2 deletions Orange/widgets/evaluate/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from AnyQt.QtWidgets import QHeaderView, QStyledItemDelegate, QMenu
from AnyQt.QtGui import QStandardItemModel, QStandardItem
from AnyQt.QtCore import Qt, QSize, QObject, pyqtSignal as Signal
from AnyQt.QtCore import Qt, QSize, QObject, pyqtSignal as Signal, \
QSortFilterProxyModel
from sklearn.exceptions import UndefinedMetricWarning

from Orange.data import Variable, DiscreteVariable, ContinuousVariable
Expand Down Expand Up @@ -98,6 +99,27 @@ def thunked():
return thunked


class ScoreModel(QSortFilterProxyModel):
def lessThan(self, left, right):
def get_data(side):
data = side.data()
try:
return float(data)
except (TypeError, ValueError):
if isinstance(data, str):
return data.upper() # make model names case insensitive
else:
return data

left = get_data(left)
right = get_data(right)
if type(left) is not type(right) or left is None or right is None:
# put the one which is not a number (= an error) at the bottom
return isinstance(left, float) == (
self.sortOrder() == Qt.AscendingOrder)
return left < right


class ScoreTable(OWComponent, QObject):
shown_scores = \
Setting(set(chain(*BUILTIN_SCORERS_ORDER.values())))
Expand Down Expand Up @@ -125,7 +147,9 @@ def __init__(self, master):

self.model = QStandardItemModel(master)
self.model.setHorizontalHeaderLabels(["Method"])
self.view.setModel(self.model)
self.sorted_model = ScoreModel()
self.sorted_model.setSourceModel(self.model)
self.view.setModel(self.sorted_model)
self.view.setItemDelegate(self.ItemDelegate())

def _column_names(self):
Expand Down

0 comments on commit 53bf9af

Please sign in to comment.