@buildcanada/charts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/LICENSE.md +8 -0
  2. package/README.md +113 -0
  3. package/package.json +137 -0
  4. package/src/components/BodyPortal/BodyPortal.tsx +40 -0
  5. package/src/components/Button/Button.scss +110 -0
  6. package/src/components/Button/Button.tsx +101 -0
  7. package/src/components/Checkbox.scss +93 -0
  8. package/src/components/Checkbox.tsx +47 -0
  9. package/src/components/ExpandableToggle/ExpandableToggle.scss +123 -0
  10. package/src/components/ExpandableToggle/ExpandableToggle.tsx +60 -0
  11. package/src/components/GrapherTabIcon.tsx +156 -0
  12. package/src/components/GrapherTrendArrow.scss +16 -0
  13. package/src/components/GrapherTrendArrow.tsx +30 -0
  14. package/src/components/Halo/Halo.tsx +44 -0
  15. package/src/components/LabeledSwitch/LabeledSwitch.scss +109 -0
  16. package/src/components/LabeledSwitch/LabeledSwitch.tsx +62 -0
  17. package/src/components/MarkdownTextWrap/MarkdownTextWrap.tsx +1173 -0
  18. package/src/components/OverlayHeader.scss +18 -0
  19. package/src/components/OverlayHeader.tsx +29 -0
  20. package/src/components/RadioButton.scss +69 -0
  21. package/src/components/RadioButton.tsx +42 -0
  22. package/src/components/SimpleMarkdownText.tsx +89 -0
  23. package/src/components/TextInput.scss +17 -0
  24. package/src/components/TextInput.tsx +19 -0
  25. package/src/components/TextWrap/TextWrap.tsx +361 -0
  26. package/src/components/TextWrap/TextWrapUtils.ts +32 -0
  27. package/src/components/closeButton/CloseButton.scss +40 -0
  28. package/src/components/closeButton/CloseButton.tsx +27 -0
  29. package/src/components/index.ts +70 -0
  30. package/src/components/loadingIndicator/LoadingIndicator.scss +40 -0
  31. package/src/components/loadingIndicator/LoadingIndicator.tsx +28 -0
  32. package/src/components/markdown/remarkPlainLinks.ts +36 -0
  33. package/src/components/reactUtil.ts +20 -0
  34. package/src/components/stubs/CodeSnippet.tsx +19 -0
  35. package/src/components/stubs/DataCitation.tsx +16 -0
  36. package/src/components/stubs/IndicatorKeyData.tsx +45 -0
  37. package/src/components/stubs/IndicatorProcessing.tsx +15 -0
  38. package/src/components/stubs/IndicatorSources.tsx +15 -0
  39. package/src/components/styles/colors.scss +113 -0
  40. package/src/components/styles/mixins.scss +630 -0
  41. package/src/components/styles/typography.scss +579 -0
  42. package/src/components/styles/util.scss +89 -0
  43. package/src/components/styles/variables.scss +208 -0
  44. package/src/config/ChartsConfig.ts +163 -0
  45. package/src/config/ChartsProvider.tsx +157 -0
  46. package/src/config/index.ts +20 -0
  47. package/src/core-table/CoreTable.ts +1355 -0
  48. package/src/core-table/CoreTableColumns.ts +973 -0
  49. package/src/core-table/CoreTableUtils.ts +793 -0
  50. package/src/core-table/ErrorValues.ts +73 -0
  51. package/src/core-table/OwidTable.ts +1175 -0
  52. package/src/core-table/OwidTableSynthesizers.ts +272 -0
  53. package/src/core-table/OwidTableUtil.ts +76 -0
  54. package/src/core-table/Transforms.ts +484 -0
  55. package/src/core-table/index.ts +82 -0
  56. package/src/explorer/ColumnGrammar.ts +217 -0
  57. package/src/explorer/Explorer.sample.ts +212 -0
  58. package/src/explorer/Explorer.scss +148 -0
  59. package/src/explorer/Explorer.tsx +1283 -0
  60. package/src/explorer/ExplorerConstants.ts +85 -0
  61. package/src/explorer/ExplorerControls.scss +156 -0
  62. package/src/explorer/ExplorerControls.tsx +210 -0
  63. package/src/explorer/ExplorerDecisionMatrix.ts +471 -0
  64. package/src/explorer/ExplorerGrammar.ts +161 -0
  65. package/src/explorer/ExplorerProgram.ts +568 -0
  66. package/src/explorer/ExplorerUtils.ts +59 -0
  67. package/src/explorer/GrapherGrammar.ts +387 -0
  68. package/src/explorer/gridLang/GrammarUtils.ts +121 -0
  69. package/src/explorer/gridLang/GridCell.ts +298 -0
  70. package/src/explorer/gridLang/GridLangConstants.ts +255 -0
  71. package/src/explorer/gridLang/GridProgram.ts +311 -0
  72. package/src/explorer/gridLang/readme.md +17 -0
  73. package/src/explorer/index.ts +69 -0
  74. package/src/explorer/readme.md +19 -0
  75. package/src/explorer/urlMigrations/CO2UrlMigration.ts +46 -0
  76. package/src/explorer/urlMigrations/CovidUrlMigration.ts +37 -0
  77. package/src/explorer/urlMigrations/EnergyUrlMigration.ts +41 -0
  78. package/src/explorer/urlMigrations/ExplorerPageUrlMigrationSpec.ts +12 -0
  79. package/src/explorer/urlMigrations/ExplorerUrlMigrationUtils.ts +45 -0
  80. package/src/explorer/urlMigrations/ExplorerUrlMigrations.ts +33 -0
  81. package/src/explorer/urlMigrations/LegacyCovidUrlMigration.ts +144 -0
  82. package/src/explorer/urlMigrations/readme.md +39 -0
  83. package/src/grapher/axis/Axis.ts +973 -0
  84. package/src/grapher/axis/AxisConfig.ts +179 -0
  85. package/src/grapher/axis/AxisViews.tsx +597 -0
  86. package/src/grapher/barCharts/DiscreteBarChart.tsx +728 -0
  87. package/src/grapher/barCharts/DiscreteBarChartConstants.ts +60 -0
  88. package/src/grapher/barCharts/DiscreteBarChartHelpers.ts +338 -0
  89. package/src/grapher/barCharts/DiscreteBarChartState.ts +354 -0
  90. package/src/grapher/barCharts/DiscreteBarChartThumbnail.tsx +34 -0
  91. package/src/grapher/captionedChart/CaptionedChart.scss +61 -0
  92. package/src/grapher/captionedChart/CaptionedChart.tsx +523 -0
  93. package/src/grapher/captionedChart/Logos.tsx +141 -0
  94. package/src/grapher/captionedChart/LogosSVG.tsx +16 -0
  95. package/src/grapher/captionedChart/StaticChartRasterizer.tsx +178 -0
  96. package/src/grapher/captionedChart/assets/buildcanada-logo-square.svg +15 -0
  97. package/src/grapher/captionedChart/assets/buildcanada-logo.svg +15 -0
  98. package/src/grapher/captionedChart/assets/canadaspends.svg +7 -0
  99. package/src/grapher/captionedChart/readme.md +14 -0
  100. package/src/grapher/chart/Chart.tsx +62 -0
  101. package/src/grapher/chart/ChartAreaContent.tsx +172 -0
  102. package/src/grapher/chart/ChartDimension.ts +121 -0
  103. package/src/grapher/chart/ChartInterface.ts +83 -0
  104. package/src/grapher/chart/ChartManager.ts +113 -0
  105. package/src/grapher/chart/ChartTabs.ts +178 -0
  106. package/src/grapher/chart/ChartTypeMap.tsx +158 -0
  107. package/src/grapher/chart/ChartTypeSwitcher.tsx +26 -0
  108. package/src/grapher/chart/ChartUtils.tsx +364 -0
  109. package/src/grapher/chart/DimensionSlot.ts +45 -0
  110. package/src/grapher/chart/StaticChartWrapper.tsx +94 -0
  111. package/src/grapher/chart/guidedChartUtils.ts +82 -0
  112. package/src/grapher/color/BinningStrategies.ts +484 -0
  113. package/src/grapher/color/BinningStrategyEqualSizeBins.ts +132 -0
  114. package/src/grapher/color/BinningStrategyLogarithmic.ts +121 -0
  115. package/src/grapher/color/CategoricalColorAssigner.ts +97 -0
  116. package/src/grapher/color/ColorBrewerSchemes.ts +80 -0
  117. package/src/grapher/color/ColorConstants.ts +20 -0
  118. package/src/grapher/color/ColorScale.ts +339 -0
  119. package/src/grapher/color/ColorScaleBin.ts +147 -0
  120. package/src/grapher/color/ColorScaleConfig.ts +204 -0
  121. package/src/grapher/color/ColorScheme.ts +137 -0
  122. package/src/grapher/color/ColorSchemes.ts +149 -0
  123. package/src/grapher/color/ColorUtils.ts +86 -0
  124. package/src/grapher/color/CustomSchemes.ts +1772 -0
  125. package/src/grapher/color/readme.md +84 -0
  126. package/src/grapher/comparisonLine/ComparisonLine.tsx +31 -0
  127. package/src/grapher/comparisonLine/ComparisonLineConstants.ts +11 -0
  128. package/src/grapher/comparisonLine/ComparisonLineGenerator.ts +60 -0
  129. package/src/grapher/comparisonLine/ComparisonLineHelpers.ts +10 -0
  130. package/src/grapher/comparisonLine/CustomComparisonLine.tsx +159 -0
  131. package/src/grapher/comparisonLine/VerticalComparisonLine.tsx +208 -0
  132. package/src/grapher/controls/ActionButtons.scss +97 -0
  133. package/src/grapher/controls/ActionButtons.tsx +453 -0
  134. package/src/grapher/controls/CommandPalette.scss +50 -0
  135. package/src/grapher/controls/CommandPalette.tsx +74 -0
  136. package/src/grapher/controls/ContentSwitchers.scss +93 -0
  137. package/src/grapher/controls/ContentSwitchers.tsx +238 -0
  138. package/src/grapher/controls/Controls.scss +158 -0
  139. package/src/grapher/controls/DataTableFilterDropdown.scss +7 -0
  140. package/src/grapher/controls/DataTableFilterDropdown.tsx +168 -0
  141. package/src/grapher/controls/DataTableSearchField.scss +3 -0
  142. package/src/grapher/controls/DataTableSearchField.tsx +76 -0
  143. package/src/grapher/controls/Dropdown.scss +252 -0
  144. package/src/grapher/controls/Dropdown.tsx +235 -0
  145. package/src/grapher/controls/EntitySelectionToggle.tsx +135 -0
  146. package/src/grapher/controls/MapRegionDropdown.scss +3 -0
  147. package/src/grapher/controls/MapRegionDropdown.tsx +104 -0
  148. package/src/grapher/controls/MapResetButton.tsx +115 -0
  149. package/src/grapher/controls/MapZoomDropdown.scss +9 -0
  150. package/src/grapher/controls/MapZoomDropdown.tsx +270 -0
  151. package/src/grapher/controls/MapZoomToSelectionButton.tsx +87 -0
  152. package/src/grapher/controls/SearchField.scss +78 -0
  153. package/src/grapher/controls/SearchField.tsx +63 -0
  154. package/src/grapher/controls/SettingsMenu.scss +191 -0
  155. package/src/grapher/controls/SettingsMenu.tsx +399 -0
  156. package/src/grapher/controls/ShareMenu.scss +58 -0
  157. package/src/grapher/controls/ShareMenu.tsx +304 -0
  158. package/src/grapher/controls/SortIcon.tsx +39 -0
  159. package/src/grapher/controls/VerticalScrollContainer.tsx +263 -0
  160. package/src/grapher/controls/controlsRow/ControlsRow.tsx +168 -0
  161. package/src/grapher/controls/dropdown-icons.scss +4 -0
  162. package/src/grapher/controls/entityPicker/EntityPicker.scss +255 -0
  163. package/src/grapher/controls/entityPicker/EntityPicker.tsx +816 -0
  164. package/src/grapher/controls/entityPicker/EntityPickerConstants.ts +23 -0
  165. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.scss +129 -0
  166. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.tsx +463 -0
  167. package/src/grapher/controls/globalEntitySelector/GlobalEntitySelectorConstants.ts +3 -0
  168. package/src/grapher/controls/globalEntitySelector/readme.md +17 -0
  169. package/src/grapher/controls/settings/AbsRelToggle.tsx +64 -0
  170. package/src/grapher/controls/settings/AxisScaleToggle.tsx +53 -0
  171. package/src/grapher/controls/settings/FacetStrategySelector.tsx +110 -0
  172. package/src/grapher/controls/settings/FacetYDomainToggle.tsx +51 -0
  173. package/src/grapher/controls/settings/NoDataAreaToggle.tsx +38 -0
  174. package/src/grapher/controls/settings/ZoomToggle.tsx +36 -0
  175. package/src/grapher/core/EntitiesByRegionType.ts +174 -0
  176. package/src/grapher/core/EntityCodes.ts +19 -0
  177. package/src/grapher/core/EntityUrlBuilder.ts +200 -0
  178. package/src/grapher/core/FetchingGrapher.tsx +156 -0
  179. package/src/grapher/core/Grapher.tsx +760 -0
  180. package/src/grapher/core/GrapherAnalytics.ts +229 -0
  181. package/src/grapher/core/GrapherConstants.ts +173 -0
  182. package/src/grapher/core/GrapherState.tsx +3659 -0
  183. package/src/grapher/core/GrapherUrl.ts +184 -0
  184. package/src/grapher/core/GrapherUrlMigrations.ts +29 -0
  185. package/src/grapher/core/GrapherUseHelpers.tsx +147 -0
  186. package/src/grapher/core/LegacyToOwidTable.ts +841 -0
  187. package/src/grapher/core/grapher.entry.ts +5 -0
  188. package/src/grapher/core/grapher.scss +257 -0
  189. package/src/grapher/core/loadGrapherTableHelpers.ts +116 -0
  190. package/src/grapher/core/loadVariable.ts +104 -0
  191. package/src/grapher/core/relatedQuestion.ts +12 -0
  192. package/src/grapher/core/typography.scss +206 -0
  193. package/src/grapher/dataTable/DataTable.sample.ts +206 -0
  194. package/src/grapher/dataTable/DataTable.scss +249 -0
  195. package/src/grapher/dataTable/DataTable.tsx +1332 -0
  196. package/src/grapher/dataTable/DataTableConstants.ts +186 -0
  197. package/src/grapher/entitySelector/EntitySelector.scss +255 -0
  198. package/src/grapher/entitySelector/EntitySelector.tsx +1838 -0
  199. package/src/grapher/facet/FacetChart.tsx +943 -0
  200. package/src/grapher/facet/FacetChartConstants.ts +24 -0
  201. package/src/grapher/facet/FacetChartUtils.ts +51 -0
  202. package/src/grapher/facet/FacetMap.tsx +604 -0
  203. package/src/grapher/facet/FacetMapConstants.ts +23 -0
  204. package/src/grapher/facet/readme.md +13 -0
  205. package/src/grapher/focus/FocusArray.ts +79 -0
  206. package/src/grapher/footer/Footer.scss +63 -0
  207. package/src/grapher/footer/Footer.tsx +809 -0
  208. package/src/grapher/footer/FooterManager.ts +44 -0
  209. package/src/grapher/fullScreen/FullScreen.scss +11 -0
  210. package/src/grapher/fullScreen/FullScreen.tsx +61 -0
  211. package/src/grapher/header/Header.scss +35 -0
  212. package/src/grapher/header/Header.tsx +372 -0
  213. package/src/grapher/header/HeaderManager.ts +28 -0
  214. package/src/grapher/index.ts +157 -0
  215. package/src/grapher/interaction/InteractionState.ts +60 -0
  216. package/src/grapher/legend/HorizontalColorLegends.tsx +923 -0
  217. package/src/grapher/legend/LegendInteractionState.ts +40 -0
  218. package/src/grapher/legend/VerticalColorLegend.tsx +295 -0
  219. package/src/grapher/lineCharts/LineChart.tsx +968 -0
  220. package/src/grapher/lineCharts/LineChartConstants.ts +89 -0
  221. package/src/grapher/lineCharts/LineChartHelpers.ts +184 -0
  222. package/src/grapher/lineCharts/LineChartState.ts +394 -0
  223. package/src/grapher/lineCharts/LineChartThumbnail.tsx +437 -0
  224. package/src/grapher/lineCharts/Lines.tsx +258 -0
  225. package/src/grapher/lineLegend/LineLegend.tsx +723 -0
  226. package/src/grapher/lineLegend/LineLegendConstants.ts +9 -0
  227. package/src/grapher/lineLegend/LineLegendFilterAlgorithms.ts +143 -0
  228. package/src/grapher/lineLegend/LineLegendHelpers.ts +253 -0
  229. package/src/grapher/lineLegend/LineLegendTypes.ts +32 -0
  230. package/src/grapher/mapCharts/CanadaTopology.ts +17922 -0
  231. package/src/grapher/mapCharts/ChoroplethGlobe.tsx +949 -0
  232. package/src/grapher/mapCharts/ChoroplethMap.tsx +662 -0
  233. package/src/grapher/mapCharts/GeoFeatures.ts +184 -0
  234. package/src/grapher/mapCharts/GlobeController.ts +496 -0
  235. package/src/grapher/mapCharts/MapAnnotationPlacements.json +1040 -0
  236. package/src/grapher/mapCharts/MapAnnotationPlacements.ts +31 -0
  237. package/src/grapher/mapCharts/MapAnnotations.ts +723 -0
  238. package/src/grapher/mapCharts/MapChart.sample.ts +59 -0
  239. package/src/grapher/mapCharts/MapChart.scss +5 -0
  240. package/src/grapher/mapCharts/MapChart.tsx +720 -0
  241. package/src/grapher/mapCharts/MapChartConstants.ts +260 -0
  242. package/src/grapher/mapCharts/MapChartState.ts +416 -0
  243. package/src/grapher/mapCharts/MapChartThumbnail.tsx +25 -0
  244. package/src/grapher/mapCharts/MapComponents.tsx +338 -0
  245. package/src/grapher/mapCharts/MapConfig.ts +156 -0
  246. package/src/grapher/mapCharts/MapHelpers.ts +181 -0
  247. package/src/grapher/mapCharts/MapProjections.ts +49 -0
  248. package/src/grapher/mapCharts/MapSparkline.tsx +257 -0
  249. package/src/grapher/mapCharts/MapTooltip.scss +49 -0
  250. package/src/grapher/mapCharts/MapTooltip.tsx +409 -0
  251. package/src/grapher/mapCharts/MapTopology.ts +1766 -0
  252. package/src/grapher/mapCharts/d3-bboxCollide.js +204 -0
  253. package/src/grapher/mapCharts/d3-geo-projection.ts +198 -0
  254. package/src/grapher/modal/DownloadIcons.tsx +39 -0
  255. package/src/grapher/modal/DownloadModal.scss +300 -0
  256. package/src/grapher/modal/DownloadModal.tsx +1226 -0
  257. package/src/grapher/modal/EmbedModal.scss +40 -0
  258. package/src/grapher/modal/EmbedModal.tsx +160 -0
  259. package/src/grapher/modal/EntitySelectorModal.tsx +59 -0
  260. package/src/grapher/modal/Modal.scss +31 -0
  261. package/src/grapher/modal/Modal.tsx +90 -0
  262. package/src/grapher/modal/ModalHeader.scss +12 -0
  263. package/src/grapher/modal/ModalHeader.tsx +16 -0
  264. package/src/grapher/modal/SourcesDescriptions.scss +87 -0
  265. package/src/grapher/modal/SourcesDescriptions.tsx +89 -0
  266. package/src/grapher/modal/SourcesKeyDataTable.scss +49 -0
  267. package/src/grapher/modal/SourcesKeyDataTable.tsx +87 -0
  268. package/src/grapher/modal/SourcesModal.scss +301 -0
  269. package/src/grapher/modal/SourcesModal.tsx +568 -0
  270. package/src/grapher/noDataModal/NoDataModal.tsx +125 -0
  271. package/src/grapher/scatterCharts/ConnectedScatterLegend.tsx +143 -0
  272. package/src/grapher/scatterCharts/MultiColorPolyline.tsx +129 -0
  273. package/src/grapher/scatterCharts/NoDataSection.scss +14 -0
  274. package/src/grapher/scatterCharts/NoDataSection.tsx +56 -0
  275. package/src/grapher/scatterCharts/ScatterPlotChart.tsx +792 -0
  276. package/src/grapher/scatterCharts/ScatterPlotChartConstants.ts +157 -0
  277. package/src/grapher/scatterCharts/ScatterPlotChartState.ts +678 -0
  278. package/src/grapher/scatterCharts/ScatterPlotChartThumbnail.tsx +155 -0
  279. package/src/grapher/scatterCharts/ScatterPlotTooltip.tsx +560 -0
  280. package/src/grapher/scatterCharts/ScatterPoints.tsx +153 -0
  281. package/src/grapher/scatterCharts/ScatterPointsWithLabels.tsx +708 -0
  282. package/src/grapher/scatterCharts/ScatterSizeLegend.tsx +327 -0
  283. package/src/grapher/scatterCharts/ScatterUtils.ts +265 -0
  284. package/src/grapher/scatterCharts/Triangle.tsx +41 -0
  285. package/src/grapher/schema/README.md +33 -0
  286. package/src/grapher/schema/defaultGrapherConfig.ts +100 -0
  287. package/src/grapher/schema/grapher-schema.009.yaml +781 -0
  288. package/src/grapher/schema/migrations/helpers.ts +58 -0
  289. package/src/grapher/schema/migrations/migrate.ts +75 -0
  290. package/src/grapher/schema/migrations/migrations.ts +158 -0
  291. package/src/grapher/selection/MapSelectionArray.ts +99 -0
  292. package/src/grapher/selection/SelectionArray.ts +71 -0
  293. package/src/grapher/selection/readme.md +16 -0
  294. package/src/grapher/sidePanel/SidePanel.scss +10 -0
  295. package/src/grapher/sidePanel/SidePanel.tsx +23 -0
  296. package/src/grapher/slideInDrawer/SlideInDrawer.scss +57 -0
  297. package/src/grapher/slideInDrawer/SlideInDrawer.tsx +125 -0
  298. package/src/grapher/slideshowController/SlideShowController.tsx +43 -0
  299. package/src/grapher/slideshowController/readme.md +7 -0
  300. package/src/grapher/slopeCharts/MarkX.tsx +45 -0
  301. package/src/grapher/slopeCharts/Slope.tsx +102 -0
  302. package/src/grapher/slopeCharts/SlopeChart.tsx +1152 -0
  303. package/src/grapher/slopeCharts/SlopeChartConstants.ts +33 -0
  304. package/src/grapher/slopeCharts/SlopeChartHelpers.ts +73 -0
  305. package/src/grapher/slopeCharts/SlopeChartState.ts +392 -0
  306. package/src/grapher/slopeCharts/SlopeChartThumbnail.tsx +368 -0
  307. package/src/grapher/stackedCharts/AbstractStackedChartState.ts +370 -0
  308. package/src/grapher/stackedCharts/MarimekkoBars.tsx +190 -0
  309. package/src/grapher/stackedCharts/MarimekkoBarsForOneEntity.tsx +168 -0
  310. package/src/grapher/stackedCharts/MarimekkoChart.tsx +1144 -0
  311. package/src/grapher/stackedCharts/MarimekkoChartConstants.ts +112 -0
  312. package/src/grapher/stackedCharts/MarimekkoChartHelpers.ts +21 -0
  313. package/src/grapher/stackedCharts/MarimekkoChartState.ts +465 -0
  314. package/src/grapher/stackedCharts/MarimekkoChartThumbnail.tsx +168 -0
  315. package/src/grapher/stackedCharts/MarimekkoInternalLabels.tsx +124 -0
  316. package/src/grapher/stackedCharts/StackedAreaChart.tsx +678 -0
  317. package/src/grapher/stackedCharts/StackedAreaChartState.ts +34 -0
  318. package/src/grapher/stackedCharts/StackedAreaChartThumbnail.tsx +215 -0
  319. package/src/grapher/stackedCharts/StackedAreas.tsx +223 -0
  320. package/src/grapher/stackedCharts/StackedBarChart.tsx +619 -0
  321. package/src/grapher/stackedCharts/StackedBarChartState.ts +80 -0
  322. package/src/grapher/stackedCharts/StackedBarChartThumbnail.tsx +220 -0
  323. package/src/grapher/stackedCharts/StackedBarSegment.tsx +87 -0
  324. package/src/grapher/stackedCharts/StackedBars.tsx +102 -0
  325. package/src/grapher/stackedCharts/StackedConstants.ts +109 -0
  326. package/src/grapher/stackedCharts/StackedDiscreteBarChart.tsx +270 -0
  327. package/src/grapher/stackedCharts/StackedDiscreteBarChartState.ts +296 -0
  328. package/src/grapher/stackedCharts/StackedDiscreteBarChartThumbnail.tsx +27 -0
  329. package/src/grapher/stackedCharts/StackedDiscreteBars.tsx +648 -0
  330. package/src/grapher/stackedCharts/StackedUtils.ts +142 -0
  331. package/src/grapher/tabs/Tabs.scss +169 -0
  332. package/src/grapher/tabs/Tabs.tsx +54 -0
  333. package/src/grapher/tabs/TabsWithDropdown.scss +62 -0
  334. package/src/grapher/tabs/TabsWithDropdown.tsx +114 -0
  335. package/src/grapher/testData/OwidTestData.sample.ts +273 -0
  336. package/src/grapher/testData/OwidTestData.ts +64 -0
  337. package/src/grapher/timeline/TimelineComponent.scss +139 -0
  338. package/src/grapher/timeline/TimelineComponent.tsx +658 -0
  339. package/src/grapher/timeline/TimelineController.ts +368 -0
  340. package/src/grapher/timeline/readme.md +7 -0
  341. package/src/grapher/tooltip/Tooltip.scss +510 -0
  342. package/src/grapher/tooltip/Tooltip.tsx +294 -0
  343. package/src/grapher/tooltip/TooltipContents.tsx +383 -0
  344. package/src/grapher/tooltip/TooltipProps.ts +123 -0
  345. package/src/grapher/tooltip/TooltipState.ts +81 -0
  346. package/src/grapher/verticalLabels/VerticalLabels.tsx +31 -0
  347. package/src/grapher/verticalLabels/VerticalLabelsState.ts +154 -0
  348. package/src/index.ts +226 -0
  349. package/src/styles/charts.scss +15 -0
  350. package/src/types/NominalType.ts +30 -0
  351. package/src/types/OwidOrigin.ts +18 -0
  352. package/src/types/OwidSource.ts +9 -0
  353. package/src/types/OwidVariable.ts +133 -0
  354. package/src/types/OwidVariableDisplayConfigInterface.ts +49 -0
  355. package/src/types/analyticsTypes.ts +54 -0
  356. package/src/types/dbTypes/Tags.ts +11 -0
  357. package/src/types/domainTypes/Archive.ts +139 -0
  358. package/src/types/domainTypes/Author.ts +28 -0
  359. package/src/types/domainTypes/ContentGraph.ts +76 -0
  360. package/src/types/domainTypes/CoreTableTypes.ts +305 -0
  361. package/src/types/domainTypes/DeployStatus.ts +23 -0
  362. package/src/types/domainTypes/Layout.ts +34 -0
  363. package/src/types/domainTypes/Posts.ts +34 -0
  364. package/src/types/domainTypes/Search.ts +299 -0
  365. package/src/types/domainTypes/Site.ts +8 -0
  366. package/src/types/domainTypes/StaticViz.ts +64 -0
  367. package/src/types/domainTypes/Toc.ts +11 -0
  368. package/src/types/domainTypes/Tombstone.ts +19 -0
  369. package/src/types/domainTypes/Various.ts +79 -0
  370. package/src/types/gdocTypes/Gdoc.ts +280 -0
  371. package/src/types/grapherTypes/BinningStrategyTypes.ts +46 -0
  372. package/src/types/grapherTypes/GrapherConstants.ts +53 -0
  373. package/src/types/grapherTypes/GrapherTypes.ts +743 -0
  374. package/src/types/index.ts +316 -0
  375. package/src/types/wordpressTypes/WordpressTypes.ts +9 -0
  376. package/src/utils/Bounds.ts +439 -0
  377. package/src/utils/BrowserUtils.ts +12 -0
  378. package/src/utils/FuzzySearch.ts +74 -0
  379. package/src/utils/MultiDimDataPageConfig.ts +31 -0
  380. package/src/utils/OwidVariable.ts +82 -0
  381. package/src/utils/PointVector.ts +97 -0
  382. package/src/utils/PromiseCache.ts +36 -0
  383. package/src/utils/PromiseSwitcher.ts +52 -0
  384. package/src/utils/TimeBounds.ts +130 -0
  385. package/src/utils/Tippy.tsx +57 -0
  386. package/src/utils/Util.ts +2369 -0
  387. package/src/utils/archival/archivalDate.ts +48 -0
  388. package/src/utils/dayjs.ts +32 -0
  389. package/src/utils/formatValue.ts +242 -0
  390. package/src/utils/grapherConfigUtils.ts +81 -0
  391. package/src/utils/image.ts +225 -0
  392. package/src/utils/index.ts +318 -0
  393. package/src/utils/isPresent.ts +5 -0
  394. package/src/utils/metadataHelpers.ts +329 -0
  395. package/src/utils/persistable/Persistable.ts +82 -0
  396. package/src/utils/persistable/readme.md +50 -0
  397. package/src/utils/regions.json +5635 -0
  398. package/src/utils/regions.ts +463 -0
  399. package/src/utils/serializers.ts +16 -0
  400. package/src/utils/string.ts +42 -0
  401. package/src/utils/urls/Url.ts +195 -0
  402. package/src/utils/urls/UrlMigration.ts +10 -0
  403. package/src/utils/urls/UrlUtils.ts +54 -0
  404. package/src/utils/urls/readme.md +90 -0
@@ -0,0 +1,121 @@
1
+ import { numberMagnitude, RequiredBy } from "../../utils/index.js"
2
+ import {
3
+ BinningStrategyIncludingManual,
4
+ LogBinningStrategy,
5
+ ResolvedLogBinningStrategy,
6
+ } from "../../types/index.js"
7
+ import {
8
+ calcMagnitudeDiff,
9
+ pruneUnusedBins,
10
+ ResolvedBinningStrategyConfig,
11
+ } from "./BinningStrategies.js"
12
+ import * as R from "remeda"
13
+ import { match } from "ts-pattern"
14
+
15
+ export const isLogBinningStrategy = (
16
+ strategy: BinningStrategyIncludingManual
17
+ ): strategy is LogBinningStrategy => strategy.startsWith("log-")
18
+
19
+ /**
20
+ * Automatically chooses a log binning strategy based on the magnitude difference between the min and max values.
21
+ * Very roughly, the resulting number of bins is roughly magnitudeDiff * numberOfLogSteps.
22
+ *
23
+ * The threshold numbers in here are chosen empirically by experimentation.
24
+ * The main idea is that we want to ideally have 5-8 bins, and with the number of resulting bins very roughly
25
+ * being `magnitudeDiff * numberOfLogSteps`, we arrive roughly at these thresholds:
26
+ * - for magnitudeDiff < 2.6, and 3 log steps, we'll end up with up to 8 bins
27
+ * - for magnitudeDiff between 2.6 and 3.6, and 2 log steps, we'll end up with 5 to 8 bins
28
+ * - for magnitudeDiff >= 3.6, and 1 log step, we'll end up with >=4 bins
29
+ * - ... there's probably also cases where we can end up with more than 8 bins, but these should be pretty rare
30
+ * (and in these case, the authors can still manually choose a different strategy)
31
+ */
32
+ const autoChooseLogBinningStrategy = (
33
+ magnitudeDiff: number
34
+ ): ResolvedLogBinningStrategy => {
35
+ if (magnitudeDiff >= 3.6) {
36
+ return "log-10"
37
+ }
38
+ if (magnitudeDiff >= 2.6) {
39
+ return "log-1-3"
40
+ }
41
+ return "log-1-2-5"
42
+ }
43
+
44
+ export const runLogBinningStrategy = (
45
+ conf: RequiredBy<ResolvedBinningStrategyConfig, "minValue" | "maxValue">,
46
+ { hasMidpoint }: { hasMidpoint?: boolean } = {}
47
+ ): number[] => {
48
+ const { minValue, maxValue } = conf
49
+
50
+ if (minValue <= 0 || maxValue <= 0) {
51
+ throw new Error("Log binning strategy only supports positive values")
52
+ }
53
+
54
+ let resolvedStrategy: ResolvedLogBinningStrategy
55
+ if (conf.strategy === "log-auto") {
56
+ let magnitudeDiff = calcMagnitudeDiff(minValue, maxValue)
57
+ if (hasMidpoint) magnitudeDiff *= 1.8 // If there is a midpoint, we want to create fewer bins than we would otherwise
58
+ resolvedStrategy = autoChooseLogBinningStrategy(magnitudeDiff)
59
+ } else {
60
+ resolvedStrategy = conf.strategy as ResolvedLogBinningStrategy
61
+ }
62
+
63
+ const bins = match(resolvedStrategy)
64
+ .with("log-10", () =>
65
+ createLogBins({ minValue, maxValue, logSteps: [1] })
66
+ )
67
+ .with("log-1-3", () =>
68
+ createLogBins({ minValue, maxValue, logSteps: [1, 3] })
69
+ )
70
+ .with("log-1-2-5", () =>
71
+ createLogBins({ minValue, maxValue, logSteps: [1, 2, 5] })
72
+ )
73
+ .exhaustive()
74
+
75
+ // Add the midpoint (most likely zero) if it is not already included in a bin
76
+ if (
77
+ !hasMidpoint &&
78
+ conf.midpoint !== undefined &&
79
+ bins[0] > conf.midpoint
80
+ ) {
81
+ bins.unshift(conf.midpoint)
82
+ }
83
+
84
+ return bins
85
+ }
86
+
87
+ const createLogBins = ({
88
+ minValue,
89
+ maxValue,
90
+ logSteps,
91
+ }: {
92
+ minValue: number
93
+ maxValue: number
94
+ logSteps: number[]
95
+ }): number[] => {
96
+ if (minValue <= 0 || maxValue <= 0) {
97
+ throw new Error("createLogBins only supports positive values")
98
+ }
99
+
100
+ // We need the -1 here to convert between magnitude and logarithms.
101
+ // Magnitude is defined such that magnitude(1) = 1, whereas log10(1) = 0.
102
+ // Because we generate factors as 10^magnitude, we need to adjust the values accordingly.
103
+ const exponentMin = numberMagnitude(minValue) - 1
104
+ const exponentMax = numberMagnitude(maxValue) - 1
105
+
106
+ const candidates = R.range(exponentMin, exponentMax + 1).flatMap(
107
+ (magnitude) => {
108
+ const factor = Math.pow(10, magnitude)
109
+ return logSteps.map((step) => step * factor)
110
+ }
111
+ )
112
+
113
+ // Adding this extra value at the end is useful if we have, for example, maxValue = 99.
114
+ // Then the candidates above will go up to 50 (if logSteps includes 5), and here we'll then
115
+ // add 100 to the mix.
116
+ if ((R.last(candidates) ?? 0) < maxValue) {
117
+ candidates.push(1 * Math.pow(10, exponentMax + 1))
118
+ }
119
+
120
+ return pruneUnusedBins(candidates, { minValue, maxValue })
121
+ }
@@ -0,0 +1,97 @@
1
+ import * as R from "remeda"
2
+ import { Color } from "../../utils/index.js"
3
+ import { ColorScheme } from "./ColorScheme"
4
+ import { getLeastUsedColor } from "./ColorUtils"
5
+
6
+ type CategoryId = string
7
+ export type CategoricalColorMap = Map<CategoryId, Color>
8
+ export type CategoricalColorMapReadonly = ReadonlyMap<CategoryId, Color>
9
+
10
+ export interface CategoricalColorAssignerProps {
11
+ colorScheme: ColorScheme
12
+ invertColorScheme?: boolean
13
+
14
+ /** The custom color mappings (most likely author-specified) to use. */
15
+ colorMap?: CategoricalColorMap
16
+
17
+ /**
18
+ * A cache for custom colors or automatically selected colors for each identifier
19
+ * encountered.
20
+ *
21
+ * In the Grapher, this is persisted across charts, so that a line chart
22
+ * that turns into a bar chart will have a matching color scheme across
23
+ * both states.
24
+ */
25
+ autoColorMapCache?: CategoricalColorMap
26
+
27
+ numColorsInUse?: number
28
+ }
29
+
30
+ /**
31
+ * Assigns custom categorical colors, e.g. specified by an author for entities or variables.
32
+ *
33
+ * When an identifier doesn't have an assigned color, it uses the least used color in the scheme.
34
+ *
35
+ * Keeps a cache so that identical identifiers are assigned consistent colors. See
36
+ * Grapher#seriesColorMap for an example of a cache.
37
+ */
38
+ export class CategoricalColorAssigner {
39
+ private colorScheme: ColorScheme
40
+ private invertColorScheme: boolean
41
+ private colorMap: CategoricalColorMapReadonly
42
+ private autoColorMapCache: CategoricalColorMap
43
+ private numColorsInUse?: number
44
+
45
+ constructor(props: CategoricalColorAssignerProps) {
46
+ this.colorScheme = props.colorScheme
47
+ this.invertColorScheme = props.invertColorScheme ?? false
48
+ this.colorMap = props.colorMap ?? new Map()
49
+ this.autoColorMapCache = props.autoColorMapCache ?? new Map()
50
+ this.numColorsInUse = props.numColorsInUse
51
+ }
52
+
53
+ private get usedColors(): Color[] {
54
+ const merged: CategoricalColorMap = new Map([
55
+ ...this.autoColorMapCache,
56
+ ...this.colorMap,
57
+ ])
58
+ return Array.from(merged.values())
59
+ }
60
+
61
+ private get availableColors(): Color[] {
62
+ // copy the colors array because we might need to reverse it
63
+ const colors =
64
+ (this.numColorsInUse !== undefined
65
+ ? this.colorScheme.getColors(this.numColorsInUse)
66
+ : R.last(this.colorScheme.colorSets)
67
+ )?.slice() ?? []
68
+ if (this.invertColorScheme) return colors.toReversed()
69
+ else return colors
70
+ }
71
+
72
+ private get leastUsedColor(): Color {
73
+ const leastUsedColor = getLeastUsedColor(
74
+ this.availableColors,
75
+ this.usedColors
76
+ )
77
+ // TODO handle this better?
78
+ if (leastUsedColor === undefined) {
79
+ // eslint-disable-next-line no-console
80
+ console.trace("Least used color is undefined, using black.", {
81
+ availableColors: this.availableColors,
82
+ usedColors: this.usedColors,
83
+ })
84
+ }
85
+ return leastUsedColor ?? "#000"
86
+ }
87
+
88
+ assign(id: CategoryId): Color {
89
+ let color = this.colorMap.get(id)
90
+ if (color === undefined) color = this.autoColorMapCache.get(id)
91
+ if (color === undefined && this.colorScheme.colorMap)
92
+ color = this.colorScheme.colorMap[id]
93
+ if (color === undefined) color = this.leastUsedColor
94
+ this.autoColorMapCache.set(id, color)
95
+ return color
96
+ }
97
+ }
@@ -0,0 +1,80 @@
1
+ import colorbrewer from "colorbrewer"
2
+ import {
3
+ Color,
4
+ ColorSchemeInterface,
5
+ ColorSchemeName,
6
+ } from "../../types/index.js"
7
+
8
+ type ColorSchemeProps = { displayName: string; singleColorScale: boolean }
9
+
10
+ const ColorBrewerSchemeIndex: {
11
+ [key in ColorSchemeName]?: ColorSchemeProps
12
+ } = {
13
+ YlGn: { displayName: "Yellow-Green shades", singleColorScale: true },
14
+ YlGnBu: {
15
+ displayName: "Yellow-Green-Blue shades",
16
+ singleColorScale: false,
17
+ },
18
+ GnBu: { displayName: "Green-Blue shades", singleColorScale: true },
19
+ BuGn: { displayName: "Blue-Green shades", singleColorScale: true },
20
+ PuBuGn: {
21
+ displayName: "Purple-Blue-Green shades",
22
+ singleColorScale: false,
23
+ },
24
+ BuPu: { displayName: "Blue-Purple shades", singleColorScale: true },
25
+ RdPu: { displayName: "Red-Purple shades", singleColorScale: true },
26
+ PuRd: { displayName: "Purple-Red shades", singleColorScale: true },
27
+ OrRd: { displayName: "Orange-Red shades", singleColorScale: true },
28
+ YlOrRd: {
29
+ displayName: "Yellow-Orange-Red shades",
30
+ singleColorScale: true,
31
+ },
32
+ YlOrBr: {
33
+ displayName: "Yellow-Orange-Brown shades",
34
+ singleColorScale: true,
35
+ },
36
+ Purples: { displayName: "Purple shades", singleColorScale: true },
37
+ Blues: { displayName: "Blue shades", singleColorScale: true },
38
+ Greens: { displayName: "Green shades", singleColorScale: true },
39
+ Oranges: { displayName: "Orange shades", singleColorScale: true },
40
+ Reds: { displayName: "Red shades", singleColorScale: true },
41
+ Greys: { displayName: "Grey shades", singleColorScale: true },
42
+ PuOr: { displayName: "Purple-Orange", singleColorScale: false },
43
+ BrBG: { displayName: "Brown-Blue-Green", singleColorScale: false },
44
+ PRGn: { displayName: "Purple-Red-Green", singleColorScale: false },
45
+ PiYG: { displayName: "Magenta-Yellow-Green", singleColorScale: false },
46
+ RdBu: { displayName: "Red-Blue", singleColorScale: false },
47
+ RdGy: { displayName: "Red-Grey", singleColorScale: false },
48
+ RdYlBu: { displayName: "Red-Yellow-Blue", singleColorScale: false },
49
+ Spectral: { displayName: "Spectral colors", singleColorScale: false },
50
+ RdYlGn: { displayName: "Red-Yellow-Green", singleColorScale: false },
51
+ Accent: { displayName: "Accents", singleColorScale: false },
52
+ Dark2: { displayName: "Dark colors", singleColorScale: false },
53
+ Paired: { displayName: "Paired colors", singleColorScale: false },
54
+ Pastel1: { displayName: "Pastel 1 colors", singleColorScale: false },
55
+ Pastel2: { displayName: "Pastel 2 colors", singleColorScale: false },
56
+ Set1: { displayName: "Set 1 colors", singleColorScale: false },
57
+ Set2: { displayName: "Set 2 colors", singleColorScale: false },
58
+ Set3: { displayName: "Set 3 colors", singleColorScale: false },
59
+ PuBu: { displayName: "Purple-Blue shades", singleColorScale: true },
60
+ } as const
61
+
62
+ export const getColorBrewerScheme: (
63
+ name: string
64
+ ) => ColorSchemeInterface | undefined = (name: string) => {
65
+ const props = ColorBrewerSchemeIndex[name as ColorSchemeName]
66
+ const colorSets = (colorbrewer as any)[name]
67
+
68
+ if (!props || !colorSets) return undefined
69
+
70
+ const colorSetsArray: Color[][] = []
71
+ Object.keys(colorSets).forEach(
72
+ (numColors) => (colorSetsArray[+numColors] = colorSets[numColors])
73
+ )
74
+ return {
75
+ name,
76
+ displayName: props.displayName,
77
+ colorSets: colorSetsArray,
78
+ singleColorScale: props.singleColorScale,
79
+ }
80
+ }
@@ -0,0 +1,20 @@
1
+ // gray shades
2
+ export const GRAY_100 = "#2d2e2d"
3
+ export const GRAY_90 = "#4e4e4e"
4
+ export const GRAY_80 = "#5b5b5b"
5
+ export const GRAY_70 = "#767676"
6
+ export const GRAY_60 = "#a1a1a1"
7
+ export const GRAY_50 = "#c6c6c6"
8
+ export const GRAY_30 = "#dadada"
9
+ export const GRAY_20 = "#e7e7e7"
10
+ export const GRAY_10 = "#f2f2f2"
11
+ export const GRAY_5 = "#f7f7f7"
12
+
13
+ export const GRAPHER_BACKGROUND_DEFAULT = "#ffffff"
14
+ export const GRAPHER_BACKGROUND_BEIGE = "#fbf9f3"
15
+
16
+ export const GRAPHER_DARK_TEXT = GRAY_80
17
+ export const GRAPHER_LIGHT_TEXT = GRAY_70
18
+
19
+ export const OWID_NO_DATA_GRAY = "#6e7581"
20
+ export const OWID_ERROR_COLOR = "ff0002"
@@ -0,0 +1,339 @@
1
+ import * as _ from "lodash-es"
2
+ import { computed, toJS, makeObservable } from "mobx"
3
+ import { ColorScaleConfig } from "./ColorScaleConfig"
4
+ import { mapNullToUndefined, sortNumeric } from "../../utils/index.js"
5
+ import { pairs } from "d3-array"
6
+ import { ColorSchemes } from "../color/ColorSchemes"
7
+ import { ColorScheme } from "../color/ColorScheme"
8
+ import { ColorScaleBin, NumericBin, CategoricalBin } from "./ColorScaleBin"
9
+ import { OWID_NO_DATA_GRAY } from "./ColorConstants"
10
+ import {
11
+ ColorScaleConfigInterface,
12
+ ColorSchemeName,
13
+ Color,
14
+ CoreValueType,
15
+ OwidVariableRoundingMode,
16
+ } from "../../types/index.js"
17
+ import { CoreColumn } from "../../core-table/index.js"
18
+ import * as R from "remeda"
19
+ import { runBinningStrategy } from "./BinningStrategies.js"
20
+
21
+ export const NO_DATA_LABEL = "No data"
22
+ export const PROJECTED_DATA_LABEL = "Projected data"
23
+
24
+ export interface ColorScaleManager {
25
+ colorScaleConfig?: ColorScaleConfigInterface
26
+ hasNoDataBin?: boolean
27
+ hasProjectedDataBin?: boolean
28
+ defaultNoDataColor?: string
29
+ defaultBaseColorScheme?: ColorSchemeName
30
+ colorScaleColumn?: CoreColumn
31
+ }
32
+
33
+ export class ColorScale {
34
+ private manager: Readonly<ColorScaleManager>
35
+ constructor(manager: ColorScaleManager = {}) {
36
+ makeObservable(this)
37
+ this.manager = manager
38
+ }
39
+
40
+ // Config accessors
41
+
42
+ @computed get config(): ColorScaleConfigInterface {
43
+ return this.manager.colorScaleConfig ?? new ColorScaleConfig()
44
+ }
45
+
46
+ @computed get customNumericValues(): number[] {
47
+ return this.config.customNumericValues ?? []
48
+ }
49
+
50
+ @computed get customNumericColorsActive(): boolean {
51
+ return this.config.customNumericColorsActive ?? false
52
+ }
53
+
54
+ @computed get customNumericColors(): (Color | undefined)[] {
55
+ return this.customNumericColorsActive
56
+ ? mapNullToUndefined(this.config.customNumericColors)
57
+ : []
58
+ }
59
+
60
+ @computed get customHiddenCategories(): {
61
+ [key: string]: true | undefined
62
+ } {
63
+ return this.config.customHiddenCategories ?? {}
64
+ }
65
+
66
+ @computed get customNumericLabels(): (string | undefined)[] {
67
+ if (!this.isManualBuckets) return []
68
+
69
+ const labels =
70
+ mapNullToUndefined(toJS(this.config.customNumericLabels)) || []
71
+ while (labels.length < this.numNumericBins) labels.push(undefined)
72
+ return labels
73
+ }
74
+
75
+ @computed get isColorSchemeInverted(): boolean {
76
+ return this.config.colorSchemeInvert ?? false
77
+ }
78
+
79
+ @computed private get customCategoryLabels(): {
80
+ [key: string]: string | undefined
81
+ } {
82
+ return this.config.customCategoryLabels ?? {}
83
+ }
84
+
85
+ @computed get baseColorScheme(): ColorSchemeName {
86
+ return (
87
+ this.config.baseColorScheme ??
88
+ this.manager.defaultBaseColorScheme ??
89
+ ColorSchemeName.BuGn
90
+ )
91
+ }
92
+
93
+ @computed private get defaultColorScheme(): ColorScheme {
94
+ return ColorSchemes.get(ColorSchemeName.BuGn)
95
+ }
96
+
97
+ @computed private get defaultNoDataColor(): Color {
98
+ return this.manager.defaultNoDataColor ?? OWID_NO_DATA_GRAY
99
+ }
100
+
101
+ @computed get colorScaleColumn(): CoreColumn | undefined {
102
+ return this.manager.colorScaleColumn
103
+ }
104
+
105
+ @computed get legendDescription(): string | undefined {
106
+ return this.config.legendDescription
107
+ }
108
+
109
+ // Transforms
110
+
111
+ @computed private get hasNoDataBin(): boolean {
112
+ return this.manager.hasNoDataBin || false
113
+ }
114
+
115
+ @computed private get hasProjectedDataBin(): boolean {
116
+ return this.manager.hasProjectedDataBin || false
117
+ }
118
+
119
+ @computed get sortedNumericValues(): number[] {
120
+ return sortNumeric(
121
+ this.colorScaleColumn?.values.filter(R.isNumber) ?? []
122
+ )
123
+ }
124
+
125
+ @computed private get minPossibleValue(): number | undefined {
126
+ return R.first(this.sortedNumericValues)
127
+ }
128
+
129
+ @computed private get maxPossibleValue(): number | undefined {
130
+ return R.last(this.sortedNumericValues)
131
+ }
132
+
133
+ @computed private get categoricalValues(): string[] {
134
+ return this.colorScaleColumn?.sortedUniqNonEmptyStringVals ?? []
135
+ }
136
+
137
+ @computed private get colorScheme(): ColorScheme {
138
+ return ColorSchemes.get(this.baseColorScheme) ?? this.defaultColorScheme
139
+ }
140
+
141
+ @computed get singleColorScale(): boolean {
142
+ return this.colorScheme.singleColorScale
143
+ }
144
+
145
+ @computed private get manualBinThresholds(): number[] {
146
+ if (!this.sortedNumericValues.length || this.numNumericBins <= 0)
147
+ return []
148
+
149
+ return this.customNumericValues
150
+ }
151
+
152
+ // When automatic classification is turned on, this takes the numeric map data
153
+ // and works out some discrete ranges to assign colors to
154
+ @computed get autoBinThresholds(): number[] {
155
+ if (this.config.binningStrategy === "manual") {
156
+ throw new Error(
157
+ "Cannot compute automatic bin thresholds when binning is set to manual"
158
+ )
159
+ }
160
+ return runBinningStrategy({
161
+ sortedValues: this.sortedNumericValues,
162
+ isPercent: this.colorScaleColumn?.shortUnit === "%",
163
+ numDecimalPlaces: this.colorScaleColumn?.numDecimalPlaces,
164
+
165
+ strategy: this.config.binningStrategy,
166
+ createBinForMidpoint: this.config.createBinForMidpoint,
167
+ minValue: this.config.minValue,
168
+ maxValue: this.config.maxValue,
169
+ midpoint: this.config.midpoint,
170
+ midpointMode: this.config.midpointMode,
171
+ }).bins
172
+ }
173
+
174
+ @computed private get bucketThresholds(): number[] {
175
+ return this.isManualBuckets
176
+ ? this.manualBinThresholds
177
+ : this.autoBinThresholds
178
+ }
179
+
180
+ // Ensure there's always a custom color for "No data"
181
+ @computed private get customCategoryColors(): { [key: string]: Color } {
182
+ return {
183
+ [NO_DATA_LABEL]: this.defaultNoDataColor, // default 'no data' color
184
+ ...this.config.customCategoryColors,
185
+ }
186
+ }
187
+
188
+ @computed get noDataColor(): Color {
189
+ return this.customCategoryColors[NO_DATA_LABEL]
190
+ }
191
+
192
+ @computed get baseColors(): Color[] {
193
+ const { categoricalValues, colorScheme, isColorSchemeInverted } = this
194
+ const numColors = this.numNumericBins + categoricalValues.length
195
+ const colors = colorScheme.getColors(numColors)
196
+
197
+ if (isColorSchemeInverted) return colors.toReversed()
198
+ else return colors
199
+ }
200
+
201
+ @computed get isManualBuckets(): boolean {
202
+ return this.config.binningStrategy === "manual"
203
+ }
204
+
205
+ @computed get numNumericBins(): number {
206
+ if (!this.sortedNumericValues.length) return 0
207
+
208
+ return this.isManualBuckets
209
+ ? Math.max(this.customNumericValues.length - 1, 0)
210
+ : this.autoBinThresholds.length - 1
211
+ }
212
+
213
+ @computed private get numericLegendBins(): NumericBin[] {
214
+ const {
215
+ customNumericLabels,
216
+ minPossibleValue,
217
+ maxPossibleValue,
218
+ customNumericColors,
219
+ bucketThresholds,
220
+ baseColors,
221
+ } = this
222
+
223
+ if (minPossibleValue === undefined || maxPossibleValue === undefined)
224
+ return []
225
+
226
+ return pairs(bucketThresholds).map(([min, max], index) => {
227
+ const baseColor = baseColors[index]
228
+ const color = customNumericColors[index] ?? baseColor
229
+ const label = customNumericLabels[index]
230
+
231
+ const roundingOptions = {
232
+ roundingMode: OwidVariableRoundingMode.decimalPlaces,
233
+ }
234
+ const displayMin =
235
+ this.colorScaleColumn?.formatValueShort(min, roundingOptions) ??
236
+ min.toString()
237
+ const displayMax =
238
+ this.colorScaleColumn?.formatValueShort(max, roundingOptions) ??
239
+ max.toString()
240
+
241
+ const isFirst = index === 0
242
+ const isLast = index === bucketThresholds.length - 2
243
+ return new NumericBin({
244
+ isFirst,
245
+ isOpenLeft: isFirst && min > minPossibleValue,
246
+ isOpenRight: isLast && max < maxPossibleValue,
247
+ min,
248
+ max,
249
+ color,
250
+ label,
251
+ displayMin,
252
+ displayMax,
253
+ })
254
+ })
255
+ }
256
+
257
+ @computed get legendBins(): ColorScaleBin[] {
258
+ // todo: turn comment into unit test
259
+ // Will eventually produce something like this:
260
+ // [{ min: 10, max: 20, minText: "10%", maxText: "20%", color: '#faeaef' },
261
+ // { min: 20, max: 30, minText: "20%", maxText: "30%", color: '#fefabc' },
262
+ // { value: 'Foobar', text: "Foobar Boop", color: '#bbbbbb'}]
263
+ return [
264
+ ...this.numericLegendBins,
265
+ ...this.categoricalLegendBins,
266
+ ] as ColorScaleBin[]
267
+ }
268
+
269
+ @computed get categoricalLegendBins(): CategoricalBin[] {
270
+ const {
271
+ bucketThresholds,
272
+ baseColors,
273
+ hasNoDataBin,
274
+ hasProjectedDataBin,
275
+ categoricalValues,
276
+ customCategoryColors,
277
+ customCategoryLabels,
278
+ customHiddenCategories,
279
+ colorScheme,
280
+ } = this
281
+
282
+ let allCategoricalValues = categoricalValues
283
+
284
+ // Inject "No data" bin
285
+ if (hasNoDataBin && !allCategoricalValues.includes(NO_DATA_LABEL)) {
286
+ // The color scheme colors get applied in order, starting from first, and we only use
287
+ // as many colors as there are categorical values (excluding "No data").
288
+ // So in order to leave it colorless, we want to append the "No data" label last.
289
+ // -@danielgavrilov, 2020-06-02
290
+ allCategoricalValues = [...allCategoricalValues, NO_DATA_LABEL]
291
+ }
292
+
293
+ // Inject "Projected data" bin
294
+ if (hasProjectedDataBin) {
295
+ allCategoricalValues = [
296
+ ...allCategoricalValues,
297
+ PROJECTED_DATA_LABEL,
298
+ ]
299
+ }
300
+
301
+ return allCategoricalValues.map((value, index) => {
302
+ const boundingOffset = _.isEmpty(bucketThresholds)
303
+ ? 0
304
+ : bucketThresholds.length - 1
305
+
306
+ // Use colorMap if available and the value exists in it
307
+ let baseColor: Color | undefined
308
+ if (colorScheme.colorMap && value in colorScheme.colorMap) {
309
+ baseColor = colorScheme.colorMap[value]
310
+ } else {
311
+ baseColor = baseColors[index + boundingOffset]
312
+ }
313
+
314
+ const color = customCategoryColors[value] ?? baseColor
315
+ const label = customCategoryLabels[value] ?? value
316
+
317
+ return new CategoricalBin({
318
+ index,
319
+ value,
320
+ color,
321
+ label,
322
+ isHidden: !!customHiddenCategories[value],
323
+ })
324
+ })
325
+ }
326
+
327
+ getBinForValue(
328
+ value: CoreValueType | undefined
329
+ ): ColorScaleBin | undefined {
330
+ return value === undefined
331
+ ? undefined
332
+ : this.legendBins.find((bin) => bin.contains(value))
333
+ }
334
+
335
+ getColor(value: CoreValueType | undefined): string | undefined {
336
+ if (value === undefined) return this.noDataColor
337
+ return this.getBinForValue(value)?.color
338
+ }
339
+ }