@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,155 @@
1
+ import * as _ from "lodash-es"
2
+ import React from "react"
3
+ import { computed, makeObservable } from "mobx"
4
+ import { observer } from "mobx-react"
5
+ import { ChartInterface } from "../chart/ChartInterface"
6
+ import { ScatterPlotChartState } from "./ScatterPlotChartState"
7
+ import { type ScatterPlotChartProps } from "./ScatterPlotChart.js"
8
+ import { ScaleLinear, scaleSqrt } from "d3-scale"
9
+ import { DualAxis, HorizontalAxis, VerticalAxis } from "../axis/Axis"
10
+ import { Bounds } from "../../utils/index.js"
11
+ import {
12
+ BASE_FONT_SIZE,
13
+ DEFAULT_GRAPHER_BOUNDS,
14
+ } from "../core/GrapherConstants"
15
+ import { AxisConfig, AxisManager } from "../axis/AxisConfig"
16
+ import {
17
+ SCATTER_LINE_MIN_WIDTH,
18
+ SCATTER_POINT_MIN_RADIUS,
19
+ ScatterPlotManager,
20
+ } from "./ScatterPlotChartConstants"
21
+ import { toSizeRange } from "./ScatterUtils"
22
+ import { DualAxisComponent } from "../axis/AxisViews"
23
+ import { ScatterPointsWithLabels } from "./ScatterPointsWithLabels"
24
+ import { NoDataModal } from "../noDataModal/NoDataModal"
25
+
26
+ @observer
27
+ export class ScatterPlotChartThumbnail
28
+ extends React.Component<ScatterPlotChartProps>
29
+ implements ChartInterface, AxisManager
30
+ {
31
+ constructor(props: ScatterPlotChartProps) {
32
+ super(props)
33
+ makeObservable(this)
34
+ }
35
+
36
+ @computed get chartState(): ScatterPlotChartState {
37
+ return this.props.chartState
38
+ }
39
+
40
+ @computed get manager(): ScatterPlotManager {
41
+ return this.chartState.manager
42
+ }
43
+
44
+ @computed get fontSize(): number {
45
+ return this.manager.fontSize ?? BASE_FONT_SIZE
46
+ }
47
+
48
+ @computed private get bounds(): Bounds {
49
+ return this.props.bounds ?? DEFAULT_GRAPHER_BOUNDS
50
+ }
51
+
52
+ @computed private get innerBounds(): Bounds {
53
+ return this.bounds
54
+ }
55
+
56
+ @computed get axisBounds(): Bounds {
57
+ return this.innerBounds
58
+ }
59
+
60
+ @computed private get xAxisConfig(): AxisConfig {
61
+ const { xAxisConfig } = this.manager
62
+ const custom = { labelPadding: 2 }
63
+ return new AxisConfig({ ...custom, ...xAxisConfig }, this)
64
+ }
65
+
66
+ @computed private get yAxisConfig(): AxisConfig {
67
+ const { yAxisConfig } = this.manager
68
+ const custom = { labelPadding: 8 }
69
+ return new AxisConfig({ ...custom, ...yAxisConfig }, this)
70
+ }
71
+
72
+ @computed private get verticalAxisPart(): VerticalAxis {
73
+ return this.chartState.toVerticalAxis(this.yAxisConfig)
74
+ }
75
+
76
+ @computed private get horizontalAxisPart(): HorizontalAxis {
77
+ return this.chartState.toHorizontalAxis(this.xAxisConfig)
78
+ }
79
+
80
+ @computed private get dualAxis(): DualAxis {
81
+ return new DualAxis({
82
+ bounds: this.innerBounds,
83
+ horizontalAxis: this.horizontalAxisPart,
84
+ verticalAxis: this.verticalAxisPart,
85
+ })
86
+ }
87
+
88
+ @computed private get sizeRange(): [number, number] {
89
+ return toSizeRange(this.chartState, this.innerBounds)
90
+ }
91
+
92
+ @computed get sizeScale(): ScaleLinear<number, number> {
93
+ return scaleSqrt()
94
+ .domain(this.chartState.sizeDomain)
95
+ .range(this.sizeRange)
96
+ }
97
+
98
+ private getPointRadius(value: number | undefined): number {
99
+ const radius =
100
+ value !== undefined
101
+ ? this.sizeScale(value)
102
+ : this.sizeScale.range()[0]
103
+
104
+ // We are enforcing the minimum radius/width just before render,
105
+ // it should not be enforced earlier than that.
106
+ return Math.max(
107
+ radius,
108
+ this.props.chartState.isConnected
109
+ ? SCATTER_LINE_MIN_WIDTH
110
+ : SCATTER_POINT_MIN_RADIUS
111
+ )
112
+ }
113
+
114
+ override render(): React.ReactElement {
115
+ if (this.chartState.errorInfo.reason)
116
+ return (
117
+ <NoDataModal
118
+ manager={this.manager}
119
+ bounds={this.props.bounds}
120
+ message={this.chartState.errorInfo.reason}
121
+ />
122
+ )
123
+
124
+ return (
125
+ <>
126
+ <DualAxisComponent
127
+ dualAxis={this.dualAxis}
128
+ showTickMarks={false}
129
+ showEndpointsOnly={true}
130
+ />
131
+ <ScatterPointsWithLabels
132
+ noDataModalManager={this.manager}
133
+ isConnected={this.chartState.isConnected}
134
+ hideConnectedScatterLines={
135
+ !!this.manager.hideConnectedScatterLines
136
+ }
137
+ seriesArray={this.chartState.series}
138
+ dualAxis={this.dualAxis}
139
+ colorScale={
140
+ !this.chartState.colorColumn.isMissing
141
+ ? this.chartState.colorScale
142
+ : undefined
143
+ }
144
+ sizeScale={this.sizeScale}
145
+ baseFontSize={this.fontSize}
146
+ focusedSeriesNames={
147
+ this.chartState.selectionArray.selectedEntityNames
148
+ }
149
+ hideScatterLabels={true}
150
+ backgroundColor={this.manager.backgroundColor}
151
+ />
152
+ </>
153
+ )
154
+ }
155
+ }
@@ -0,0 +1,560 @@
1
+ import * as _ from "lodash-es"
2
+ import * as R from "remeda"
3
+ import React from "react"
4
+ import { observer } from "mobx-react"
5
+ import { computed } from "mobx"
6
+ import {
7
+ excludeNullish,
8
+ excludeUndefined,
9
+ calculateTrendDirection,
10
+ Time,
11
+ RequiredBy,
12
+ } from "../../utils/index.js"
13
+ import { CoreColumn } from "../../core-table/index.js"
14
+ import {
15
+ Tooltip,
16
+ TooltipState,
17
+ TooltipValueRange,
18
+ makeTooltipToleranceNotice,
19
+ makeTooltipRoundingNotice,
20
+ formatTooltipRangeValues,
21
+ TooltipValue,
22
+ } from "../tooltip/Tooltip"
23
+ import { FooterItem, TooltipFooterIcon } from "../tooltip/TooltipProps.js"
24
+ import { ScatterSeries, SeriesPoint } from "./ScatterPlotChartConstants"
25
+ import { ScatterPlotChartState } from "./ScatterPlotChartState"
26
+
27
+ export interface ScatterPlotTooltipProps {
28
+ chartState: ScatterPlotChartState
29
+ tooltipState: TooltipState<{ series: ScatterSeries }>
30
+ }
31
+
32
+ interface TooltipValueRangeProps {
33
+ chartState: ScatterPlotChartState
34
+ points?: SeriesPoint[]
35
+ values: SeriesPoint[]
36
+ showSignificanceSuperscript?: boolean
37
+ showOriginalTimes?: boolean
38
+ }
39
+
40
+ @observer
41
+ export class ScatterPlotTooltip extends React.Component<ScatterPlotTooltipProps> {
42
+ @computed private get chartState(): ScatterPlotChartState {
43
+ return this.props.chartState
44
+ }
45
+
46
+ @computed private get points(): SeriesPoint[] {
47
+ return this.props.tooltipState.target?.series.points ?? []
48
+ }
49
+
50
+ @computed private get values(): SeriesPoint[] {
51
+ return excludeNullish(
52
+ _.uniq([R.first(this.points), R.last(this.points)])
53
+ )
54
+ }
55
+
56
+ @computed private get toleranceNotice(): FooterItem | undefined {
57
+ const { points, values } = this
58
+ const { xColumn, yColumn, manager, isTimeScatter } = this.chartState
59
+ const { startTime, endTime } = manager
60
+
61
+ // No tolerance notice needed if comparing the same variable across years
62
+ if (hasSameVariableWithTimeOverride(xColumn, yColumn, points)) {
63
+ return undefined
64
+ }
65
+
66
+ // No tolerance notice needed for time scatter plots
67
+ if (isTimeScatter) return undefined
68
+
69
+ // Check the time span in relative mode
70
+ if (manager.isRelativeMode) {
71
+ const [start, end] = points[0].time.span ?? []
72
+ const noticeNeeded = hasTimeMismatch({
73
+ actualStartTime: start,
74
+ actualEndTime: end,
75
+ targetStartTime: startTime,
76
+ targetEndTime: endTime,
77
+ })
78
+
79
+ if (!noticeNeeded) return undefined
80
+
81
+ return makeToleranceNotice({
82
+ startTime,
83
+ endTime,
84
+ formatTime: (time) => yColumn.formatTime(time),
85
+ })
86
+ }
87
+
88
+ const { x: xStart, y: yStart } = R.first(values)?.time ?? {}
89
+ const { x: xEnd, y: yEnd } = R.last(values)?.time ?? {}
90
+
91
+ const xNoticeNeeded = hasTimeMismatch({
92
+ actualStartTime: xStart,
93
+ actualEndTime: xEnd,
94
+ targetStartTime: startTime,
95
+ targetEndTime: endTime,
96
+ })
97
+ const yNoticeNeeded = hasTimeMismatch({
98
+ actualStartTime: yStart,
99
+ actualEndTime: yEnd,
100
+ targetStartTime: startTime,
101
+ targetEndTime: endTime,
102
+ })
103
+
104
+ if (!xNoticeNeeded && !yNoticeNeeded) return undefined
105
+
106
+ return makeToleranceNotice({
107
+ startTime,
108
+ endTime,
109
+ formatTime: (time) => yColumn.formatTime(time),
110
+ })
111
+ }
112
+
113
+ @computed private get roundingNotice(): FooterItem | undefined {
114
+ const { xColumn, yColumn, sizeColumn } = this.props.chartState
115
+
116
+ const columns = [xColumn, yColumn, sizeColumn].filter(
117
+ (column) => !column.isMissing && !column.isTimeColumn
118
+ )
119
+
120
+ const allRoundedToSigFigs = columns.every(
121
+ (column) => column.roundsToSignificantFigures
122
+ )
123
+ const anyRoundedToSigFigs = columns.some(
124
+ (column) => column.roundsToSignificantFigures
125
+ )
126
+
127
+ if (!anyRoundedToSigFigs) return undefined
128
+
129
+ const sigFigs = excludeUndefined(
130
+ columns.map((column) =>
131
+ column.roundsToSignificantFigures
132
+ ? column.numSignificantFigures
133
+ : undefined
134
+ )
135
+ )
136
+
137
+ return {
138
+ icon: allRoundedToSigFigs
139
+ ? TooltipFooterIcon.None
140
+ : TooltipFooterIcon.Significance,
141
+ text: makeTooltipRoundingNotice(sigFigs, {
142
+ plural: sigFigs.length > 1,
143
+ }),
144
+ }
145
+ }
146
+
147
+ @computed private get showSignificanceSuperscript(): boolean {
148
+ return this.roundingNotice?.icon === TooltipFooterIcon.Significance
149
+ }
150
+
151
+ @computed private get footer(): FooterItem[] {
152
+ return excludeUndefined([this.toleranceNotice, this.roundingNotice])
153
+ }
154
+
155
+ @computed private get subtitle(): string {
156
+ const { manager, yColumn, xColumn } = this.chartState
157
+ const { startTime, endTime, isRelativeMode } = manager
158
+
159
+ let times: Time[]
160
+ if (hasSameVariableWithTimeOverride(xColumn, yColumn, this.points)) {
161
+ times = _.sortBy([this.points[0].time.x, this.points[0].time.y])
162
+ } else if (this.chartState.isTimeScatter) {
163
+ times = _.uniq(excludeNullish(this.values.map((v) => v.time.y)))
164
+ } else {
165
+ times = _.uniq(excludeNullish([startTime, endTime]))
166
+ }
167
+
168
+ const timeRange = times.map((t) => yColumn.formatTime(t)).join(" to ")
169
+
170
+ return timeRange + (isRelativeMode ? " (avg. annual change)" : "")
171
+ }
172
+
173
+ override render(): React.ReactElement | null {
174
+ const { showSignificanceSuperscript } = this
175
+ const { chartState, tooltipState } = this.props
176
+
177
+ const { target, position, fading } = tooltipState
178
+ if (!target) return null
179
+
180
+ const hasToleranceNotice = this.toleranceNotice !== undefined
181
+
182
+ return (
183
+ <Tooltip
184
+ id="scatterTooltip"
185
+ tooltipManager={chartState.manager}
186
+ x={position.x}
187
+ y={position.y}
188
+ offsetX={20}
189
+ offsetY={-16}
190
+ style={{ maxWidth: "250px" }}
191
+ title={target.series.label}
192
+ subtitle={this.subtitle}
193
+ dissolve={fading}
194
+ footer={this.footer}
195
+ dismiss={() => (tooltipState.target = null)}
196
+ >
197
+ <TooltipValueRangeX
198
+ chartState={chartState}
199
+ points={this.points}
200
+ values={this.values}
201
+ showSignificanceSuperscript={showSignificanceSuperscript}
202
+ showOriginalTimes={hasToleranceNotice}
203
+ />
204
+ <TooltipValueRangeY
205
+ chartState={chartState}
206
+ points={this.points}
207
+ values={this.values}
208
+ showSignificanceSuperscript={showSignificanceSuperscript}
209
+ showOriginalTimes={hasToleranceNotice}
210
+ />
211
+ <TooltipValueRangeSize
212
+ chartState={chartState}
213
+ values={this.values}
214
+ showSignificanceSuperscript={showSignificanceSuperscript}
215
+ />
216
+ <TooltipValueColor
217
+ chartState={chartState}
218
+ values={this.values}
219
+ />
220
+ </Tooltip>
221
+ )
222
+ }
223
+ }
224
+
225
+ function TooltipValueRangeX({
226
+ chartState,
227
+ points,
228
+ values,
229
+ showSignificanceSuperscript,
230
+ showOriginalTimes,
231
+ }: RequiredBy<TooltipValueRangeProps, "points">): React.ReactElement | null {
232
+ const { xColumn } = chartState
233
+
234
+ if (xColumn.isMissing || xColumn.isTimeColumn) return null
235
+
236
+ const { values: xValues, originalTimes = [] } = getXValuesWithTimes(
237
+ chartState,
238
+ points,
239
+ values
240
+ )
241
+
242
+ const formattedOriginalTimes = showOriginalTimes
243
+ ? originalTimes.map((time) => formatTime(time, xColumn))
244
+ : []
245
+
246
+ return (
247
+ <TooltipValueRange
248
+ label={xColumn.displayName}
249
+ unit={xColumn.displayUnit}
250
+ values={formatTooltipRangeValues(xValues, xColumn)}
251
+ trend={calculateTrendDirection(...xValues)}
252
+ originalTimes={formattedOriginalTimes}
253
+ isRoundedToSignificantFigures={xColumn.roundsToSignificantFigures}
254
+ showSignificanceSuperscript={showSignificanceSuperscript}
255
+ />
256
+ )
257
+ }
258
+
259
+ function TooltipValueRangeY({
260
+ chartState,
261
+ points,
262
+ values,
263
+ showSignificanceSuperscript,
264
+ showOriginalTimes,
265
+ }: RequiredBy<TooltipValueRangeProps, "points">): React.ReactElement | null {
266
+ const { yColumn } = chartState
267
+
268
+ if (yColumn.isMissing) return null
269
+
270
+ const { values: yValues, originalTimes = [] } = getYValuesWithTimes(
271
+ chartState,
272
+ points,
273
+ values
274
+ )
275
+
276
+ const formattedOriginalTimes = showOriginalTimes
277
+ ? originalTimes.map((time) => formatTime(time, yColumn))
278
+ : []
279
+
280
+ return (
281
+ <TooltipValueRange
282
+ label={yColumn.displayName}
283
+ unit={yColumn.displayUnit}
284
+ values={formatTooltipRangeValues(yValues, yColumn)}
285
+ trend={calculateTrendDirection(...yValues)}
286
+ originalTimes={formattedOriginalTimes}
287
+ isRoundedToSignificantFigures={yColumn.roundsToSignificantFigures}
288
+ showSignificanceSuperscript={showSignificanceSuperscript}
289
+ />
290
+ )
291
+ }
292
+
293
+ function TooltipValueRangeSize({
294
+ chartState,
295
+ values,
296
+ showSignificanceSuperscript,
297
+ }: TooltipValueRangeProps): React.ReactElement | null {
298
+ const { sizeColumn } = chartState
299
+
300
+ if (sizeColumn.isMissing) return null
301
+
302
+ const sizeValues = excludeNullish(values.map((v) => v.size))
303
+
304
+ return (
305
+ <TooltipValueRange
306
+ label={sizeColumn.displayName}
307
+ unit={sizeColumn.displayUnit}
308
+ values={formatTooltipRangeValues(sizeValues, sizeColumn)}
309
+ trend={calculateTrendDirection(...sizeValues)}
310
+ isRoundedToSignificantFigures={
311
+ sizeColumn.roundsToSignificantFigures
312
+ }
313
+ showSignificanceSuperscript={showSignificanceSuperscript}
314
+ />
315
+ )
316
+ }
317
+
318
+ function TooltipValueColor({
319
+ chartState,
320
+ values,
321
+ }: TooltipValueRangeProps): React.ReactElement | null {
322
+ const { colorColumn, colorScale } = chartState
323
+
324
+ if (colorColumn.isMissing) return null
325
+
326
+ const value = values.at(-1)
327
+ const colorValue = value?.color
328
+ if (!colorValue) return null
329
+
330
+ // Get the legend label for this color value
331
+ const bin = colorScale.getBinForValue(colorValue)
332
+ const displayValue = bin?.label ?? colorValue.toString()
333
+
334
+ return (
335
+ <TooltipValue
336
+ label={colorScale.legendDescription ?? colorColumn.displayName}
337
+ value={displayValue}
338
+ />
339
+ )
340
+ }
341
+
342
+ /**
343
+ * Detects when a scatter plot compares the same variable across two different years.
344
+ *
345
+ * Example: GDP in 2020 (y-axis) vs GDP in 2010 (x-axis).
346
+ */
347
+ function hasSameVariableWithTimeOverride(
348
+ xColumn: CoreColumn,
349
+ yColumn: CoreColumn,
350
+ points: SeriesPoint[]
351
+ ): boolean {
352
+ // Check if there is exactly one point
353
+ if (points.length !== 1) return false
354
+
355
+ // Check if both axes use the same dataset/variable
356
+ const isSameDataset = xColumn.def.datasetId === yColumn.def.datasetId
357
+ if (!isSameDataset) return false
358
+
359
+ // Check if the point has different time points for x and y
360
+ const point = points[0]
361
+ const hasDifferentTimes =
362
+ point.time.x !== point.time.y &&
363
+ _.isNumber(point.time.x) &&
364
+ _.isNumber(point.time.y)
365
+
366
+ return hasDifferentTimes
367
+ }
368
+
369
+ function hasTimeMismatch({
370
+ actualStartTime,
371
+ actualEndTime,
372
+ targetStartTime,
373
+ targetEndTime,
374
+ }: {
375
+ actualStartTime?: Time
376
+ actualEndTime?: Time
377
+ targetStartTime?: Time
378
+ targetEndTime?: Time
379
+ }): boolean {
380
+ const startTimesDiffer =
381
+ actualStartTime !== undefined && actualStartTime !== targetStartTime
382
+ const endTimesDiffer =
383
+ actualEndTime !== undefined && actualEndTime !== targetEndTime
384
+
385
+ return startTimesDiffer || endTimesDiffer
386
+ }
387
+
388
+ function makeToleranceNotice({
389
+ startTime,
390
+ endTime,
391
+ formatTime,
392
+ }: {
393
+ startTime?: Time
394
+ endTime?: Time
395
+ formatTime: (time: Time) => string
396
+ }): FooterItem {
397
+ const targetNotice = _.uniq(excludeNullish([startTime, endTime]))
398
+ .map((t) => formatTime(t))
399
+ .join(" to ")
400
+
401
+ return {
402
+ icon: TooltipFooterIcon.Notice,
403
+ text: makeTooltipToleranceNotice(targetNotice),
404
+ }
405
+ }
406
+
407
+ function getXValuesWithTimes(
408
+ chartState: ScatterPlotChartState,
409
+ points: SeriesPoint[],
410
+ values: SeriesPoint[]
411
+ ): {
412
+ values: number[]
413
+ originalTimes: (number | undefined)[]
414
+ } {
415
+ const { xColumn, yColumn, manager } = chartState
416
+ const { startTime, endTime, isRelativeMode } = manager
417
+
418
+ const firstValue = R.first(values)
419
+ const lastValue = R.last(values)
420
+
421
+ if (!firstValue || !lastValue) return { values: [], originalTimes: [] }
422
+
423
+ // Handle the special case where the same variable is used for both axes
424
+ // with a different year's value on each
425
+ if (hasSameVariableWithTimeOverride(xColumn, yColumn, points)) {
426
+ const point = points[0]
427
+ const values =
428
+ point.time.x < point.time.y
429
+ ? [point.x, point.y]
430
+ : [point.y, point.x]
431
+ return { values, originalTimes: [] }
432
+ }
433
+
434
+ const xStart = firstValue.time.x
435
+ const xEnd = lastValue.time.x
436
+
437
+ const xValues = xStart === xEnd ? [firstValue.x] : values.map((v) => v.x)
438
+
439
+ if (isRelativeMode) {
440
+ const originalTimes = getOriginalTimesForRelativeMode({
441
+ span: firstValue.time.span,
442
+ startTime,
443
+ endTime,
444
+ })
445
+
446
+ return { values: xValues, originalTimes }
447
+ }
448
+
449
+ // Check if tolerance notice is needed
450
+ const noticeNeeded = hasTimeMismatch({
451
+ actualStartTime: xStart,
452
+ actualEndTime: xEnd,
453
+ targetStartTime: startTime,
454
+ targetEndTime: endTime,
455
+ })
456
+
457
+ const originalTimes = noticeNeeded
458
+ ? xStart === xEnd
459
+ ? [xEnd]
460
+ : [xStart, xEnd]
461
+ : []
462
+
463
+ return { values: xValues, originalTimes }
464
+ }
465
+
466
+ function getYValuesWithTimes(
467
+ chartState: ScatterPlotChartState,
468
+ points: SeriesPoint[],
469
+ values: SeriesPoint[]
470
+ ): {
471
+ values: number[]
472
+ originalTimes: (number | undefined)[]
473
+ } {
474
+ const { xColumn, yColumn, manager } = chartState
475
+ const { startTime, endTime, isRelativeMode } = manager
476
+
477
+ // Handle the special case where the x-axis is time
478
+ if (chartState.isTimeScatter) {
479
+ return { values: values.map((v) => v.y), originalTimes: [] }
480
+ }
481
+
482
+ // Handle the special case where the same variable is used for both axes
483
+ // with a different year's value on each
484
+ if (hasSameVariableWithTimeOverride(xColumn, yColumn, points)) {
485
+ // Don't return anything (values shown on X axis)
486
+ return { values: [], originalTimes: [] }
487
+ }
488
+
489
+ const firstValue = R.first(values)
490
+ const lastValue = R.last(values)
491
+
492
+ if (!firstValue || !lastValue) {
493
+ return { values: [], originalTimes: [] }
494
+ }
495
+
496
+ const yStart = firstValue.time.y
497
+ const yEnd = lastValue.time.y
498
+
499
+ const yValues = yStart === yEnd ? [firstValue.y] : values.map((v) => v.y)
500
+
501
+ if (isRelativeMode) {
502
+ const originalTimes = getOriginalTimesForRelativeMode({
503
+ span: firstValue.time.span,
504
+ startTime,
505
+ endTime,
506
+ })
507
+
508
+ return { values: yValues, originalTimes }
509
+ }
510
+
511
+ // Check if tolerance notice is needed
512
+ const noticeNeeded = hasTimeMismatch({
513
+ actualStartTime: yStart,
514
+ actualEndTime: yEnd,
515
+ targetStartTime: startTime,
516
+ targetEndTime: endTime,
517
+ })
518
+
519
+ const originalTimes = noticeNeeded
520
+ ? yStart === yEnd
521
+ ? [yEnd]
522
+ : [yStart, yEnd]
523
+ : []
524
+
525
+ return { values: yValues, originalTimes }
526
+ }
527
+
528
+ function getOriginalTimesForRelativeMode({
529
+ startTime,
530
+ endTime,
531
+ span,
532
+ }: {
533
+ span?: [number, number]
534
+ startTime?: Time
535
+ endTime?: Time
536
+ }): (number | undefined)[] {
537
+ if (!span) return []
538
+
539
+ const [spanStart, spanEnd] = span
540
+ const noticeNeeded = hasTimeMismatch({
541
+ actualStartTime: spanStart,
542
+ actualEndTime: spanEnd,
543
+ targetStartTime: startTime,
544
+ targetEndTime: endTime,
545
+ })
546
+
547
+ return noticeNeeded
548
+ ? spanStart === spanEnd
549
+ ? [spanEnd]
550
+ : [spanStart, spanEnd]
551
+ : []
552
+ }
553
+
554
+ function formatTime(
555
+ time: Time | undefined,
556
+ column: CoreColumn
557
+ ): string | undefined {
558
+ if (time === undefined) return undefined
559
+ return column.formatTime(time)
560
+ }