@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,678 @@
1
+ import * as _ from "lodash-es"
2
+ import * as R from "remeda"
3
+ import {
4
+ CoreColumn,
5
+ defaultIfErrorValue,
6
+ isNotErrorValue,
7
+ OwidTable,
8
+ } from "../../core-table/index.js"
9
+ import { ChartState } from "../chart/ChartInterface"
10
+ import { ColorScale, ColorScaleManager } from "../color/ColorScale"
11
+ import {
12
+ SCATTER_POINT_DEFAULT_COLOR,
13
+ ScatterPlotManager,
14
+ ScatterSeries,
15
+ SeriesPoint,
16
+ } from "./ScatterPlotChartConstants"
17
+ import { computed, makeObservable } from "mobx"
18
+ import {
19
+ autoDetectYColumnSlugs,
20
+ getShortNameForEntity,
21
+ makeSelectionArray,
22
+ } from "../chart/ChartUtils"
23
+ import {
24
+ ChartErrorInfo,
25
+ ColorSchemeName,
26
+ EntityName,
27
+ ScaleType,
28
+ ScatterPointLabelStrategy,
29
+ ColorScaleConfigInterface,
30
+ SeriesName,
31
+ ValueRange,
32
+ } from "../../types/index.js"
33
+ import {
34
+ domainExtent,
35
+ intersection,
36
+ lowerCaseFirstLetterUnlessAbbreviation,
37
+ } from "../../utils/index.js"
38
+ import { ColorScaleConfig } from "../color/ColorScaleConfig"
39
+ import { OWID_NO_DATA_GRAY } from "../color/ColorConstants"
40
+ import { AxisConfig } from "../axis/AxisConfig"
41
+ import { BASE_FONT_SIZE } from "../core/GrapherConstants"
42
+ import { SelectionArray } from "../selection/SelectionArray"
43
+ import { computeSizeDomain } from "./ScatterUtils"
44
+ import { FocusArray } from "../focus/FocusArray"
45
+ import { HorizontalAxis, VerticalAxis } from "../axis/Axis.js"
46
+
47
+ export class ScatterPlotChartState implements ChartState, ColorScaleManager {
48
+ manager: ScatterPlotManager
49
+
50
+ colorScale: ColorScale
51
+ defaultBaseColorScheme = ColorSchemeName.continents
52
+ defaultNoDataColor = OWID_NO_DATA_GRAY
53
+
54
+ constructor({ manager }: { manager: ScatterPlotManager }) {
55
+ this.manager = manager
56
+ this.colorScale = manager.colorScaleOverride ?? new ColorScale(this)
57
+ makeObservable(this)
58
+ }
59
+
60
+ @computed get inputTable(): OwidTable {
61
+ return this.manager.table
62
+ }
63
+
64
+ @computed get transformedTableFromGrapher(): OwidTable {
65
+ return (
66
+ this.manager.transformedTable ??
67
+ this.transformTable(this.inputTable)
68
+ )
69
+ }
70
+
71
+ // TODO chunk this up into multiple computeds for better performance?
72
+ @computed get transformedTable(): OwidTable {
73
+ let table = this.transformedTableFromGrapher
74
+ // We don't want to apply this transform when relative mode is also enabled, it has a
75
+ // slightly different endpoints logic that drops initial zeroes to avoid DivideByZero error.
76
+ if (this.compareEndPointsOnly && !this.manager.isRelativeMode) {
77
+ table = table.keepMinTimeAndMaxTimeForEachEntityOnly()
78
+ }
79
+ if (this.manager.isRelativeMode) {
80
+ table = table.toAverageAnnualChangeForEachEntity([
81
+ this.xColumnSlug,
82
+ this.yColumnSlug,
83
+ ])
84
+ }
85
+ return table
86
+ }
87
+
88
+ transformTable(table: OwidTable): OwidTable {
89
+ // Drop all entities that have no data in either the X or Y column.
90
+ // For some charts, this can drop more than 50% of rows, so we do it first.
91
+ // If there's no data at all for an entity, then tolerance can also not "recover" any data, so this is safe to do.
92
+ table = table.dropEntitiesThatHaveNoDataInSomeColumn([
93
+ this.xColumnSlug,
94
+ this.yColumnSlug,
95
+ ])
96
+
97
+ if (this.xScaleType === ScaleType.log && this.xColumnSlug)
98
+ table = table.replaceNonPositiveCellsForLogScale([this.xColumnSlug])
99
+
100
+ if (this.yScaleType === ScaleType.log && this.yColumnSlug)
101
+ table = table.replaceNonPositiveCellsForLogScale([this.yColumnSlug])
102
+
103
+ if (this.colorColumnSlug && this.manager.matchingEntitiesOnly)
104
+ table = table.dropRowsWithErrorValuesForColumn(this.colorColumnSlug)
105
+
106
+ // We want to "chop off" any rows outside the time domain for X and Y to avoid creating
107
+ // leading and trailing timeline times that don't really exist in the dataset.
108
+ const [timeDomainStart, timeDomainEnd] = table.timeDomainFor([
109
+ this.xColumnSlug,
110
+ this.yColumnSlug,
111
+ ])
112
+ table = table.filterByTimeRange(
113
+ timeDomainStart ?? -Infinity,
114
+ timeDomainEnd ?? Infinity
115
+ )
116
+
117
+ if (this.xOverrideTime !== undefined) {
118
+ table = table.interpolateColumnWithTolerance(this.yColumnSlug)
119
+ } else {
120
+ table = table.interpolateColumnsByClosestTimeMatch(
121
+ this.xColumnSlug,
122
+ this.yColumnSlug
123
+ )
124
+ }
125
+
126
+ // Drop any rows which have non-number values for X or Y.
127
+ // This needs to be done after the tolerance, because the tolerance may fill in some gaps.
128
+ table = table
129
+ .columnFilter(
130
+ this.xColumnSlug,
131
+ _.isNumber,
132
+ "Drop rows with non-number values in X column"
133
+ )
134
+ .columnFilter(
135
+ this.yColumnSlug,
136
+ _.isNumber,
137
+ "Drop rows with non-number values in Y column"
138
+ )
139
+
140
+ // The tolerance application might lead to some data being dropped for some years.
141
+ // For example, if X times are [2000, 2005, 2010], and Y times are [2005], then for all 3
142
+ // rows we have the same match [[2005, 2005], [2005, 2005], [2005, 2005]].
143
+ // This means we can drop 2000 and 2010 from the timeline.
144
+ // It might not make a huge difference here, but it makes a difference when there are more
145
+ // entities covering different time periods.
146
+ const [originalTimeDomainStart, originalTimeDomainEnd] =
147
+ table.originalTimeDomainFor([this.xColumnSlug, this.yColumnSlug])
148
+ table = table.filterByTimeRange(
149
+ originalTimeDomainStart ?? -Infinity,
150
+ originalTimeDomainEnd ?? Infinity
151
+ )
152
+
153
+ return table
154
+ }
155
+
156
+ transformTableForDisplay(table: OwidTable): OwidTable {
157
+ // Drop any rows which have non-number values for X or Y.
158
+ table = table
159
+ .columnFilter(
160
+ this.xColumnSlug,
161
+ _.isNumber,
162
+ "Drop rows with non-number values in X column"
163
+ )
164
+ .columnFilter(
165
+ this.yColumnSlug,
166
+ _.isNumber,
167
+ "Drop rows with non-number values in Y column"
168
+ )
169
+ return table
170
+ }
171
+
172
+ @computed get selectionArray(): SelectionArray {
173
+ return makeSelectionArray(this.manager.selection)
174
+ }
175
+
176
+ @computed get focusArray(): FocusArray {
177
+ return this.manager.focusArray ?? new FocusArray()
178
+ }
179
+
180
+ @computed get isFocusModeActive(): boolean {
181
+ return this.focusArray.hasFocusedSeries
182
+ }
183
+
184
+ // todo: remove. do this at table filter level
185
+ @computed get seriesNamesToHighlight(): Set<SeriesName> {
186
+ const seriesNames = this.selectionArray.selectedEntityNames
187
+
188
+ if (this.manager.matchingEntitiesOnly && !this.colorColumn.isMissing)
189
+ return new Set(
190
+ intersection(seriesNames, this.colorColumn.uniqEntityNames)
191
+ )
192
+
193
+ return new Set(seriesNames)
194
+ }
195
+
196
+ // todo: remove this. Should be done as a simple column transform at the data level.
197
+ // Possible to override the x axis dimension to target a special year
198
+ // In case you want to graph say, education in the past and democracy today https://ourworldindata.org/grapher/correlation-between-education-and-democracy
199
+ @computed get xOverrideTime(): number | undefined {
200
+ return this.manager.xOverrideTime
201
+ }
202
+
203
+ @computed get compareEndPointsOnly(): boolean {
204
+ return !!this.manager.compareEndPointsOnly
205
+ }
206
+
207
+ @computed get xScaleType(): ScaleType {
208
+ return this.manager.isRelativeMode
209
+ ? ScaleType.linear
210
+ : (this.manager.xAxisConfig?.scaleType ?? ScaleType.linear)
211
+ }
212
+
213
+ @computed get yScaleType(): ScaleType {
214
+ return this.manager.isRelativeMode
215
+ ? ScaleType.linear
216
+ : (this.manager.yAxisConfig?.scaleType ?? ScaleType.linear)
217
+ }
218
+
219
+ @computed get yColumnSlug(): string {
220
+ return autoDetectYColumnSlugs(this.manager)[0]
221
+ }
222
+
223
+ @computed get yColumn(): CoreColumn {
224
+ return this.transformedTable.get(this.yColumnSlug)
225
+ }
226
+
227
+ @computed get xColumnSlug(): string {
228
+ const { xColumnSlug } = this.manager
229
+ return xColumnSlug ?? this.manager.table.timeColumn.slug
230
+ }
231
+
232
+ @computed get isTimeScatter(): boolean {
233
+ return this.manager.xColumnSlug === undefined
234
+ }
235
+
236
+ @computed get xColumn(): CoreColumn {
237
+ return this.transformedTable.get(this.xColumnSlug)
238
+ }
239
+
240
+ @computed get sizeColumnSlug(): string | undefined {
241
+ return this.manager.sizeColumnSlug
242
+ }
243
+
244
+ @computed get sizeColumn(): CoreColumn {
245
+ return this.transformedTable.get(this.sizeColumnSlug)
246
+ }
247
+
248
+ @computed get colorColumnSlug(): string | undefined {
249
+ // Scatter plots only support categorical variables as color dimension
250
+ return this.manager.categoricalColorColumnSlug
251
+ }
252
+
253
+ @computed get colorColumn(): CoreColumn {
254
+ return this.transformedTable.get(this.colorColumnSlug)
255
+ }
256
+
257
+ @computed get colorScaleColumn(): CoreColumn {
258
+ return (
259
+ // For faceted charts, we have to get the values of inputTable before it's filtered by
260
+ // the faceting logic.
261
+ this.manager.colorScaleColumnOverride ?? // We need to use inputTable in order to get consistent coloring for a variable across
262
+ // charts, e.g. each continent being assigned to the same color.
263
+ // inputTable is unfiltered, so it contains every value that exists in the variable.
264
+ this.inputTable.get(this.colorColumnSlug)
265
+ )
266
+ }
267
+
268
+ @computed get colorScaleConfig(): ColorScaleConfigInterface | undefined {
269
+ return (
270
+ ColorScaleConfig.fromDSL(this.colorColumn.def) ??
271
+ this.manager.colorScale
272
+ )
273
+ }
274
+
275
+ @computed get hasNoDataBin(): boolean {
276
+ if (this.colorColumn.isMissing) return false
277
+ return this.colorColumn.valuesIncludingErrorValues.some(
278
+ (value) => !isNotErrorValue(value)
279
+ )
280
+ }
281
+
282
+ @computed private get allEntityNamesWithXAndY(): EntityName[] {
283
+ return intersection(
284
+ this.yColumn.uniqEntityNames,
285
+ this.xColumn.uniqEntityNames
286
+ )
287
+ }
288
+
289
+ private assignColorToSeries(
290
+ entityName: EntityName,
291
+ series: ScatterSeries
292
+ ): void {
293
+ if (series.points.length) {
294
+ const keyColor =
295
+ this.transformedTable.getColorForEntityName(entityName)
296
+ if (keyColor !== undefined) series.color = keyColor
297
+ else if (!this.colorColumn.isMissing) {
298
+ const colorValue = R.last(series.points)?.color
299
+ const color = this.colorScale.getColor(colorValue)
300
+ if (color !== undefined) {
301
+ series.color = color
302
+ series.isScaleColor = true
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ @computed get fontSize(): number {
309
+ return this.manager.fontSize ?? BASE_FONT_SIZE
310
+ }
311
+
312
+ @computed private get xAxisConfig(): AxisConfig {
313
+ return new AxisConfig(this.manager.xAxisConfig, this)
314
+ }
315
+
316
+ @computed private get yAxisConfig(): AxisConfig {
317
+ return new AxisConfig(this.manager.yAxisConfig, this)
318
+ }
319
+
320
+ private removePointsOutsidePlane(points: SeriesPoint[]): SeriesPoint[] {
321
+ const { xAxisConfig, yAxisConfig } = this
322
+
323
+ if (
324
+ yAxisConfig.removePointsOutsideDomain ||
325
+ xAxisConfig.removePointsOutsideDomain
326
+ ) {
327
+ return points.filter((point) => {
328
+ return (
329
+ !xAxisConfig.shouldRemovePoint(point.x) &&
330
+ !yAxisConfig.shouldRemovePoint(point.y)
331
+ )
332
+ })
333
+ }
334
+ return points
335
+ }
336
+
337
+ private getPointLabel(rowIndex: number): string | undefined {
338
+ const strat = this.manager.scatterPointLabelStrategy
339
+ const { xColumn, yColumn } = this
340
+ const { timeColumn } = this.transformedTable
341
+ let label
342
+ if (strat === ScatterPointLabelStrategy.y) {
343
+ label = yColumn?.formatValue(
344
+ yColumn.valuesIncludingErrorValues[rowIndex]
345
+ )
346
+ } else if (strat === ScatterPointLabelStrategy.x) {
347
+ label = xColumn?.formatValue(
348
+ xColumn.valuesIncludingErrorValues[rowIndex]
349
+ )
350
+ } else {
351
+ label = timeColumn.formatTime(
352
+ timeColumn.valuesIncludingErrorValues[rowIndex] as number
353
+ )
354
+ }
355
+ return label
356
+ }
357
+
358
+ @computed private get allPointsBeforeEndpointsFilter(): SeriesPoint[] {
359
+ const { entityNameColumn, timeColumn } = this.transformedTable
360
+ const { xColumn, yColumn, sizeColumn, colorColumn } = this
361
+
362
+ // We are running this filter first because it only depends on author-specified config, not
363
+ // on any user interaction.
364
+ return this.removePointsOutsidePlane(
365
+ this.transformedTable.indices.map((rowIndex) => {
366
+ return {
367
+ x: xColumn.valuesIncludingErrorValues[rowIndex] as number,
368
+ y: yColumn.valuesIncludingErrorValues[rowIndex] as number,
369
+ size: defaultIfErrorValue(
370
+ sizeColumn.valuesIncludingErrorValues[rowIndex],
371
+ undefined
372
+ ) as number | undefined,
373
+ color: defaultIfErrorValue(
374
+ colorColumn.valuesIncludingErrorValues[rowIndex],
375
+ undefined
376
+ ) as string | number | undefined,
377
+ entityName: entityNameColumn.valuesIncludingErrorValues[
378
+ rowIndex
379
+ ] as EntityName,
380
+ label: this.getPointLabel(rowIndex) ?? "",
381
+ timeValue: timeColumn.valuesIncludingErrorValues[
382
+ rowIndex
383
+ ] as number,
384
+ time: {
385
+ x: xColumn.originalTimeColumn
386
+ .valuesIncludingErrorValues[rowIndex] as number,
387
+ y: yColumn.originalTimeColumn
388
+ .valuesIncludingErrorValues[rowIndex] as number,
389
+ // Technically, to be more correct, we should support distinct
390
+ // start and end times for each axis, but for simplicity we use
391
+ // a single span (see getAverageAnnualChangeIndicesByEntity)
392
+ span: this.manager.isRelativeMode
393
+ ? [
394
+ yColumn.originalStartTimeColumn
395
+ .valuesIncludingErrorValues[
396
+ rowIndex
397
+ ] as number,
398
+ yColumn.originalTimeColumn
399
+ .valuesIncludingErrorValues[
400
+ rowIndex
401
+ ] as number,
402
+ ]
403
+ : undefined,
404
+ },
405
+ }
406
+ })
407
+ )
408
+ }
409
+
410
+ @computed get series(): ScatterSeries[] {
411
+ return Object.entries(
412
+ _.groupBy(this.allPointsBeforeEndpointsFilter, (p) => p.entityName)
413
+ ).map(([entityName, points]) => {
414
+ const shortEntityName = getShortNameForEntity(entityName)
415
+ const series: ScatterSeries = {
416
+ seriesName: entityName,
417
+ label: shortEntityName ?? entityName,
418
+ color: SCATTER_POINT_DEFAULT_COLOR,
419
+ points,
420
+ focus: this.focusArray.state(entityName),
421
+ }
422
+ this.assignColorToSeries(entityName, series)
423
+ return series
424
+ })
425
+ }
426
+
427
+ /** Whether series are shown as lines (instead of single points) */
428
+ @computed get isConnected(): boolean {
429
+ return this.series.some((s) => s.points.length > 1)
430
+ }
431
+
432
+ @computed get allPoints(): SeriesPoint[] {
433
+ return this.series.flatMap((series) => series.points)
434
+ }
435
+
436
+ @computed private get selectedPoints(): SeriesPoint[] {
437
+ const seriesNamesSet = this.seriesNamesToHighlight
438
+ return this.allPoints.filter(
439
+ (point) => point.entityName && seriesNamesSet.has(point.entityName)
440
+ )
441
+ }
442
+
443
+ @computed get pointsForAxisDomains(): SeriesPoint[] {
444
+ if (
445
+ !this.selectionArray.numSelectedEntities ||
446
+ !this.manager.zoomToSelection
447
+ )
448
+ return this.allPoints
449
+
450
+ return this.selectedPoints.length ? this.selectedPoints : this.allPoints
451
+ }
452
+
453
+ // domains across the entire timeline
454
+ private domainDefault(property: "x" | "y"): [number, number] {
455
+ const scaleType = property === "x" ? this.xScaleType : this.yScaleType
456
+ const defaultDomain: [number, number] =
457
+ scaleType === ScaleType.log ? [1, 100] : [-1, 1]
458
+ return (
459
+ domainExtent(
460
+ this.pointsForAxisDomains.map((point) => point[property]),
461
+ scaleType,
462
+ this.manager.zoomToSelection && this.selectedPoints.length
463
+ ? 1.1
464
+ : 1
465
+ ) ?? defaultDomain
466
+ )
467
+ }
468
+
469
+ @computed get xDomainDefault(): [number, number] {
470
+ return this.domainDefault("x")
471
+ }
472
+
473
+ @computed get yDomainDefault(): [number, number] {
474
+ return this.domainDefault("y")
475
+ }
476
+
477
+ @computed get sizeDomain(): [number, number] {
478
+ if (this.sizeColumn.isMissing) return [1, 100]
479
+ if (
480
+ this.manager.isSingleTimeScatterAnimationActive &&
481
+ this.domainsForAnimation.size
482
+ ) {
483
+ return this.domainsForAnimation.size
484
+ }
485
+ return computeSizeDomain(this.transformedTable, this.sizeColumn.slug)
486
+ }
487
+
488
+ @computed get domainsForAnimation(): {
489
+ x?: ValueRange
490
+ y?: ValueRange
491
+ size?: ValueRange
492
+ } {
493
+ const { inputTable } = this
494
+ const { animationStartTime, animationEndTime } = this.manager
495
+
496
+ if (!animationStartTime || !animationEndTime) return {}
497
+
498
+ let table = inputTable.filterByTimeRange(
499
+ animationStartTime,
500
+ animationEndTime
501
+ )
502
+
503
+ if (this.manager.matchingEntitiesOnly && !this.colorColumn.isMissing) {
504
+ table = table.filterByEntityNames(
505
+ table.get(this.colorColumnSlug).uniqEntityNames
506
+ )
507
+ }
508
+
509
+ table = table
510
+ .columnFilter(
511
+ this.xColumnSlug,
512
+ _.isNumber,
513
+ "Drop rows with non-number values in X column"
514
+ )
515
+ .columnFilter(
516
+ this.yColumnSlug,
517
+ _.isNumber,
518
+ "Drop rows with non-number values in Y column"
519
+ )
520
+
521
+ const xValues = table.get(this.xColumnSlug).uniqValues
522
+ const yValues = table.get(this.yColumnSlug).uniqValues
523
+
524
+ return {
525
+ x: domainExtent(xValues, this.xScaleType),
526
+ y: domainExtent(yValues, this.yScaleType),
527
+ size: computeSizeDomain(table, this.sizeColumn.slug),
528
+ }
529
+ }
530
+
531
+ @computed get validValuesForAxisDomainX(): number[] {
532
+ const { xScaleType, pointsForAxisDomains } = this
533
+
534
+ const values = pointsForAxisDomains.map((point) => point.x)
535
+ return xScaleType === ScaleType.log
536
+ ? values.filter((v) => v > 0)
537
+ : values
538
+ }
539
+
540
+ @computed get validValuesForAxisDomainY(): number[] {
541
+ const { yScaleType, pointsForAxisDomains } = this
542
+
543
+ const values = pointsForAxisDomains.map((point) => point.y)
544
+ return yScaleType === ScaleType.log
545
+ ? values.filter((v) => v > 0)
546
+ : values
547
+ }
548
+
549
+ @computed get verticalAxisLabel(): string {
550
+ const yAxisConfig = this.manager.yAxisConfig
551
+
552
+ let label = yAxisConfig?.label || this.yColumn?.displayName || ""
553
+
554
+ if (this.manager.isRelativeMode && label && label.length > 1) {
555
+ label = `Average annual change in ${lowerCaseFirstLetterUnlessAbbreviation(
556
+ label
557
+ )}`
558
+ }
559
+
560
+ return label.trim()
561
+ }
562
+
563
+ @computed private get horizontalAxisLabelBase(): string {
564
+ const xDimName = this.xColumn?.displayName ?? ""
565
+ if (this.xOverrideTime !== undefined)
566
+ return `${xDimName} in ${this.xOverrideTime}`
567
+ return xDimName
568
+ }
569
+
570
+ @computed get horizontalAxisLabel(): string {
571
+ const xAxisConfig = this.manager.xAxisConfig
572
+
573
+ let label = xAxisConfig?.label || this.horizontalAxisLabelBase
574
+ if (this.manager.isRelativeMode && label && label.length > 1) {
575
+ label = `Average annual change in ${lowerCaseFirstLetterUnlessAbbreviation(
576
+ label
577
+ )}`
578
+ }
579
+
580
+ return label.trim()
581
+ }
582
+
583
+ toHorizontalAxis(config: AxisConfig): HorizontalAxis {
584
+ const axis = config.toHorizontalAxis()
585
+
586
+ axis.formatColumn = this.xColumn
587
+ axis.scaleType = this.xScaleType
588
+
589
+ if (this.horizontalAxisLabel) axis.label = this.horizontalAxisLabel
590
+
591
+ if (
592
+ this.manager.isSingleTimeScatterAnimationActive &&
593
+ this.domainsForAnimation.x
594
+ ) {
595
+ axis.updateDomainPreservingUserSettings(this.domainsForAnimation.x)
596
+ } else if (this.manager.isRelativeMode) {
597
+ axis.domain = this.xDomainDefault // Overwrite author's min/max
598
+ } else {
599
+ const isAnyValueOutsideUserDomain =
600
+ this.validValuesForAxisDomainX.some(
601
+ (value) => value < axis.domain[0] || value > axis.domain[1]
602
+ )
603
+
604
+ // only overwrite the authors's min/max if there is more than one unique value along the x-axis
605
+ // or if respecting the author's setting would hide data points
606
+ if (
607
+ new Set(this.validValuesForAxisDomainX).size > 1 ||
608
+ isAnyValueOutsideUserDomain
609
+ ) {
610
+ axis.updateDomainPreservingUserSettings(this.xDomainDefault)
611
+ }
612
+ }
613
+
614
+ return axis
615
+ }
616
+
617
+ toVerticalAxis(config: AxisConfig): VerticalAxis {
618
+ const axis = config.toVerticalAxis()
619
+
620
+ axis.formatColumn = this.yColumn
621
+ axis.scaleType = this.yScaleType
622
+ if (this.verticalAxisLabel) axis.label = this.verticalAxisLabel
623
+
624
+ if (
625
+ this.manager.isSingleTimeScatterAnimationActive &&
626
+ this.domainsForAnimation.y
627
+ ) {
628
+ axis.updateDomainPreservingUserSettings(this.domainsForAnimation.y)
629
+ } else if (this.manager.isRelativeMode) {
630
+ axis.domain = this.yDomainDefault // Overwrite author's min/max
631
+ } else {
632
+ const isAnyValueOutsideUserDomain =
633
+ this.validValuesForAxisDomainY.some(
634
+ (value) => value < axis.domain[0] || value > axis.domain[1]
635
+ )
636
+
637
+ // only overwrite the authors's min/max if there is more than one unique value along the y-axis
638
+ // or if respecting the author's setting would hide data points
639
+ if (
640
+ new Set(this.validValuesForAxisDomainY).size > 1 ||
641
+ isAnyValueOutsideUserDomain
642
+ ) {
643
+ axis.updateDomainPreservingUserSettings(this.yDomainDefault)
644
+ }
645
+ }
646
+
647
+ return axis
648
+ }
649
+
650
+ @computed get errorInfo(): ChartErrorInfo {
651
+ if (this.yColumn.isMissing) return { reason: "Missing Y axis variable" }
652
+
653
+ if (this.xColumn.isMissing) return { reason: "Missing X axis variable" }
654
+
655
+ const { entityTypePlural = "entities" } = this.manager
656
+ if (_.isEmpty(this.allEntityNamesWithXAndY)) {
657
+ if (
658
+ this.manager.isRelativeMode &&
659
+ this.manager.hasTimeline &&
660
+ this.manager.startTime === this.manager.endTime
661
+ ) {
662
+ return {
663
+ reason: "Please select a start and end point on the timeline below",
664
+ }
665
+ }
666
+ return {
667
+ reason: `No ${entityTypePlural} with data for both X and Y`,
668
+ }
669
+ }
670
+
671
+ if (_.isEmpty(this.series))
672
+ return {
673
+ reason: `No data for any ${entityTypePlural}`,
674
+ }
675
+
676
+ return { reason: "" }
677
+ }
678
+ }