Show all main metrics in the leaderboard

This commit is contained in:
Filip Gralinski 2018-09-08 19:21:06 +02:00
parent e20e8dfa63
commit 20fc29159f
6 changed files with 50 additions and 38 deletions

View File

@ -3,7 +3,7 @@ module Handler.Graph where
import Import import Import
import Handler.Tables import Handler.Tables
import Handler.Shared (formatParameter, formatScore) import Handler.Shared (formatParameter, formatScore, getMainTest)
import Data.Maybe import Data.Maybe
import Data.List ((!!)) import Data.List ((!!))
import Database.Persist.Sql import Database.Persist.Sql
@ -23,7 +23,7 @@ getChallengeParamGraphDataR challengeName testId paramName = do
(Entity challengeId _) <- runDB $ getBy404 $ UniqueName challengeName (Entity challengeId _) <- runDB $ getBy404 $ UniqueName challengeName
test <- runDB $ get404 testId test <- runDB $ get404 testId
(entries, tests) <- getChallengeSubmissionInfos (const True) challengeId (entries, _) <- getChallengeSubmissionInfos (const True) challengeId
let values = map (findParamValue paramName) entries let values = map (findParamValue paramName) entries
@ -72,23 +72,29 @@ submissionsToJSON :: ((Entity Submission) -> Bool) -> Text -> Handler Value
submissionsToJSON condition challengeName = do submissionsToJSON condition challengeName = do
(Entity challengeId _) <- runDB $ getBy404 $ UniqueName challengeName (Entity challengeId _) <- runDB $ getBy404 $ UniqueName challengeName
(_, entries, _) <- getLeaderboardEntriesByCriterion challengeId (entries, _) <- getLeaderboardEntriesByCriterion challengeId
condition condition
(\(TableEntry (Entity submissionId _) _ _ _ _ _) -> submissionId) (\(TableEntry (Entity submissionId _) _ _ _ _ _) -> submissionId)
let naturalRange = getNaturalRange entries
tests <- runDB $ selectList [TestChallenge ==. challengeId] []
let mainTestId = entityKey $ getMainTest tests
let naturalRange = getNaturalRange mainTestId entries
let submissionIds = map leaderboardBestSubmissionId entries let submissionIds = map leaderboardBestSubmissionId entries
forks <- runDB $ selectList [ForkSource <-. submissionIds, ForkTarget <-. submissionIds] [] forks <- runDB $ selectList [ForkSource <-. submissionIds, ForkTarget <-. submissionIds] []
return $ object [ "nodes" .= (Data.Maybe.catMaybes $ map (auxSubmissionToNode naturalRange) $ entries), return $ object [ "nodes" .= (Data.Maybe.catMaybes
$ map (auxSubmissionToNode mainTestId naturalRange)
$ entries),
"edges" .= map forkToEdge forks ] "edges" .= map forkToEdge forks ]
getNaturalRange :: [LeaderboardEntry] -> Double getNaturalRange :: TestId -> [LeaderboardEntry] -> Double
getNaturalRange entries = 2.0 * (interQuantile $ Data.Maybe.catMaybes $ map (evaluationScore . leaderboardEvaluation) entries) getNaturalRange testId entries = 2.0 * (interQuantile $ Data.Maybe.catMaybes $ map (\entry -> evaluationScore $ ((leaderboardEvaluationMap entry) M.! testId)) entries)
auxSubmissionToNode :: Double -> LeaderboardEntry -> Maybe Value auxSubmissionToNode :: TestId -> Double -> LeaderboardEntry -> Maybe Value
auxSubmissionToNode naturalRange entry = case evaluationScore $ leaderboardEvaluation entry of auxSubmissionToNode testId naturalRange entry = case evaluationScore $ ((leaderboardEvaluationMap entry) M.! testId) of
Just score -> Just $ object [ Just score -> Just $ object [
"id" .= (nodeId $ leaderboardBestSubmissionId entry), "id" .= (nodeId $ leaderboardBestSubmissionId entry),
"x" .= (stampToX $ submissionStamp $ leaderboardBestSubmission entry), "x" .= (stampToX $ submissionStamp $ leaderboardBestSubmission entry),

View File

@ -53,11 +53,11 @@ getPresentationDATeCH2017R = do
presentationLayout $(widgetFile "presentation-datech-2017") presentationLayout $(widgetFile "presentation-datech-2017")
getSampleLeaderboard :: Text -> HandlerFor App (WidgetT App IO ()) getSampleLeaderboard :: Text -> HandlerFor App (WidgetFor App ())
getSampleLeaderboard name = do getSampleLeaderboard name = do
(Entity challengeId challenge) <- runDB $ getBy404 $ UniqueName name (Entity challengeId challenge) <- runDB $ getBy404 $ UniqueName name
(test, leaderboard, _) <- getLeaderboardEntries challengeId (leaderboard, (_, tests)) <- getLeaderboardEntries challengeId
let leaderboardWithRanks = zip [1..] (take 10 leaderboard) let leaderboardWithRanks = zip [1..] (take 10 leaderboard)
app <- getYesod app <- getYesod
@ -67,7 +67,7 @@ getSampleLeaderboard name = do
return $ Table.buildBootstrap (leaderboardTable Nothing return $ Table.buildBootstrap (leaderboardTable Nothing
(challengeName challenge) (challengeName challenge)
scheme challengeRepo test) scheme challengeRepo tests)
leaderboardWithRanks leaderboardWithRanks
presentationLayout widget = do presentationLayout widget = do

View File

@ -330,7 +330,7 @@ getMainTest tests = DL.maximumBy testComparator tests
-- get all the non-dev tests starting with the one with the highest priorty -- get all the non-dev tests starting with the one with the highest priorty
-- (or all the tests if there are no non-dev tests) -- (or all the tests if there are no non-dev tests)
getMainTests :: [Entity Test] -> [Entity Test] getMainTests :: [Entity Test] -> [Entity Test]
getMainTests tests = sortBy (flip testComparator) tests' getMainTests tests = sortBy testComparator tests'
where tests' = if null tests'' where tests' = if null tests''
then tests then tests
else tests'' else tests''

View File

@ -46,7 +46,7 @@ getShowChallengeR :: Text -> Handler Html
getShowChallengeR name = do getShowChallengeR name = do
(Entity challengeId challenge) <- runDB $ getBy404 $ UniqueName name (Entity challengeId challenge) <- runDB $ getBy404 $ UniqueName name
Just repo <- runDB $ get $ challengePublicRepo challenge Just repo <- runDB $ get $ challengePublicRepo challenge
(mainTest, leaderboard, (entries, tests)) <- getLeaderboardEntries challengeId (leaderboard, (entries, tests)) <- getLeaderboardEntries challengeId
mauth <- maybeAuth mauth <- maybeAuth
let muserId = (\(Entity uid _) -> uid) <$> mauth let muserId = (\(Entity uid _) -> uid) <$> mauth
@ -60,7 +60,6 @@ getShowChallengeR name = do
challengeLayout True challenge (showChallengeWidget muserId challengeLayout True challenge (showChallengeWidget muserId
challenge scheme challenge scheme
challengeRepo challengeRepo
mainTest
repo repo
leaderboard leaderboard
params params
@ -85,7 +84,6 @@ showChallengeWidget :: Maybe UserId
-> Challenge -> Challenge
-> RepoScheme -> RepoScheme
-> Repo -> Repo
-> Test
-> Repo -> Repo
-> [LeaderboardEntry] -> [LeaderboardEntry]
-> [Text] -> [Text]
@ -95,7 +93,6 @@ showChallengeWidget muserId
challenge challenge
scheme scheme
challengeRepo challengeRepo
test
repo repo
leaderboard leaderboard
params params
@ -104,7 +101,7 @@ showChallengeWidget muserId
where leaderboardWithRanks = zip [1..] leaderboard where leaderboardWithRanks = zip [1..] leaderboard
maybeRepoLink = getRepoLink repo maybeRepoLink = getRepoLink repo
delta = Number 4 delta = Number 4
higherTheBetterArray = getIsHigherTheBetterArray [test] higherTheBetterArray = getIsHigherTheBetterArray $ map entityVal tests
getRepoLink :: Repo -> Maybe Text getRepoLink :: Repo -> Maybe Text
getRepoLink repo getRepoLink repo
@ -589,7 +586,7 @@ challengeAllSubmissionsWidget muserId challenge scheme challengeRepo submissions
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")
where chartJSs = getChartJss challenge selectedTests params where chartJSs = getChartJss challenge selectedTests params
selectedTests = getMainTests tests selectedTests = reverse $ getMainTests tests
getChartJss :: Challenge -> [Entity Test] -> [Text] -> JavascriptUrl (Route App) getChartJss :: Challenge -> [Entity Test] -> [Text] -> JavascriptUrl (Route App)
getChartJss challenge tests params = getChartJss challenge tests params =

View File

@ -29,7 +29,7 @@ data LeaderboardEntry = LeaderboardEntry {
leaderboardBestSubmissionId :: SubmissionId, leaderboardBestSubmissionId :: SubmissionId,
leaderboardBestVariant :: Variant, leaderboardBestVariant :: Variant,
leaderboardBestVariantId :: VariantId, leaderboardBestVariantId :: VariantId,
leaderboardEvaluation :: Evaluation, leaderboardEvaluationMap :: Map (Key Test) Evaluation,
leaderboardNumberOfSubmissions :: Int, leaderboardNumberOfSubmissions :: Int,
leaderboardTags :: [(Entity Tag, Entity SubmissionTag)], leaderboardTags :: [(Entity Tag, Entity SubmissionTag)],
leaderboardParams :: [Parameter] leaderboardParams :: [Parameter]
@ -75,13 +75,13 @@ descriptionToBeShown s v params = (submissionDescription s) ++ (Data.Text.pack v
extractScore :: Key Test -> TableEntry -> Maybe Evaluation extractScore :: Key Test -> TableEntry -> Maybe Evaluation
extractScore k (TableEntry _ _ _ m _ _) = lookup k m extractScore k (TableEntry _ _ _ m _ _) = lookup k m
leaderboardTable :: Maybe UserId -> Text -> RepoScheme -> Repo -> Test -> Table App (Int, LeaderboardEntry) leaderboardTable :: Maybe UserId -> Text -> RepoScheme -> Repo -> [Entity Test] -> Table App (Int, LeaderboardEntry)
leaderboardTable mauthId challengeName repoScheme challengeRepo test = mempty leaderboardTable mauthId challengeName repoScheme challengeRepo tests = mempty
++ Table.int "#" fst ++ Table.int "#" fst
++ Table.text "submitter" (formatSubmitter . leaderboardUser . snd) ++ Table.text "submitter" (formatSubmitter . leaderboardUser . snd)
++ timestampCell "when" (submissionStamp . leaderboardBestSubmission . snd) ++ timestampCell "when" (submissionStamp . leaderboardBestSubmission . snd)
++ leaderboardDescriptionCell ++ leaderboardDescriptionCell
++ resultCell test ((\e -> Just e) . leaderboardEvaluation . snd) ++ mconcat (map (\(Entity k t) -> resultCell t (extractScoreFromLeaderboardEntry k . snd)) tests)
++ Table.int "×" (leaderboardNumberOfSubmissions . snd) ++ Table.int "×" (leaderboardNumberOfSubmissions . snd)
++ statusCell challengeName repoScheme challengeRepo (\(_, e) -> (leaderboardBestSubmissionId e, ++ statusCell challengeName repoScheme challengeRepo (\(_, e) -> (leaderboardBestSubmissionId e,
leaderboardBestSubmission e, leaderboardBestSubmission e,
@ -90,6 +90,9 @@ leaderboardTable mauthId challengeName repoScheme challengeRepo test = mempty
leaderboardUserId e, leaderboardUserId e,
mauthId)) mauthId))
extractScoreFromLeaderboardEntry :: Key Test -> LeaderboardEntry -> Maybe Evaluation
extractScoreFromLeaderboardEntry k entry = lookup k (leaderboardEvaluationMap entry)
leaderboardDescriptionCell :: Table site (a, LeaderboardEntry) leaderboardDescriptionCell :: Table site (a, LeaderboardEntry)
leaderboardDescriptionCell = Table.widget "description" ( leaderboardDescriptionCell = Table.widget "description" (
\(_,entry) -> fragmentWithSubmissionTags (descriptionToBeShown (leaderboardBestSubmission entry) \(_,entry) -> fragmentWithSubmissionTags (descriptionToBeShown (leaderboardBestSubmission entry)
@ -137,26 +140,29 @@ getAuxSubmissionEnts testId evaluationMaps = map processEvaluationMap evaluation
getLeaderboardEntriesByCriterion :: (Ord a) => Key Challenge getLeaderboardEntriesByCriterion :: (Ord a) => Key Challenge
-> ((Entity Submission) -> Bool) -> ((Entity Submission) -> Bool)
-> (TableEntry -> a) -> (TableEntry -> a)
-> Handler (Test, [LeaderboardEntry], ([TableEntry], [Entity Test])) -> Handler ([LeaderboardEntry], ([TableEntry], [Entity Test]))
getLeaderboardEntriesByCriterion challengeId condition selector = do getLeaderboardEntriesByCriterion challengeId condition selector = do
infos@(evaluationMaps, tests) <- getChallengeSubmissionInfos condition challengeId (evaluationMaps, tests) <- getChallengeSubmissionInfos condition challengeId
let mainTests = getMainTests tests
let mainTestEnt = getMainTest tests let mainTestEnt = getMainTest tests
let (Entity mainTestId mainTest) = mainTestEnt let (Entity mainTestId mainTest) = mainTestEnt
let auxItems = map (\i -> (selector i, [i])) $ filter (\(TableEntry _ _ _ em _ _) -> member mainTestId em) $ evaluationMaps let auxItems = map (\i -> (selector i, [i]))
$ filter (\(TableEntry _ _ _ em _ _) -> member mainTestId em)
$ evaluationMaps
let auxItemsMap = Map.fromListWith (++) auxItems let auxItemsMap = Map.fromListWith (++) auxItems
let entryComparator a b = (compareResult mainTest) (evaluationScore $ leaderboardEvaluation a) (evaluationScore $ leaderboardEvaluation b) let entryComparator a b = (compareResult mainTest) (evaluationScore $ leaderboardEvaluationMap a Map.! mainTestId)
entries' <- mapM (toLeaderboardEntry challengeId mainTestEnt) (evaluationScore $ leaderboardEvaluationMap b Map.! mainTestId)
entries' <- mapM (toLeaderboardEntry challengeId mainTests)
$ filter (\ll -> not (null ll)) $ filter (\ll -> not (null ll))
$ map snd $ map snd
$ Map.toList auxItemsMap $ Map.toList auxItemsMap
let entries = sortBy (flip entryComparator) entries' let entries = sortBy (flip entryComparator) entries'
return (mainTest, entries, infos) return (entries, (evaluationMaps, mainTests))
toLeaderboardEntry :: (BaseBackend (YesodPersistBackend site) ~ SqlBackend, PersistQueryRead (YesodPersistBackend site), YesodPersist site, Foldable t) => Key Challenge -> Entity Test -> t TableEntry -> HandlerFor site LeaderboardEntry toLeaderboardEntry :: (BaseBackend (YesodPersistBackend site) ~ SqlBackend, PersistQueryRead (YesodPersistBackend site), YesodPersist site, Foldable t) => Key Challenge -> [Entity Test] -> t TableEntry -> HandlerFor site LeaderboardEntry
toLeaderboardEntry challengeId (Entity mainTestId mainTest) ss = do toLeaderboardEntry challengeId tests ss = do
let bestOne = DL.maximumBy submissionComparator ss let bestOne = DL.maximumBy submissionComparator ss
let (TableEntry bestSubmission bestVariant user evals _ _) = bestOne let (TableEntry bestSubmission bestVariant user evals _ _) = bestOne
let bestEvaluation = evals Map.! mainTestId
let submissionId = entityKey bestSubmission let submissionId = entityKey bestSubmission
tagEnts <- runDB $ getTags submissionId tagEnts <- runDB $ getTags submissionId
@ -173,14 +179,17 @@ toLeaderboardEntry challengeId (Entity mainTestId mainTest) ss = do
leaderboardBestSubmissionId = entityKey bestSubmission, leaderboardBestSubmissionId = entityKey bestSubmission,
leaderboardBestVariant = entityVal bestVariant, leaderboardBestVariant = entityVal bestVariant,
leaderboardBestVariantId = entityKey bestVariant, leaderboardBestVariantId = entityKey bestVariant,
leaderboardEvaluation = bestEvaluation, leaderboardEvaluationMap = evals,
leaderboardNumberOfSubmissions = length allUserSubmissions, leaderboardNumberOfSubmissions = length allUserSubmissions,
leaderboardTags = tagEnts, leaderboardTags = tagEnts,
leaderboardParams = map entityVal parameters leaderboardParams = map entityVal parameters
} }
where submissionComparator (TableEntry _ _ _ em1 _ _) (TableEntry _ _ _ em2 _ _) = (compareResult mainTest) (evaluationScore (em1 Map.! mainTestId)) (evaluationScore (em2 Map.! mainTestId)) where (Entity mainTestId mainTest) = getMainTest tests
submissionComparator (TableEntry _ _ _ em1 _ _) (TableEntry _ _ _ em2 _ _) =
(compareResult mainTest) (evaluationScore (em1 Map.! mainTestId))
(evaluationScore (em2 Map.! mainTestId))
getLeaderboardEntries :: Key Challenge -> Handler (Test, [LeaderboardEntry], ([TableEntry], [Entity Test])) getLeaderboardEntries :: Key Challenge -> Handler ([LeaderboardEntry], ([TableEntry], [Entity Test]))
getLeaderboardEntries challengeId = getLeaderboardEntries challengeId =
getLeaderboardEntriesByCriterion challengeId getLeaderboardEntriesByCriterion challengeId
(const True) (const True)

View File

@ -5,7 +5,7 @@ $nothing
<h2>Leaderboard <h2>Leaderboard
^{Table.buildBootstrap (leaderboardTable muserId (challengeName challenge) scheme challengeRepo test) leaderboardWithRanks} ^{Table.buildBootstrap (leaderboardTable muserId (challengeName challenge) scheme challengeRepo tests) leaderboardWithRanks}
<div id="graph-container"> <div id="graph-container">