Spaces:
Running
Running
File size: 3,600 Bytes
972026c 34b05c6 972026c |
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 |
import { useRef, useEffect } from 'react'
import * as Plot from '@observablehq/plot'
const LanguageTierHistoryPlot = ({ data, width = 750, height = 500 }) => {
const containerRef = useRef()
const tierHistory = [...(data.language_tier_history || [])]
.filter(d => d.proficiency_score !== null && d.creation_date !== null)
.sort((a, b) => new Date(a.creation_date) - new Date(b.creation_date))
// Get unique tiers from data, dynamically
const tiers = [...new Set(tierHistory.map(d => d.tier))]
// Add " languages" suffix for legend display
const tierWithSuffix = (tier) => `${tier} languages`
// Calculate max proficiency over time for each tier
const tierRecords = {}
tiers.forEach(tier => {
const tierData = tierHistory.filter(d => d.tier === tier)
const records = []
let maxScore = 0
tierData.forEach(curr => {
if (curr.proficiency_score > maxScore) {
maxScore = curr.proficiency_score
records.push({
...curr,
maxScore: maxScore,
newRecord: true
})
} else {
records.push({
...curr,
maxScore: maxScore,
newRecord: false
})
}
})
tierRecords[tier] = records
})
// Flatten for plotting - only show dots for new records
// Add " languages" suffix to tier for display
const recordBreakingDots = Object.values(tierRecords)
.flat()
.filter(d => d.newRecord)
.map(d => ({ ...d, tierDisplay: tierWithSuffix(d.tier) }))
// Create step function data for each tier
const stepData = tiers.flatMap(tier => {
const records = tierRecords[tier].filter(d => d.newRecord)
if (records.length === 0) return []
return [
...records.map(d => ({ ...d, tierDisplay: tierWithSuffix(d.tier) })),
{
tier: tier,
tierDisplay: tierWithSuffix(tier),
creation_date: new Date(),
maxScore: records[records.length - 1]?.maxScore || 0
}
]
})
useEffect(() => {
const plot = Plot.plot({
width: width,
height: height,
subtitle: 'Model performance on language tiers over time',
x: {
label: 'Date',
type: 'time',
tickFormat: '%Y-%m'
},
y: {
label: 'Overall Score by Language Tier'
},
color: {
legend: true,
domain: tiers.map(tierWithSuffix)
},
marks: [
Plot.dot(recordBreakingDots, {
x: d => new Date(d.creation_date),
y: d => d.proficiency_score,
fill: 'tierDisplay',
stroke: 'tierDisplay',
title: d =>
`${d.provider_name} - ${d.name} (${
d.size?.toLocaleString('en-US', { notation: 'compact' }) || '?B'
})\nTier: ${d.tier}\nPublished: ${new Date(
d.creation_date
).toLocaleDateString()}\nScore: ${d.proficiency_score.toFixed(2)}`,
tip: true
}),
Plot.line(stepData, {
x: d => new Date(d.creation_date),
y: d => d.maxScore || 0,
stroke: 'tierDisplay',
curve: 'step-after',
strokeOpacity: 0.5,
strokeWidth: 2
})
]
})
containerRef.current.append(plot)
return () => plot.remove()
}, [recordBreakingDots, stepData, width, height, tiers])
return (
<div
ref={containerRef}
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
/>
)
}
export default LanguageTierHistoryPlot
|