Scores are sorted correctly with N/A and Infinity values correctly handled

This commit is contained in:
Filip Gralinski 2018-09-08 09:12:47 +02:00
parent 1aafff1808
commit 858f494047
6 changed files with 190 additions and 3 deletions

View File

@ -37,6 +37,11 @@ import System.IO.Unsafe (unsafePerformIO)
import Text.Regex.TDFA import Text.Regex.TDFA
import Data.Aeson.Types
import GEval.Core
import qualified Data.Vector as DV
arena :: Handler FilePath arena :: Handler FilePath
arena = do arena = do
app <- getYesod app <- getYesod
@ -386,3 +391,13 @@ unwantedLocalIds = ["git",
isLocalIdAcceptable :: Text -> Bool isLocalIdAcceptable :: Text -> Bool
isLocalIdAcceptable localId = isLocalIdAcceptable localId =
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds) match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
-- need to transfer the information into a JS script
getIsHigherTheBetterArray :: [Test] -> Value
getIsHigherTheBetterArray = Array
. DV.fromList
. map (convertIsHigherTheBetter
. getMetricOrdering
. testMetric)
where convertIsHigherTheBetter TheHigherTheBetter = Bool True
convertIsHigherTheBetter _ = Bool False

View File

@ -103,6 +103,8 @@ showChallengeWidget muserId
= $(widgetFile "show-challenge") = $(widgetFile "show-challenge")
where leaderboardWithRanks = zip [1..] leaderboard where leaderboardWithRanks = zip [1..] leaderboard
maybeRepoLink = getRepoLink repo maybeRepoLink = getRepoLink repo
delta = Number 4
higherTheBetterArray = getIsHigherTheBetterArray [test]
getRepoLink :: Repo -> Maybe Text getRepoLink :: Repo -> Maybe Text
getRepoLink repo getRepoLink repo
@ -570,6 +572,7 @@ getAllParams entries = sort
$ concat $ concat
$ map (\entry -> map (parameterName . entityVal) (tableEntryParams entry)) entries $ map (\entry -> map (parameterName . entityVal) (tableEntryParams entry)) entries
challengeAllSubmissionsWidget :: Maybe UserId challengeAllSubmissionsWidget :: Maybe UserId
-> Challenge -> Challenge
-> RepoScheme -> RepoScheme
@ -580,6 +583,8 @@ challengeAllSubmissionsWidget :: Maybe UserId
-> WidgetFor App () -> WidgetFor App ()
challengeAllSubmissionsWidget muserId challenge scheme challengeRepo submissions tests params = challengeAllSubmissionsWidget muserId challenge scheme challengeRepo submissions tests params =
$(widgetFile "challenge-all-submissions") $(widgetFile "challenge-all-submissions")
where delta = Number 3
higherTheBetterArray = getIsHigherTheBetterArray $ map entityVal tests
paramGraphsWidget :: Challenge -> [Entity Test] -> [Text] -> WidgetFor App () paramGraphsWidget :: Challenge -> [Entity Test] -> [Text] -> WidgetFor App ()
paramGraphsWidget challenge tests params = $(widgetFile "param-graphs") paramGraphsWidget challenge tests params = $(widgetFile "param-graphs")

View File

@ -0,0 +1,158 @@
/**
* Based on absolute-order Datatables plug-in by Allan Jardine
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net')(root, $).$;
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
function extractValue(a) {
if ( typeof a === 'string' ) {
var m = a.match(/<span title="([^"]+)"/)
if (m != null) {
return m[1]
}
} else {
return a
}
}
function extractNumber(a) {
// Cast as a number if required
if ( typeof a === 'string' ) {
return (a.replace(/[^\d\-\.]/g, '') * 1);
} else {
return a;
}
}
function toSign(a, b) {
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
// Unique value allowing multiple absolute ordering use cases on a single page.
var _unique = 0;
// Function to encapsulate code that is common to both the string and number
// ordering plug-ins.
var _setup = function ( isHigherTheBetter ) {
var o = {
name: 'absoluteOrder'+(_unique++),
alwaysHighest: {},
alwaysLowest: {}
};
// In order to provide performance, the symbols that are to be looked for
// are stored as parameter keys in an object, allowing O(1) lookup, rather
// than O(n) if it were in an array.
o.alwaysHighest["Infinity"] = 1
if (isHigherTheBetter) {
o.alwaysLowest["N/A"] = -1
} else {
o.alwaysHighest["N/A"] = 2
}
// Ascending ordering method
o.asc = function ( a, b ) {
a = extractValue(a)
b = extractValue(b)
if ( o.alwaysLowest[ a ] && o.alwaysLowest[ b ] ) {
return toSign(o.alwaysLowest[a], o.alwaysLowest[b]);
}
else if ( o.alwaysHighest[ a ] && o.alwaysHighest[ b ] ) {
return toSign(o.alwaysHighest[a], o.alwaysHighest[b]);
}
else if ( o.alwaysLowest[ a ] || o.alwaysHighest[ b ] ) {
return -1;
}
else if ( o.alwaysHighest[ a ] || o.alwaysLowest[ b ] ) {
return 1;
}
a = extractNumber(a);
b = extractNumber(b);
return toSign(a, b);
};
// Descending ordering method
o.desc = function ( a, b ) {
a = extractValue(a)
b = extractValue(b)
if ( o.alwaysLowest[ a ] && o.alwaysLowest[ b ] ) {
return toSign(o.alwaysLowest[b], o.alwaysLowest[a]);
}
else if ( o.alwaysHighest[ a ] && o.alwaysHighest[ b ] ) {
return toSign(o.alwaysHighest[b], o.alwaysHighest[a]);
}
else if ( o.alwaysLowest[ a ] || o.alwaysHighest[ b ] ) {
return 1;
}
else if ( o.alwaysHighest[ a ] || o.alwaysLowest[ b ] ) {
return -1;
}
a = extractNumber(a);
b = extractNumber(b);
return toSign(b, a);
};
return o;
};
// Number based ordering - strips out everything but the number information
$.fn.dataTable.extendedOrderNumber = function ( isHigherTheBetter ) {
var conf = _setup( isHigherTheBetter );
$.fn.dataTable.ext.type.order[ conf.name+'-asc' ] = function ( a, b ) {
return conf.asc( a, b, true );
};
$.fn.dataTable.ext.type.order[ conf.name+'-desc' ] = function ( a, b ) {
return conf.desc( a, b, true );
};
return conf.name;
};
$.fn.dataTable.getColumnDef = function (ix, isHigherTheBetter) {
return {
type: $.fn.dataTable.extendedOrderNumber(isHigherTheBetter),
targets: ix
};
}
$.fn.dataTable.getColumnDefs = function (delta, isHigherTheBetterArray) {
var ix = delta;
return isHigherTheBetterArray.map(isHigherTheBetter => $.fn.dataTable.getColumnDef(ix++, isHigherTheBetter));
};
}));

View File

@ -5,8 +5,12 @@
} }
}); });
var columnDefs = $.fn.dataTable.getColumnDefs(#{delta}, #{higherTheBetterArray});
$(document).ready(function() { $(document).ready(function() {
$("table").DataTable({ $("table").DataTable({
'pageLength': 50, 'pageLength': 50,
'order': [[1, 'desc']]}); 'order': [[1, 'desc']],
'columnDefs': columnDefs
});
} ); } );

View File

@ -16,6 +16,7 @@ $newline never
<link rel="stylesheet" type="text/css" href="/static/css/datatables.min.css"/> <link rel="stylesheet" type="text/css" href="/static/css/datatables.min.css"/>
<link rel="stylesheet" type="text/css" href="/static/css/c3.min.css"/> <link rel="stylesheet" type="text/css" href="/static/css/c3.min.css"/>
<script type="text/javascript" src="/static/js/datatables.min.js"> <script type="text/javascript" src="/static/js/datatables.min.js">
<script type="text/javascript" src="/static/js/datatables-extended.js">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

View File

@ -5,7 +5,11 @@
} }
}); });
var columnDefs = $.fn.dataTable.getColumnDefs(#{delta}, #{higherTheBetterArray});
$(document).ready(function() { $(document).ready(function() {
$("table").DataTable({ $("table").DataTable({
'pageLength': 50}); 'pageLength': 50,
'columnDefs': columnDefs
})
}); });