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