File size: 4,634 Bytes
98847a8
 
ed37070
98847a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ed37070
98847a8
 
 
 
 
 
 
 
 
ed37070
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98847a8
 
 
ed37070
98847a8
 
 
 
 
 
 
 
 
 
 
ed37070
 
 
 
98847a8
ed37070
98847a8
 
 
 
 
 
ed37070
98847a8
 
 
ed37070
98847a8
ed37070
98847a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ed37070
98847a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import React, { useEffect, useState } from 'react'
import API from '../API'
import LeaderboardFilter from './LeaderboardFilter'

interface LeaderboardTableProps {
  file: string
}

interface Row {
  metric: string
  [key: string]: string | number
}

interface Groups {
  [group: string]: { [subgroup: string]: string[] }
}

const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ file }) => {
  const [tableRows, setTableRows] = useState<Row[]>([])
  const [tableHeader, setTableHeader] = useState<string[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [groups, setGroups] = useState<Groups>({})

  const [selectedMetrics, setSelectedMetrics] = useState<Set<string>>(new Set())
  const [defaultSelectedMetrics, setDefaultSelectedMetrics] = useState<string[]>([])

  useEffect(() => {
    API.fetchStaticFile(`data/${file}_benchmark.csv`)
      .then((response) => {
        const data = JSON.parse(response)
        const rows: Row[] = data['rows']
        const groups = data['groups'] as { [key: string]: string[] }

        // Each value of groups is a list of metrics, group them by the first part of the metric before the first _
        const groupsData = Object.entries(groups)
          .sort(([groupA], [groupB]) => {
            // Make sure "overall" comes first
            if (groupA === 'Overall') return -1
            if (groupB === 'Overall') return 1
            // Otherwise sort alphabetically
            return groupA.localeCompare(groupB)
          })
          .reduce(
            (acc, [group, metrics]) => {
              // Sort metrics to ensure consistent subgroup order
              const sortedMetrics = [...metrics].sort()

              // Create and sort subgroups
              acc[group] = sortedMetrics.reduce<{ [key: string]: string[] }>((subAcc, metric) => {
                const [mainGroup, subGroup] = metric.split('_')
                if (!subAcc[mainGroup]) {
                  subAcc[mainGroup] = []
                }
                subAcc[mainGroup].push(metric)
                return subAcc
              }, {})

              // Convert to sorted entries and back to object
              acc[group] = Object.fromEntries(
                Object.entries(acc[group]).sort(([subGroupA], [subGroupB]) =>
                  subGroupA.localeCompare(subGroupB)
                )
              )

              return acc
            },
            {} as { [key: string]: { [key: string]: string[] } }
          )

        const allKeys: string[] = Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
        setSelectedMetrics(new Set(data['default_selected_metrics']))
        setDefaultSelectedMetrics(data['default_selected_metrics'])
        setTableHeader(allKeys)
        setTableRows(rows)
        setGroups(groupsData)
        setLoading(false)
      })
      .catch((err) => {
        setError('Failed to fetch JSON: ' + err.message)
        setLoading(false)
      })
  }, [file])

  const handleSelectDefaults = () => {
    setSelectedMetrics(new Set(defaultSelectedMetrics))
  }

  return (
    <div className="rounded shadow overflow-auto">
      <h3 className="font-bold mb-2">{file}</h3>
      {loading && <div>Loading...</div>}
      {error && <div className="text-red-500">{error}</div>}

      {!loading && !error && (
        <div className="overflow-x-auto">
          <LeaderboardFilter
            groups={groups}
            selectedMetrics={selectedMetrics}
            setSelectedMetrics={setSelectedMetrics}
            defaultSelectedMetrics={defaultSelectedMetrics}
          />
          <table className="table">
            <thead>
              <tr>
                {tableHeader.map((col, idx) => (
                  <th key={idx}>{col}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {tableRows
                .filter((row) => selectedMetrics.has(row['metric'] as string))
                .map((row, i) => (
                  <tr key={i}>
                    {Object.keys(row).map((column, j) => {
                      const cell = row[column]

                      return (
                        <td key={j}>
                          <div className="">
                            {isNaN(Number(cell)) ? cell : Number(Number(cell).toFixed(3))}
                          </div>
                        </td>
                      )
                    })}
                  </tr>
                ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  )
}

export default LeaderboardTable