From a2c9fb4ab7901bbf336612692f223d92a44f0d70 Mon Sep 17 00:00:00 2001
From: Paul Pestov <pestov@sub.uni-goettingen.de>
Date: Wed, 6 Dec 2023 11:52:55 +0100
Subject: [PATCH] feat: display trend colors depedant on given metric

---
 src/components/Workflows.vue                  |  6 +++
 .../workflows/WorkflowsTimeline.vue           |  4 +-
 .../workflows/timeline/BaseTimelineChart.vue  | 21 ++++------
 .../workflows/timeline/MetricAverageChart.vue | 41 +++++++++----------
 .../workflows/timeline/TimelineItem.vue       | 17 ++++----
 src/helpers/metrics.ts                        | 14 +++++--
 6 files changed, 55 insertions(+), 48 deletions(-)

diff --git a/src/components/Workflows.vue b/src/components/Workflows.vue
index 7f20484..adb64b7 100644
--- a/src/components/Workflows.vue
+++ b/src/components/Workflows.vue
@@ -52,6 +52,12 @@
     workflowsStore.gt = await api.getGroundTruth()
     workflowsStore.workflows = await api.getWorkflows()
 
+    workflowsStore.runs.forEach(run => {
+      const gtId = mapGtId(run.metadata.gt_workspace.id)
+
+      if (!workflowsStore.gt.find(gt => gt.id === gtId)) console.log(gtId)
+    })
+
     const releasesObj = workflowsStore.runs.reduce((acc, cur) => {
       acc[cur.metadata.release_info.tag_name] = cur.metadata.release_info
       return acc
diff --git a/src/components/workflows/WorkflowsTimeline.vue b/src/components/workflows/WorkflowsTimeline.vue
index d912a1d..bb038ec 100644
--- a/src/components/workflows/WorkflowsTimeline.vue
+++ b/src/components/workflows/WorkflowsTimeline.vue
@@ -4,14 +4,14 @@ import Dropdown from 'primevue/dropdown'
 import {computed, onMounted, ref, watch} from "vue"
 import {EvaluationMetrics, getMaxValueByMetric} from '@/helpers/metrics'
 import { useI18n } from "vue-i18n"
-import type {DropdownOption, EvaluationResultsDocumentWide, Workflow} from "@/types"
+import type { DropdownOption, EvaluationResultsDocumentWide, Workflow, GroundTruth } from "@/types"
 import { DropdownPassThroughStyles } from '@/helpers/pt'
 import workflowsStore from '@/store/workflows-store'
 import filtersStore from '@/store/filters-store'
 import timelineStore from "@/store/timeline-store"
 
 const { t } = useI18n()
-const gtList = computed(() => workflowsStore.gt.filter(({ id }) => filtersStore.gt.findIndex(({ value }) => value === id) > -1))
+const gtList = computed<GroundTruth[]>(() => workflowsStore.gt.filter(({ id }) => filtersStore.gt.findIndex(({ value }) => value === id) > -1))
 const workflows = ref<Workflow[]>([])
 const selectedMetric = ref<DropdownOption | null>(null)
 const metrics = computed<DropdownOption[]>(() => Object.keys(EvaluationMetrics).map(key => ({ value: EvaluationMetrics[key], label: t(EvaluationMetrics[key]) })))
diff --git a/src/components/workflows/timeline/BaseTimelineChart.vue b/src/components/workflows/timeline/BaseTimelineChart.vue
index 8c92c69..b52f12c 100644
--- a/src/components/workflows/timeline/BaseTimelineChart.vue
+++ b/src/components/workflows/timeline/BaseTimelineChart.vue
@@ -14,7 +14,8 @@ interface Props {
   startDate: Date,
   endDate: Date,
   height?: number,
-  tooltipContent: (d: TimelineChartDataPoint) => string
+  tooltipContent: (d: TimelineChartDataPoint) => string,
+  higherIsPositive?: boolean
 }
 
 const props = defineProps<Props>()
@@ -28,24 +29,20 @@ const _width = computed(() => props.width ?? 300)
 
 const container = ref<HTMLDivElement>()
 
-function isUp(data: TimelineChartDataPoint[], higherIsUp = true) {
+function isUp(data: TimelineChartDataPoint[], higherIsPositive = true) {
 
   if (data.length === 0) return 0
 
   const last = data[data.length - 1].value
   const secondLast = data.length > 1 ? data[data.length - 2].value : last
 
-  const diff = higherIsUp ? last - secondLast : secondLast - last
+  const diff = higherIsPositive ? last - secondLast : secondLast - last
 
   if (diff === 0) return 0
   else if (diff > 0) return 1
   else return -1
 }
 
-function renderReleases() {
-
-}
-
 function render([data, startDate, endDate, maxY]) {
   if (!data || !startDate || !endDate) return
 
@@ -90,13 +87,13 @@ function render([data, startDate, endDate, maxY]) {
   svg.selectAll('.y-axis-group .tick text').attr('fill', colors.gray['400'])
 
 
-  const trend = isUp(data, false)
+  const trend = isUp(data, props.higherIsPositive)
 
   const pathGroup = svg
       .append('g')
       .classed('path-group', true)
-      .classed('up', trend === 1)
-      .classed('down', trend === -1)
+      .classed('trend-positive', trend === 1)
+      .classed('trend-negative', trend === -1)
 
   pathGroup.append("path")
       .datum(data)
@@ -181,7 +178,7 @@ watch([() => props.data, () => props.startDate, () => props.endDate, () => props
     fill: var(--color--neutral-text);
   }
 
-  &.up {
+  &.trend-positive {
     path {
       stroke: var(--color--positive-text);
     }
@@ -191,7 +188,7 @@ watch([() => props.data, () => props.startDate, () => props.endDate, () => props
     }
   }
 
-  &.down {
+  &.trend-negative {
     path {
       stroke: var(--color--negative-text);
     }
diff --git a/src/components/workflows/timeline/MetricAverageChart.vue b/src/components/workflows/timeline/MetricAverageChart.vue
index 7bdbed7..a77e738 100644
--- a/src/components/workflows/timeline/MetricAverageChart.vue
+++ b/src/components/workflows/timeline/MetricAverageChart.vue
@@ -1,15 +1,12 @@
 <script setup lang="ts">
 import {computed, onMounted, ref, watch} from "vue"
-import api from "@/helpers/api"
 import BaseTimelineChart from "@/components/workflows/timeline/BaseTimelineChart.vue"
 import type {EvaluationResultsDocumentWide, EvaluationRun, TimelineChartDataPoint} from "@/types"
-import {useI18n} from "vue-i18n";
 import { metricChartTooltipContent } from "@/helpers/metric-chart-tooltip-content";
 import OverlayPanel from "primevue/overlaypanel";
 import BaseTimelineDetailedChart from "@/components/workflows/timeline/BaseTimelineDetailedChart.vue";
 import timelineStore from "@/store/timeline-store";
-
-const { t } = useI18n()
+import {isHigherPositive} from "@/helpers/metrics";
 
 const props = defineProps<{
   runs: EvaluationRun[],
@@ -21,7 +18,6 @@ const props = defineProps<{
 
 const data = ref<TimelineChartDataPoint[]>([])
 const maxY = computed(() => timelineStore.maxValues[props.metric] ?? 0)
-const runs = ref<EvaluationRun[]>([])
 const op = ref<OverlayPanel | null>(null)
 
 onMounted(async () => {
@@ -37,26 +33,26 @@ function init() {
 
 function getTimelineData(runs: EvaluationRun[], metric: string): TimelineChartDataPoint[] {
   const datesValues = runs.reduce((acc, cur) => {
-      const date = new Date(new Date(cur.metadata.timestamp).setHours(0, 0, 0, 0)).toDateString()
-      const value = cur.evaluation_results.document_wide[<keyof EvaluationResultsDocumentWide>metric]
-      if (!value || Array.isArray(value)) return acc
+    const date = new Date(new Date(cur.metadata.timestamp).setHours(0, 0, 0, 0)).toDateString()
+    const value = cur.evaluation_results.document_wide[<keyof EvaluationResultsDocumentWide>metric]
+    if (!value || Array.isArray(value)) return acc
 
-      if (!acc[date]) acc[date] = [value]
-      else acc[date] = [...acc[date], value]
-      return acc
-    },
-    <{ [key: string]: number[] }>{})
+    if (!acc[date]) acc[date] = [value]
+    else acc[date] = [...acc[date], value]
+    return acc
+  },
+  <{ [key: string]: number[] }>{})
 
   return Object
-      .keys(datesValues)
-      .sort((a, b) => new Date(a) - new Date(b))
-      .map(date => {
-        const value = datesValues[date].reduce((a, b) => a + b, 0) / datesValues[date].length
-        return {
-          date: new Date(date),
-          value
-        }
-      })
+    .keys(datesValues)
+    .sort((a, b) => new Date(a) - new Date(b))
+    .map(date => {
+      const value = datesValues[date].reduce((a, b) => a + b, 0) / datesValues[date].length
+      return {
+        date: new Date(date),
+        value
+      }
+    })
 }
 
 function tooltipContent(d: TimelineChartDataPoint) {
@@ -73,6 +69,7 @@ function tooltipContent(d: TimelineChartDataPoint) {
       :end-date="endDate"
       :tooltip-content="tooltipContent"
       :width="400"
+      :higher-is-positive="isHigherPositive(metric)"
     />
   </div>
   <OverlayPanel
diff --git a/src/components/workflows/timeline/TimelineItem.vue b/src/components/workflows/timeline/TimelineItem.vue
index 6811bfe..c8b3831 100644
--- a/src/components/workflows/timeline/TimelineItem.vue
+++ b/src/components/workflows/timeline/TimelineItem.vue
@@ -3,13 +3,12 @@ import Panel from "primevue/panel"
 import OverlayPanel from 'primevue/overlaypanel'
 import StepsAcronyms from '@/helpers/workflow-steps-acronyms'
 import MetricChart from "@/components/workflows/timeline/MetricChart.vue"
-import type { EvaluationResultsDocumentWide, EvaluationRun, GroundTruth, Workflow, WorkflowStep } from "@/types"
+import type { EvaluationResultsDocumentWide, GroundTruth, Workflow, WorkflowStep } from "@/types"
 import MetricAverageChart from "@/components/workflows/timeline/MetricAverageChart.vue"
 import { Icon } from '@iconify/vue'
 import { onMounted, ref } from "vue"
 import { OverlayPanelDropdownStyles } from "@/helpers/pt"
 import workflowsStore from "@/store/workflows-store"
-import HomeView from "@/views/HomeView.vue"
 
 const props = defineProps<{
   gt: GroundTruth,
@@ -99,13 +98,13 @@ function hideParametersOverlay() {
             </td>
             <td class="overflow-x-auto">
               <MetricChart
-                  :runs="workflowsStore.getRuns(gt.id, workflow.id)"
-                  :workflow-name="workflow.label"
-                  :metric="metric"
-                  :width="400"
-                  :start-date="startDate"
-                  :end-date="endDate"
-                  class="flex justify-end"
+                :runs="workflowsStore.getRuns(gt.id, workflow.id)"
+                :workflow-name="workflow.label"
+                :metric="metric"
+                :width="400"
+                :start-date="startDate"
+                :end-date="endDate"
+                class="flex justify-end"
               />
             </td>
           </tr>
diff --git a/src/helpers/metrics.ts b/src/helpers/metrics.ts
index 488697d..b9040fc 100644
--- a/src/helpers/metrics.ts
+++ b/src/helpers/metrics.ts
@@ -31,13 +31,21 @@ function getMaxValueByMetric(metric: keyof EvaluationResultsDocumentWide, runs:
   return Math.max(...values)
 }
 
-function extendMaxValue(value: number): number {
-  return Math.floor(value + value * 0.2)
+function isHigherPositive(metric: keyof EvaluationResultsDocumentWide): boolean {
+  if (metric === EvaluationMetrics.CER_MEAN) return false
+  if (metric === EvaluationMetrics.CER_MEDIAN) return false
+  if (metric === EvaluationMetrics.CER_STANDARD_DEVIATION) return false
+  if (metric === EvaluationMetrics.WER) return false
+  if (metric === EvaluationMetrics.WALL_TIME) return false
+  if (metric === EvaluationMetrics.PAGES_PER_MINUTE) return true
+  if (metric === EvaluationMetrics.CPU_TIME) return false
+
+  return false
 }
 
 export {
   EvaluationMetrics,
   getMaxValueByMetric,
   getDefaultMaxValueOfMetric,
-  extendMaxValue
+  isHigherPositive
 }
-- 
GitLab