@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,792 @@
1
+ import * as _ from "lodash-es"
2
+ import React from "react"
3
+ import { EntitySelectionMode, SeriesName, Color } from "../../types/index.js"
4
+ import { observable, computed, action, makeObservable } from "mobx"
5
+ import { ScaleLinear, scaleSqrt } from "d3-scale"
6
+ import { Quadtree, quadtree } from "d3-quadtree"
7
+ import { pairs } from "d3-array"
8
+ import { quantize, interpolate } from "d3-interpolate"
9
+ import {
10
+ intersection,
11
+ excludeUndefined,
12
+ getRelativeMouse,
13
+ exposeInstanceOnWindow,
14
+ PointVector,
15
+ Bounds,
16
+ isTouchDevice,
17
+ makeIdForHumanConsumption,
18
+ } from "../../utils/index.js"
19
+ import { observer } from "mobx-react"
20
+ import { NoDataModal } from "../noDataModal/NoDataModal"
21
+ import {
22
+ BASE_FONT_SIZE,
23
+ DEFAULT_GRAPHER_BOUNDS,
24
+ } from "../core/GrapherConstants"
25
+ import {
26
+ OwidTable,
27
+ isNotErrorValue,
28
+ CoreColumn,
29
+ } from "../../core-table/index.js"
30
+ import {
31
+ ConnectedScatterLegend,
32
+ ConnectedScatterLegendManager,
33
+ } from "./ConnectedScatterLegend"
34
+ import {
35
+ VerticalColorLegend,
36
+ VerticalColorLegendManager,
37
+ } from "../legend/VerticalColorLegend"
38
+ import { DualAxisComponent } from "../axis/AxisViews"
39
+ import { DualAxis, HorizontalAxis, VerticalAxis } from "../axis/Axis"
40
+
41
+ import { ColorScale, NO_DATA_LABEL } from "../color/ColorScale"
42
+ import { AxisConfig, AxisManager } from "../axis/AxisConfig"
43
+ import { ChartInterface } from "../chart/ChartInterface"
44
+ import { getShortNameForEntity } from "../chart/ChartUtils"
45
+ import {
46
+ ScatterPlotManager,
47
+ ScatterSeries,
48
+ SCATTER_LABEL_DEFAULT_FONT_SIZE_FACTOR,
49
+ SCATTER_LABEL_MAX_FONT_SIZE_FACTOR,
50
+ SCATTER_LABEL_MIN_FONT_SIZE_FACTOR,
51
+ SCATTER_POINT_OPACITY,
52
+ SeriesPoint,
53
+ ScatterPointQuadtreeNode,
54
+ SCATTER_QUADTREE_SAMPLING_DISTANCE,
55
+ } from "./ScatterPlotChartConstants"
56
+ import { ScatterPointsWithLabels } from "./ScatterPointsWithLabels"
57
+ import { ColorScaleBin } from "../color/ColorScaleBin"
58
+ import {
59
+ LegendInteractionState,
60
+ LegendStyleConfig,
61
+ } from "../legend/LegendInteractionState"
62
+ import {
63
+ ScatterSizeLegend,
64
+ ScatterSizeLegendManager,
65
+ } from "./ScatterSizeLegend"
66
+ import { TooltipState } from "../tooltip/Tooltip"
67
+ import { NoDataSection } from "./NoDataSection"
68
+ import { ScatterPlotChartState } from "./ScatterPlotChartState"
69
+ import { ChartComponentProps } from "../chart/ChartTypeMap.js"
70
+ import { toSizeRange } from "./ScatterUtils.js"
71
+ import { ScatterPlotTooltip } from "./ScatterPlotTooltip"
72
+ import { GRAY_100, GRAY_60 } from "../color/ColorConstants"
73
+ import { INACTIVE_SCATTER_POINT_COLOR } from "./ScatterPoints"
74
+
75
+ export type ScatterPlotChartProps = ChartComponentProps<ScatterPlotChartState>
76
+
77
+ @observer
78
+ export class ScatterPlotChart
79
+ extends React.Component<ScatterPlotChartProps>
80
+ implements
81
+ ConnectedScatterLegendManager,
82
+ ScatterSizeLegendManager,
83
+ ChartInterface,
84
+ VerticalColorLegendManager,
85
+ AxisManager
86
+ {
87
+ constructor(props: ScatterPlotChartProps) {
88
+ super(props)
89
+
90
+ makeObservable<ScatterPlotChart, "hoveredLegendColor">(this, {
91
+ hoveredLegendColor: observable,
92
+ tooltipState: observable,
93
+ })
94
+ }
95
+
96
+ // currently hovered legend color
97
+ private hoveredLegendColor: Color | undefined = undefined
98
+ // current hovered individual series + tooltip position
99
+ tooltipState = new TooltipState<{
100
+ series: ScatterSeries
101
+ }>()
102
+
103
+ legendStyleConfig: LegendStyleConfig = {
104
+ marker: {
105
+ default: { opacity: SCATTER_POINT_OPACITY },
106
+ muted: { fill: INACTIVE_SCATTER_POINT_COLOR },
107
+ },
108
+ text: { muted: { color: GRAY_60 }, focused: { color: GRAY_100 } },
109
+ }
110
+
111
+ @computed get chartState(): ScatterPlotChartState {
112
+ return this.props.chartState
113
+ }
114
+
115
+ @computed private get manager(): ScatterPlotManager {
116
+ return this.chartState.manager
117
+ }
118
+
119
+ @computed private get colorScale(): ColorScale {
120
+ return this.chartState.colorScale
121
+ }
122
+
123
+ @computed private get transformedTable(): OwidTable {
124
+ return this.chartState.transformedTable
125
+ }
126
+
127
+ @computed.struct private get bounds(): Bounds {
128
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
129
+ }
130
+
131
+ @computed private get innerBounds(): Bounds {
132
+ return (
133
+ this.bounds
134
+ .padRight(this.sidebarWidth > 0 ? this.sidebarWidth + 20 : 0)
135
+ // top padding leaves room for tick labels
136
+ .padTop(this.chartState.verticalAxisLabel ? 0 : 6)
137
+ // bottom padding makes sure the x-axis label doesn't overflow
138
+ .padBottom(2)
139
+ )
140
+ }
141
+
142
+ @computed get axisBounds(): Bounds {
143
+ return this.innerBounds
144
+ }
145
+
146
+ @computed get isStatic(): boolean {
147
+ return !!this.manager.isStatic
148
+ }
149
+
150
+ @computed private get canAddCountry(): boolean {
151
+ const { addCountryMode } = this.manager
152
+ return (addCountryMode &&
153
+ addCountryMode !== EntitySelectionMode.Disabled) as boolean
154
+ }
155
+
156
+ @action.bound private onSelectEntity(entityName: SeriesName): void {
157
+ if (this.canAddCountry)
158
+ this.chartState.selectionArray.toggleSelection(entityName)
159
+ }
160
+
161
+ // Returns the colors that are used by all points, *across the whole timeline*.
162
+ // This is why we need the table before the timeline filter is applied.
163
+ @computed private get colorsInUse(): Color[] {
164
+ const allValues =
165
+ this.manager.tableAfterAuthorTimelineAndActiveChartTransform?.get(
166
+ this.colorColumnSlug
167
+ )?.valuesIncludingErrorValues ?? []
168
+
169
+ // Need to convert InvalidCell to undefined for color scale to assign correct color
170
+ const colorValues = _.uniq(
171
+ allValues.map((value: any) =>
172
+ isNotErrorValue(value) ? value : undefined
173
+ )
174
+ ) as (string | number)[]
175
+
176
+ return excludeUndefined(
177
+ colorValues.map((colorValue) =>
178
+ this.colorScale.getColor(colorValue)
179
+ )
180
+ )
181
+ }
182
+
183
+ @computed get detailsOrderedByReference(): string[] {
184
+ return this.manager.detailsOrderedByReference ?? []
185
+ }
186
+
187
+ @computed get fontSize(): number {
188
+ return this.manager.fontSize ?? BASE_FONT_SIZE
189
+ }
190
+
191
+ @action.bound onLegendMouseOver(bin: ColorScaleBin): void {
192
+ if (isTouchDevice()) return
193
+ this.hoveredLegendColor = bin.color
194
+ }
195
+
196
+ @action.bound onLegendMouseLeave(): void {
197
+ if (isTouchDevice()) return
198
+ this.hoveredLegendColor = undefined
199
+ }
200
+
201
+ legendCursor = "pointer"
202
+
203
+ // When the color legend is clicked, toggle selection fo all associated keys
204
+ @action.bound onLegendClick(bin: ColorScaleBin): void {
205
+ const { selectionArray } = this.chartState
206
+ if (!this.canAddCountry) return
207
+
208
+ const color = bin.color
209
+
210
+ // Find all entities that match the clicked color
211
+ const colorMatchingSeriesNames = this.series
212
+ .filter((g) => g.color === color)
213
+ .map((g) => g.seriesName)
214
+
215
+ // Check if all these entities are already selected
216
+ const allColorMatchingSeriesAreSelected =
217
+ intersection(colorMatchingSeriesNames, this.selectedEntityNames)
218
+ .length === colorMatchingSeriesNames.length
219
+
220
+ // If all matching entities are selected, deselect them;
221
+ // Otherwise select them
222
+ if (allColorMatchingSeriesAreSelected)
223
+ selectionArray.setSelectedEntities(
224
+ _.without(this.selectedEntityNames, ...colorMatchingSeriesNames)
225
+ )
226
+ else
227
+ selectionArray.setSelectedEntities(
228
+ _.uniq(
229
+ this.selectedEntityNames.concat(colorMatchingSeriesNames)
230
+ )
231
+ )
232
+ }
233
+
234
+ @computed private get hoveredSeriesNames(): string[] {
235
+ const { hoveredLegendColor, tooltipState } = this
236
+
237
+ const hoveredSeriesNames =
238
+ hoveredLegendColor === undefined
239
+ ? []
240
+ : _.uniq(
241
+ this.series
242
+ .filter((g) => g.color === hoveredLegendColor)
243
+ .map((g) => g.seriesName)
244
+ )
245
+
246
+ if (tooltipState.target) {
247
+ hoveredSeriesNames.push(tooltipState.target.series.seriesName)
248
+ }
249
+
250
+ return hoveredSeriesNames
251
+ }
252
+
253
+ @computed private get isHoverModeActive(): boolean {
254
+ const { hoveredLegendColor, tooltipState } = this
255
+ return !!(
256
+ hoveredLegendColor !== undefined ||
257
+ this.hoveredSeriesNames.length > 0 ||
258
+ tooltipState.target
259
+ )
260
+ }
261
+
262
+ @computed private get selectedEntityNames(): string[] {
263
+ return this.chartState.selectionArray.selectedEntityNames
264
+ }
265
+
266
+ @computed get displayStartTime(): string {
267
+ return this.transformedTable.timeColumn.formatTime(
268
+ this.transformedTable.minTime ?? 1900
269
+ )
270
+ }
271
+
272
+ @computed get displayEndTime(): string {
273
+ return this.transformedTable.timeColumn.formatTime(
274
+ this.transformedTable.maxTime ?? 2000
275
+ )
276
+ }
277
+
278
+ @computed private get arrowLegend(): ConnectedScatterLegend | undefined {
279
+ if (
280
+ this.displayStartTime === this.displayEndTime ||
281
+ this.xColumn.isTimeColumn ||
282
+ this.yColumn.isTimeColumn ||
283
+ this.manager.isRelativeMode ||
284
+ this.manager.isDisplayedAlongsideComplementaryTable
285
+ )
286
+ return undefined
287
+
288
+ return new ConnectedScatterLegend(this)
289
+ }
290
+
291
+ @action.bound private onScatterMouseEnter(series: ScatterSeries): void {
292
+ this.tooltipState.target = { series }
293
+ }
294
+
295
+ @action.bound private onScatterMouseLeave(): void {
296
+ this.tooltipState.target = null
297
+ }
298
+
299
+ @action.bound private onScatterMouseMove(
300
+ ev: React.MouseEvent<SVGGElement>
301
+ ): void {
302
+ const ref = this.manager?.base?.current
303
+ if (ref) {
304
+ this.tooltipState.position = getRelativeMouse(ref, ev)
305
+ }
306
+ }
307
+
308
+ @action.bound private onScatterClick(): void {
309
+ const { target } = this.tooltipState
310
+ if (target) this.onSelectEntity(target.series.seriesName)
311
+ }
312
+
313
+ @computed get tooltipSeries(): ScatterSeries | undefined {
314
+ return this.tooltipState.target?.series
315
+ }
316
+
317
+ @computed private get verticalColorLegend():
318
+ | VerticalColorLegend
319
+ | undefined {
320
+ if (
321
+ this.categoricalLegendData.length === 0 ||
322
+ this.manager.isDisplayedAlongsideComplementaryTable
323
+ )
324
+ return undefined
325
+ return new VerticalColorLegend({ manager: this })
326
+ }
327
+
328
+ @computed get maxLegendWidth(): number {
329
+ return this.sidebarMaxWidth
330
+ }
331
+
332
+ @computed private get sidebarMinWidth(): number {
333
+ return Math.max(this.bounds.width * 0.1, 60)
334
+ }
335
+
336
+ @computed private get sidebarMaxWidth(): number {
337
+ return Math.max(this.bounds.width * 0.2, this.sidebarMinWidth)
338
+ }
339
+
340
+ @computed.struct get sidebarWidth(): number {
341
+ const { sidebarMinWidth, sidebarMaxWidth } = this
342
+
343
+ if (
344
+ !this.verticalColorLegend &&
345
+ !this.sizeLegend &&
346
+ !this.arrowLegend &&
347
+ !this.hasNoDataSection
348
+ )
349
+ return 0
350
+
351
+ return Math.max(
352
+ Math.min(this.verticalColorLegend?.width ?? 0, sidebarMaxWidth),
353
+ sidebarMinWidth
354
+ )
355
+ }
356
+
357
+ @computed get dualAxis(): DualAxis {
358
+ const { horizontalAxisPart, verticalAxisPart } = this
359
+ return new DualAxis({
360
+ bounds: this.axisBounds,
361
+ horizontalAxis: horizontalAxisPart,
362
+ verticalAxis: verticalAxisPart,
363
+ comparisonLines: this.manager.comparisonLines,
364
+ })
365
+ }
366
+
367
+ @computed get yAxis(): VerticalAxis {
368
+ return this.dualAxis.verticalAxis
369
+ }
370
+
371
+ @computed get xAxis(): HorizontalAxis {
372
+ return this.dualAxis.horizontalAxis
373
+ }
374
+
375
+ @action.bound private onToggleEndpoints(): void {
376
+ this.manager.compareEndPointsOnly =
377
+ !this.compareEndPointsOnly || undefined
378
+ }
379
+
380
+ /** Legend colors that are currently highlighted (either hovered or have at least one selected series) */
381
+ @computed get activeColors(): string[] {
382
+ const { hoveredSeriesNames, selectedEntityNames, hoveredLegendColor } =
383
+ this
384
+
385
+ const activeColorsSet = new Set<string>()
386
+
387
+ if (hoveredLegendColor !== undefined)
388
+ activeColorsSet.add(hoveredLegendColor)
389
+
390
+ // Add colors from selected/hovered series
391
+ const activeSeriesNames = hoveredSeriesNames.concat(selectedEntityNames)
392
+ if (activeSeriesNames.length > 0) {
393
+ const activeSeries = this.series.filter((g) =>
394
+ activeSeriesNames.includes(g.seriesName)
395
+ )
396
+
397
+ const colorValues = _.uniq(
398
+ activeSeries.flatMap((s) => s.points.map((p) => p.color))
399
+ )
400
+
401
+ excludeUndefined(
402
+ colorValues.map((color) => this.colorScale.getColor(color))
403
+ ).forEach((color) => activeColorsSet.add(color))
404
+ }
405
+
406
+ // If nothing is active (no hover, no selection), show all colors
407
+ if (activeColorsSet.size === 0) return this.colorsInUse
408
+
409
+ return Array.from(activeColorsSet)
410
+ }
411
+
412
+ getLegendBinState(bin: ColorScaleBin): LegendInteractionState {
413
+ const isActive = this.activeColors.includes(bin.color)
414
+ return isActive
415
+ ? LegendInteractionState.Focused
416
+ : LegendInteractionState.Muted
417
+ }
418
+
419
+ @computed private get hideConnectedScatterLines(): boolean {
420
+ return !!this.manager.hideConnectedScatterLines
421
+ }
422
+
423
+ @computed private get hideScatterLabels(): boolean {
424
+ return !!this.manager.hideScatterLabels
425
+ }
426
+
427
+ @computed private get quadtree(): Quadtree<ScatterPointQuadtreeNode> {
428
+ const {
429
+ series: seriesArray,
430
+ dualAxis: { horizontalAxis, verticalAxis, innerBounds },
431
+ } = this
432
+
433
+ const xAxis = horizontalAxis.clone()
434
+ xAxis.range = innerBounds.xRange()
435
+ const yAxis = verticalAxis.clone()
436
+ yAxis.range = innerBounds.yRange()
437
+
438
+ const nodes: ScatterPointQuadtreeNode[] = seriesArray.flatMap(
439
+ (series) => {
440
+ const points = series.points.map((point) => {
441
+ return new PointVector(
442
+ xAxis.place(point.x),
443
+ yAxis.place(point.y)
444
+ )
445
+ })
446
+
447
+ // add single points as is
448
+ if (points.length < 2)
449
+ return points.map((point) => ({
450
+ series,
451
+ x: point.x,
452
+ y: point.y,
453
+ }))
454
+
455
+ // sample points from line segments with a fixed step size
456
+ return pairs(points).flatMap(([a, b]) => {
457
+ const numPoints =
458
+ 2 + // always include endpoints
459
+ Math.floor(
460
+ PointVector.distance(a, b) /
461
+ SCATTER_QUADTREE_SAMPLING_DISTANCE
462
+ ),
463
+ lineRange = interpolate(
464
+ { x: a.x, y: a.y },
465
+ { x: b.x, y: b.y }
466
+ ),
467
+ coords = quantize(
468
+ (pct: number) => _.clone(lineRange(pct)),
469
+ numPoints
470
+ )
471
+
472
+ return coords.map((point) => ({
473
+ series,
474
+ x: point.x,
475
+ y: point.y,
476
+ }))
477
+ })
478
+ }
479
+ )
480
+
481
+ return quadtree<ScatterPointQuadtreeNode>()
482
+ .x(({ x }) => x)
483
+ .y(({ y }) => y)
484
+ .addAll(nodes)
485
+ }
486
+
487
+ @computed private get points(): React.ReactElement {
488
+ return (
489
+ <ScatterPointsWithLabels
490
+ noDataModalManager={this.manager}
491
+ isConnected={this.chartState.isConnected}
492
+ hideConnectedScatterLines={this.hideConnectedScatterLines}
493
+ seriesArray={this.series}
494
+ dualAxis={this.dualAxis}
495
+ colorScale={
496
+ !this.colorColumn.isMissing ? this.colorScale : undefined
497
+ }
498
+ sizeScale={this.sizeScale}
499
+ fontScale={this.fontScale}
500
+ baseFontSize={this.fontSize}
501
+ focusedSeriesNames={this.selectedEntityNames}
502
+ hoveredSeriesNames={this.hoveredSeriesNames}
503
+ isHoverModeActive={this.isHoverModeActive}
504
+ tooltipSeriesName={this.tooltipSeries?.seriesName}
505
+ disableIntroAnimation={this.manager.disableIntroAnimation}
506
+ hideScatterLabels={this.hideScatterLabels}
507
+ onMouseEnter={this.onScatterMouseEnter}
508
+ onMouseLeave={this.onScatterMouseLeave}
509
+ onClick={this.onScatterClick}
510
+ quadtree={this.quadtree}
511
+ backgroundColor={this.manager.backgroundColor}
512
+ />
513
+ )
514
+ }
515
+
516
+ @computed private get colorColumnSlug(): string | undefined {
517
+ return this.chartState.colorColumnSlug
518
+ }
519
+
520
+ @computed private get colorColumn(): CoreColumn {
521
+ return this.chartState.colorColumn
522
+ }
523
+
524
+ @computed get categoricalLegendData(): ColorScaleBin[] {
525
+ return this.colorScale.legendBins.filter(
526
+ (bin) =>
527
+ this.colorsInUse.includes(bin.color) &&
528
+ bin.label !== NO_DATA_LABEL
529
+ )
530
+ }
531
+
532
+ @computed get legendTitle(): string | undefined {
533
+ return this.colorScale.legendDescription
534
+ }
535
+
536
+ @computed get sizeScale(): ScaleLinear<number, number> {
537
+ return scaleSqrt()
538
+ .domain(this.chartState.sizeDomain)
539
+ .range(this.sizeRange)
540
+ }
541
+
542
+ @computed private get fontScale(): ScaleLinear<number, number> {
543
+ const defaultFontSize =
544
+ SCATTER_LABEL_DEFAULT_FONT_SIZE_FACTOR * this.fontSize
545
+ const minFactor = this.manager.isNarrow
546
+ ? SCATTER_LABEL_DEFAULT_FONT_SIZE_FACTOR
547
+ : SCATTER_LABEL_MIN_FONT_SIZE_FACTOR
548
+ const maxFactor = this.manager.isNarrow
549
+ ? SCATTER_LABEL_DEFAULT_FONT_SIZE_FACTOR
550
+ : SCATTER_LABEL_MAX_FONT_SIZE_FACTOR
551
+ const minFontSize = minFactor * this.fontSize
552
+ const maxFontSize = maxFactor * this.fontSize
553
+ return scaleSqrt()
554
+ .domain(this.chartState.sizeDomain)
555
+ .range(
556
+ this.sizeColumn.isMissing
557
+ ? // if the size column is missing, we want all labels to have the same font size
558
+ [defaultFontSize, defaultFontSize]
559
+ : [minFontSize, maxFontSize]
560
+ )
561
+ }
562
+
563
+ @computed private get sizeLegend(): ScatterSizeLegend | undefined {
564
+ if (this.chartState.isConnected || this.sizeColumn.isMissing)
565
+ return undefined
566
+ return new ScatterSizeLegend(this)
567
+ }
568
+
569
+ @computed
570
+ private get selectedEntitiesWithoutData(): string[] {
571
+ const entitiesWithoutData = _.uniq(
572
+ _.difference(
573
+ this.selectedEntityNames,
574
+ this.series.map((s) => s.seriesName)
575
+ )
576
+ )
577
+
578
+ return entitiesWithoutData.map((entityName) => {
579
+ const shortName = getShortNameForEntity(entityName)
580
+ return shortName ?? entityName
581
+ })
582
+ }
583
+
584
+ @computed private get hasNoDataSection(): boolean {
585
+ return this.selectedEntitiesWithoutData.length > 0
586
+ }
587
+
588
+ override componentDidMount(): void {
589
+ exposeInstanceOnWindow(this)
590
+ }
591
+
592
+ renderSidebar(): React.ReactElement | null {
593
+ const {
594
+ bounds,
595
+ sizeLegend,
596
+ arrowLegend,
597
+ verticalColorLegend,
598
+ sidebarWidth,
599
+ } = this
600
+
601
+ const verticalLegendHeight = verticalColorLegend?.height ?? 0
602
+ const sizeLegendHeight = sizeLegend?.height ?? 0
603
+ const arrowLegendHeight = arrowLegend?.height ?? 0
604
+
605
+ const legendPadding = 16
606
+ const ySizeLegend =
607
+ this.legendY +
608
+ verticalLegendHeight +
609
+ (verticalLegendHeight > 0 ? legendPadding : 0)
610
+ const yArrowLegend =
611
+ ySizeLegend +
612
+ sizeLegendHeight +
613
+ (sizeLegendHeight > 0 ? legendPadding : 0)
614
+ const yNoDataSection =
615
+ yArrowLegend +
616
+ arrowLegendHeight +
617
+ (arrowLegendHeight > 0 ? legendPadding : 0)
618
+
619
+ const noDataSectionBounds = new Bounds(
620
+ this.legendX,
621
+ yNoDataSection,
622
+ sidebarWidth,
623
+ bounds.height - yNoDataSection
624
+ )
625
+
626
+ const separatorLine = (y: number): React.ReactElement | null =>
627
+ y > bounds.top ? (
628
+ <line
629
+ id={makeIdForHumanConsumption("separator")}
630
+ x1={this.legendX}
631
+ y1={y - 0.5 * legendPadding}
632
+ x2={bounds.right}
633
+ y2={y - 0.5 * legendPadding}
634
+ stroke="#e7e7e7"
635
+ />
636
+ ) : null
637
+
638
+ return (
639
+ <>
640
+ {verticalColorLegend && <VerticalColorLegend manager={this} />}
641
+ {sizeLegend && (
642
+ <>
643
+ {verticalColorLegend && separatorLine(ySizeLegend)}
644
+ {sizeLegend.render(this.legendX, ySizeLegend)}
645
+ </>
646
+ )}
647
+ {arrowLegend && (
648
+ <>
649
+ {(verticalColorLegend || sizeLegend) &&
650
+ separatorLine(yArrowLegend)}
651
+ <g
652
+ className="clickable"
653
+ onClick={this.onToggleEndpoints}
654
+ >
655
+ {arrowLegend.render(this.legendX, yArrowLegend)}
656
+ </g>
657
+ </>
658
+ )}
659
+ {this.hasNoDataSection && (
660
+ <>
661
+ {!this.manager.isStatic &&
662
+ (verticalColorLegend ||
663
+ sizeLegend ||
664
+ arrowLegend) &&
665
+ separatorLine(noDataSectionBounds.top)}
666
+ <NoDataSection
667
+ seriesNames={this.selectedEntitiesWithoutData}
668
+ bounds={noDataSectionBounds}
669
+ baseFontSize={this.fontSize}
670
+ />
671
+ </>
672
+ )}
673
+ </>
674
+ )
675
+ }
676
+
677
+ renderStatic(): React.ReactElement {
678
+ return (
679
+ <>
680
+ <DualAxisComponent
681
+ dualAxis={this.dualAxis}
682
+ showTickMarks={false}
683
+ detailsMarker={this.manager.detailsMarkerInSvg}
684
+ backgroundColor={this.manager.backgroundColor}
685
+ />
686
+ {this.points}
687
+ {this.renderSidebar()}
688
+ </>
689
+ )
690
+ }
691
+
692
+ renderInteractive(): React.ReactElement {
693
+ return (
694
+ <g className="ScatterPlot" onMouseMove={this.onScatterMouseMove}>
695
+ <DualAxisComponent
696
+ dualAxis={this.dualAxis}
697
+ showTickMarks={false}
698
+ detailsMarker={this.manager.detailsMarkerInSvg}
699
+ />
700
+ {this.points}
701
+ {this.renderSidebar()}
702
+ {this.tooltip}
703
+ </g>
704
+ )
705
+ }
706
+
707
+ override render(): React.ReactElement {
708
+ if (this.chartState.errorInfo.reason)
709
+ return (
710
+ <NoDataModal
711
+ manager={this.manager}
712
+ bounds={this.bounds}
713
+ message={this.chartState.errorInfo.reason}
714
+ />
715
+ )
716
+
717
+ return this.manager.isStatic
718
+ ? this.renderStatic()
719
+ : this.renderInteractive()
720
+ }
721
+
722
+ @computed private get tooltip(): React.ReactElement | null {
723
+ return (
724
+ <ScatterPlotTooltip
725
+ chartState={this.chartState}
726
+ tooltipState={this.tooltipState}
727
+ />
728
+ )
729
+ }
730
+
731
+ @computed get legendY(): number {
732
+ return this.bounds.top + this.yAxis.labelHeight
733
+ }
734
+
735
+ @computed get legendX(): number {
736
+ return this.bounds.right - this.sidebarWidth
737
+ }
738
+
739
+ @computed private get yAxisConfig(): AxisConfig {
740
+ const { yAxisConfig = {} } = this.manager
741
+ const config = {
742
+ ...yAxisConfig,
743
+ labelPadding: this.manager.isNarrow ? 10 : 14,
744
+ }
745
+ return new AxisConfig(config, this)
746
+ }
747
+
748
+ @computed private get xAxisConfig(): AxisConfig {
749
+ const { xAxisConfig = {} } = this.manager
750
+ const config = {
751
+ ...xAxisConfig,
752
+ labelPadding: this.manager.isNarrow ? 6 : undefined,
753
+ }
754
+ return new AxisConfig(config, this)
755
+ }
756
+
757
+ @computed private get yColumn(): CoreColumn {
758
+ return this.chartState.yColumn
759
+ }
760
+
761
+ @computed private get xColumn(): CoreColumn {
762
+ return this.chartState.xColumn
763
+ }
764
+
765
+ @computed get sizeColumn(): CoreColumn {
766
+ return this.chartState.sizeColumn
767
+ }
768
+
769
+ @computed get compareEndPointsOnly(): boolean {
770
+ return this.chartState.compareEndPointsOnly
771
+ }
772
+
773
+ @computed get allPoints(): SeriesPoint[] {
774
+ return this.chartState.allPoints
775
+ }
776
+
777
+ @computed private get sizeRange(): [number, number] {
778
+ return toSizeRange(this.chartState, this.innerBounds)
779
+ }
780
+
781
+ @computed private get verticalAxisPart(): VerticalAxis {
782
+ return this.chartState.toVerticalAxis(this.yAxisConfig)
783
+ }
784
+
785
+ @computed private get horizontalAxisPart(): HorizontalAxis {
786
+ return this.chartState.toHorizontalAxis(this.xAxisConfig)
787
+ }
788
+
789
+ @computed private get series(): ScatterSeries[] {
790
+ return this.chartState.series
791
+ }
792
+ }