File size: 2,384 Bytes
b54f543 |
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 |
import { useRef, useEffect } from 'react'
import * as Plot from '@observablehq/plot'
const SpeakerPlot = ({ data }) => {
const containerRef = useRef()
const allSpeakers = data.language_table.reduce((sum, curr) => sum + curr.speakers, 0)
const languages = data.language_table.sort((a, b) => b.speakers - a.speakers).slice(0, 100).reduce((acc, d) => {
acc.push({
...d,
rank: acc.length + 1,
cumSpeakers: acc.reduce((sum, curr) => sum + curr.speakers, 0) + d.speakers,
cumSpeakersPercent: (acc.reduce((sum, curr) => sum + curr.speakers, 0) + d.speakers) / allSpeakers
})
return acc
}, [])
useEffect(() => {
const plot = Plot.plot({
width: 750,
height: 500,
// title: 'Proficiency of Languages by Number of Speakers',
x: {
label: 'Languages',
ticks: [],
},
y: {
label: 'Number of Speakers (millions)',
},
color: {
legend: true,
domain: ["Speakers", "Cumulative Speakers"],
range: ["green", "lightgrey"],
},
marks: [
Plot.barY(languages,
{
x: "rank",
y: d => d.cumSpeakers / 1e6,
fill: d => "Cumulative Speakers",
sort: { x: 'y' },
title: d => `The ${d.rank} most spoken languages cover\n${d.cumSpeakersPercent.toLocaleString("en-US", { style: 'percent'})} of all speakers`,
tip: true // {y: d => d.cumSpeakers / 1e6 * 2}
}),
Plot.barY(languages,
{
x: "rank",
y: d => d.speakers / 1e6,
title: d => `${d.language_name}\n(${d.speakers.toLocaleString("en-US", {notation: 'compact', compactDisplay: 'long'})} speakers)`,
tip: true,
fill: d => "Speakers",
sort: { x: '-y' }
}),
Plot.crosshairX(languages, {x: "rank", y: d => d.cumSpeakers / 1e6, textStrokeOpacity: 0, textFillOpacity: 0}),
Plot.tip(["The 41 most spoken languages cover 80% of all speakers."], {x: 41, y: languages[40].cumSpeakers / 1e6})
],
})
containerRef.current.append(plot)
return () => plot.remove()
}, [])
return (
<div
ref={containerRef}
style={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
/>
)
}
export default SpeakerPlot
|