File size: 2,342 Bytes
a73f888
 
 
e8341d2
a73f888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e8341d2
a73f888
 
 
 
e8341d2
a73f888
 
 
 
 
 
 
 
e8341d2
a73f888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e8341d2
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
import { useRef, useEffect } from 'react'
import * as Plot from '@observablehq/plot'

const CostPlot = ({ data, width = 750, height = 500 }) => {
  const containerRef = useRef()
  useEffect(() => {
    const models = [...data.model_table] // sort copy, not in place
      .filter(d => d.average !== null && d.cost > 0)
      .sort((a, b) => a.cost - b.cost)
      .reduce((acc, curr) => {
        const last = acc[acc.length - 1]?.maxAverage || 0
        acc.push({
          ...curr,
          maxAverage: Math.max(last, curr.average),
          newRecord: curr.average > last
        })
        return acc
      }, [])
    let USDollar = new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD'
    })
    const plot = Plot.plot({
      width: width,
      height: height,
      subtitle: 'Cost vs Performance',
      x: {
        label: 'Cost (USD)',
        type: 'log',
        // format dollar / ct
        tickFormat: d => USDollar.format(d)
      },
      y: {
        label: 'Language Proficiency Score'
      },
      symbol: {
        legend: true
      },
      marks: [
        Plot.dot(models, {
          x: d => d.cost,
          y: d => d.average,
          symbol: 'provider_name',
          stroke: 'provider_name',
          title: d =>
            `${d.provider_name} - ${d.name} (${
              d.size?.toLocaleString('en-US', { notation: 'compact' }) || '?B'
            })\nCost: ${USDollar.format(d.cost)}\nScore: ${d.average.toFixed(
              2
            )}`,
          tip: true
        }),
        Plot.line(
          [
            ...models.filter(d => d.newRecord),
            {
              cost: models.map(d => d.cost).reduce((a, b) => Math.max(a, b), 0),
              maxAverage: models[models.length - 1]?.maxAverage || 0
            }
          ],
          {
            x: d => d.cost,
            y: d => d?.maxAverage || 0,
            curve: 'catmull-rom',
            strokeOpacity: 0.3
          }
        )
      ]
    })
    containerRef.current.append(plot)
    return () => plot.remove()
  }, [data, width, height])

  return (
    <div
      ref={containerRef}
      style={{
        width: '100%',
        height: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
      }}
    />
  )
}

export default CostPlot