@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.
- package/LICENSE.md +8 -0
- package/README.md +113 -0
- package/package.json +137 -0
- package/src/components/BodyPortal/BodyPortal.tsx +40 -0
- package/src/components/Button/Button.scss +110 -0
- package/src/components/Button/Button.tsx +101 -0
- package/src/components/Checkbox.scss +93 -0
- package/src/components/Checkbox.tsx +47 -0
- package/src/components/ExpandableToggle/ExpandableToggle.scss +123 -0
- package/src/components/ExpandableToggle/ExpandableToggle.tsx +60 -0
- package/src/components/GrapherTabIcon.tsx +156 -0
- package/src/components/GrapherTrendArrow.scss +16 -0
- package/src/components/GrapherTrendArrow.tsx +30 -0
- package/src/components/Halo/Halo.tsx +44 -0
- package/src/components/LabeledSwitch/LabeledSwitch.scss +109 -0
- package/src/components/LabeledSwitch/LabeledSwitch.tsx +62 -0
- package/src/components/MarkdownTextWrap/MarkdownTextWrap.tsx +1173 -0
- package/src/components/OverlayHeader.scss +18 -0
- package/src/components/OverlayHeader.tsx +29 -0
- package/src/components/RadioButton.scss +69 -0
- package/src/components/RadioButton.tsx +42 -0
- package/src/components/SimpleMarkdownText.tsx +89 -0
- package/src/components/TextInput.scss +17 -0
- package/src/components/TextInput.tsx +19 -0
- package/src/components/TextWrap/TextWrap.tsx +361 -0
- package/src/components/TextWrap/TextWrapUtils.ts +32 -0
- package/src/components/closeButton/CloseButton.scss +40 -0
- package/src/components/closeButton/CloseButton.tsx +27 -0
- package/src/components/index.ts +70 -0
- package/src/components/loadingIndicator/LoadingIndicator.scss +40 -0
- package/src/components/loadingIndicator/LoadingIndicator.tsx +28 -0
- package/src/components/markdown/remarkPlainLinks.ts +36 -0
- package/src/components/reactUtil.ts +20 -0
- package/src/components/stubs/CodeSnippet.tsx +19 -0
- package/src/components/stubs/DataCitation.tsx +16 -0
- package/src/components/stubs/IndicatorKeyData.tsx +45 -0
- package/src/components/stubs/IndicatorProcessing.tsx +15 -0
- package/src/components/stubs/IndicatorSources.tsx +15 -0
- package/src/components/styles/colors.scss +113 -0
- package/src/components/styles/mixins.scss +630 -0
- package/src/components/styles/typography.scss +579 -0
- package/src/components/styles/util.scss +89 -0
- package/src/components/styles/variables.scss +208 -0
- package/src/config/ChartsConfig.ts +163 -0
- package/src/config/ChartsProvider.tsx +157 -0
- package/src/config/index.ts +20 -0
- package/src/core-table/CoreTable.ts +1355 -0
- package/src/core-table/CoreTableColumns.ts +973 -0
- package/src/core-table/CoreTableUtils.ts +793 -0
- package/src/core-table/ErrorValues.ts +73 -0
- package/src/core-table/OwidTable.ts +1175 -0
- package/src/core-table/OwidTableSynthesizers.ts +272 -0
- package/src/core-table/OwidTableUtil.ts +76 -0
- package/src/core-table/Transforms.ts +484 -0
- package/src/core-table/index.ts +82 -0
- package/src/explorer/ColumnGrammar.ts +217 -0
- package/src/explorer/Explorer.sample.ts +212 -0
- package/src/explorer/Explorer.scss +148 -0
- package/src/explorer/Explorer.tsx +1283 -0
- package/src/explorer/ExplorerConstants.ts +85 -0
- package/src/explorer/ExplorerControls.scss +156 -0
- package/src/explorer/ExplorerControls.tsx +210 -0
- package/src/explorer/ExplorerDecisionMatrix.ts +471 -0
- package/src/explorer/ExplorerGrammar.ts +161 -0
- package/src/explorer/ExplorerProgram.ts +568 -0
- package/src/explorer/ExplorerUtils.ts +59 -0
- package/src/explorer/GrapherGrammar.ts +387 -0
- package/src/explorer/gridLang/GrammarUtils.ts +121 -0
- package/src/explorer/gridLang/GridCell.ts +298 -0
- package/src/explorer/gridLang/GridLangConstants.ts +255 -0
- package/src/explorer/gridLang/GridProgram.ts +311 -0
- package/src/explorer/gridLang/readme.md +17 -0
- package/src/explorer/index.ts +69 -0
- package/src/explorer/readme.md +19 -0
- package/src/explorer/urlMigrations/CO2UrlMigration.ts +46 -0
- package/src/explorer/urlMigrations/CovidUrlMigration.ts +37 -0
- package/src/explorer/urlMigrations/EnergyUrlMigration.ts +41 -0
- package/src/explorer/urlMigrations/ExplorerPageUrlMigrationSpec.ts +12 -0
- package/src/explorer/urlMigrations/ExplorerUrlMigrationUtils.ts +45 -0
- package/src/explorer/urlMigrations/ExplorerUrlMigrations.ts +33 -0
- package/src/explorer/urlMigrations/LegacyCovidUrlMigration.ts +144 -0
- package/src/explorer/urlMigrations/readme.md +39 -0
- package/src/grapher/axis/Axis.ts +973 -0
- package/src/grapher/axis/AxisConfig.ts +179 -0
- package/src/grapher/axis/AxisViews.tsx +597 -0
- package/src/grapher/barCharts/DiscreteBarChart.tsx +728 -0
- package/src/grapher/barCharts/DiscreteBarChartConstants.ts +60 -0
- package/src/grapher/barCharts/DiscreteBarChartHelpers.ts +338 -0
- package/src/grapher/barCharts/DiscreteBarChartState.ts +354 -0
- package/src/grapher/barCharts/DiscreteBarChartThumbnail.tsx +34 -0
- package/src/grapher/captionedChart/CaptionedChart.scss +61 -0
- package/src/grapher/captionedChart/CaptionedChart.tsx +523 -0
- package/src/grapher/captionedChart/Logos.tsx +141 -0
- package/src/grapher/captionedChart/LogosSVG.tsx +16 -0
- package/src/grapher/captionedChart/StaticChartRasterizer.tsx +178 -0
- package/src/grapher/captionedChart/assets/buildcanada-logo-square.svg +15 -0
- package/src/grapher/captionedChart/assets/buildcanada-logo.svg +15 -0
- package/src/grapher/captionedChart/assets/canadaspends.svg +7 -0
- package/src/grapher/captionedChart/readme.md +14 -0
- package/src/grapher/chart/Chart.tsx +62 -0
- package/src/grapher/chart/ChartAreaContent.tsx +172 -0
- package/src/grapher/chart/ChartDimension.ts +121 -0
- package/src/grapher/chart/ChartInterface.ts +83 -0
- package/src/grapher/chart/ChartManager.ts +113 -0
- package/src/grapher/chart/ChartTabs.ts +178 -0
- package/src/grapher/chart/ChartTypeMap.tsx +158 -0
- package/src/grapher/chart/ChartTypeSwitcher.tsx +26 -0
- package/src/grapher/chart/ChartUtils.tsx +364 -0
- package/src/grapher/chart/DimensionSlot.ts +45 -0
- package/src/grapher/chart/StaticChartWrapper.tsx +94 -0
- package/src/grapher/chart/guidedChartUtils.ts +82 -0
- package/src/grapher/color/BinningStrategies.ts +484 -0
- package/src/grapher/color/BinningStrategyEqualSizeBins.ts +132 -0
- package/src/grapher/color/BinningStrategyLogarithmic.ts +121 -0
- package/src/grapher/color/CategoricalColorAssigner.ts +97 -0
- package/src/grapher/color/ColorBrewerSchemes.ts +80 -0
- package/src/grapher/color/ColorConstants.ts +20 -0
- package/src/grapher/color/ColorScale.ts +339 -0
- package/src/grapher/color/ColorScaleBin.ts +147 -0
- package/src/grapher/color/ColorScaleConfig.ts +204 -0
- package/src/grapher/color/ColorScheme.ts +137 -0
- package/src/grapher/color/ColorSchemes.ts +149 -0
- package/src/grapher/color/ColorUtils.ts +86 -0
- package/src/grapher/color/CustomSchemes.ts +1772 -0
- package/src/grapher/color/readme.md +84 -0
- package/src/grapher/comparisonLine/ComparisonLine.tsx +31 -0
- package/src/grapher/comparisonLine/ComparisonLineConstants.ts +11 -0
- package/src/grapher/comparisonLine/ComparisonLineGenerator.ts +60 -0
- package/src/grapher/comparisonLine/ComparisonLineHelpers.ts +10 -0
- package/src/grapher/comparisonLine/CustomComparisonLine.tsx +159 -0
- package/src/grapher/comparisonLine/VerticalComparisonLine.tsx +208 -0
- package/src/grapher/controls/ActionButtons.scss +97 -0
- package/src/grapher/controls/ActionButtons.tsx +453 -0
- package/src/grapher/controls/CommandPalette.scss +50 -0
- package/src/grapher/controls/CommandPalette.tsx +74 -0
- package/src/grapher/controls/ContentSwitchers.scss +93 -0
- package/src/grapher/controls/ContentSwitchers.tsx +238 -0
- package/src/grapher/controls/Controls.scss +158 -0
- package/src/grapher/controls/DataTableFilterDropdown.scss +7 -0
- package/src/grapher/controls/DataTableFilterDropdown.tsx +168 -0
- package/src/grapher/controls/DataTableSearchField.scss +3 -0
- package/src/grapher/controls/DataTableSearchField.tsx +76 -0
- package/src/grapher/controls/Dropdown.scss +252 -0
- package/src/grapher/controls/Dropdown.tsx +235 -0
- package/src/grapher/controls/EntitySelectionToggle.tsx +135 -0
- package/src/grapher/controls/MapRegionDropdown.scss +3 -0
- package/src/grapher/controls/MapRegionDropdown.tsx +104 -0
- package/src/grapher/controls/MapResetButton.tsx +115 -0
- package/src/grapher/controls/MapZoomDropdown.scss +9 -0
- package/src/grapher/controls/MapZoomDropdown.tsx +270 -0
- package/src/grapher/controls/MapZoomToSelectionButton.tsx +87 -0
- package/src/grapher/controls/SearchField.scss +78 -0
- package/src/grapher/controls/SearchField.tsx +63 -0
- package/src/grapher/controls/SettingsMenu.scss +191 -0
- package/src/grapher/controls/SettingsMenu.tsx +399 -0
- package/src/grapher/controls/ShareMenu.scss +58 -0
- package/src/grapher/controls/ShareMenu.tsx +304 -0
- package/src/grapher/controls/SortIcon.tsx +39 -0
- package/src/grapher/controls/VerticalScrollContainer.tsx +263 -0
- package/src/grapher/controls/controlsRow/ControlsRow.tsx +168 -0
- package/src/grapher/controls/dropdown-icons.scss +4 -0
- package/src/grapher/controls/entityPicker/EntityPicker.scss +255 -0
- package/src/grapher/controls/entityPicker/EntityPicker.tsx +816 -0
- package/src/grapher/controls/entityPicker/EntityPickerConstants.ts +23 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.scss +129 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.tsx +463 -0
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelectorConstants.ts +3 -0
- package/src/grapher/controls/globalEntitySelector/readme.md +17 -0
- package/src/grapher/controls/settings/AbsRelToggle.tsx +64 -0
- package/src/grapher/controls/settings/AxisScaleToggle.tsx +53 -0
- package/src/grapher/controls/settings/FacetStrategySelector.tsx +110 -0
- package/src/grapher/controls/settings/FacetYDomainToggle.tsx +51 -0
- package/src/grapher/controls/settings/NoDataAreaToggle.tsx +38 -0
- package/src/grapher/controls/settings/ZoomToggle.tsx +36 -0
- package/src/grapher/core/EntitiesByRegionType.ts +174 -0
- package/src/grapher/core/EntityCodes.ts +19 -0
- package/src/grapher/core/EntityUrlBuilder.ts +200 -0
- package/src/grapher/core/FetchingGrapher.tsx +156 -0
- package/src/grapher/core/Grapher.tsx +760 -0
- package/src/grapher/core/GrapherAnalytics.ts +229 -0
- package/src/grapher/core/GrapherConstants.ts +173 -0
- package/src/grapher/core/GrapherState.tsx +3659 -0
- package/src/grapher/core/GrapherUrl.ts +184 -0
- package/src/grapher/core/GrapherUrlMigrations.ts +29 -0
- package/src/grapher/core/GrapherUseHelpers.tsx +147 -0
- package/src/grapher/core/LegacyToOwidTable.ts +841 -0
- package/src/grapher/core/grapher.entry.ts +5 -0
- package/src/grapher/core/grapher.scss +257 -0
- package/src/grapher/core/loadGrapherTableHelpers.ts +116 -0
- package/src/grapher/core/loadVariable.ts +104 -0
- package/src/grapher/core/relatedQuestion.ts +12 -0
- package/src/grapher/core/typography.scss +206 -0
- package/src/grapher/dataTable/DataTable.sample.ts +206 -0
- package/src/grapher/dataTable/DataTable.scss +249 -0
- package/src/grapher/dataTable/DataTable.tsx +1332 -0
- package/src/grapher/dataTable/DataTableConstants.ts +186 -0
- package/src/grapher/entitySelector/EntitySelector.scss +255 -0
- package/src/grapher/entitySelector/EntitySelector.tsx +1838 -0
- package/src/grapher/facet/FacetChart.tsx +943 -0
- package/src/grapher/facet/FacetChartConstants.ts +24 -0
- package/src/grapher/facet/FacetChartUtils.ts +51 -0
- package/src/grapher/facet/FacetMap.tsx +604 -0
- package/src/grapher/facet/FacetMapConstants.ts +23 -0
- package/src/grapher/facet/readme.md +13 -0
- package/src/grapher/focus/FocusArray.ts +79 -0
- package/src/grapher/footer/Footer.scss +63 -0
- package/src/grapher/footer/Footer.tsx +809 -0
- package/src/grapher/footer/FooterManager.ts +44 -0
- package/src/grapher/fullScreen/FullScreen.scss +11 -0
- package/src/grapher/fullScreen/FullScreen.tsx +61 -0
- package/src/grapher/header/Header.scss +35 -0
- package/src/grapher/header/Header.tsx +372 -0
- package/src/grapher/header/HeaderManager.ts +28 -0
- package/src/grapher/index.ts +157 -0
- package/src/grapher/interaction/InteractionState.ts +60 -0
- package/src/grapher/legend/HorizontalColorLegends.tsx +923 -0
- package/src/grapher/legend/LegendInteractionState.ts +40 -0
- package/src/grapher/legend/VerticalColorLegend.tsx +295 -0
- package/src/grapher/lineCharts/LineChart.tsx +968 -0
- package/src/grapher/lineCharts/LineChartConstants.ts +89 -0
- package/src/grapher/lineCharts/LineChartHelpers.ts +184 -0
- package/src/grapher/lineCharts/LineChartState.ts +394 -0
- package/src/grapher/lineCharts/LineChartThumbnail.tsx +437 -0
- package/src/grapher/lineCharts/Lines.tsx +258 -0
- package/src/grapher/lineLegend/LineLegend.tsx +723 -0
- package/src/grapher/lineLegend/LineLegendConstants.ts +9 -0
- package/src/grapher/lineLegend/LineLegendFilterAlgorithms.ts +143 -0
- package/src/grapher/lineLegend/LineLegendHelpers.ts +253 -0
- package/src/grapher/lineLegend/LineLegendTypes.ts +32 -0
- package/src/grapher/mapCharts/CanadaTopology.ts +17922 -0
- package/src/grapher/mapCharts/ChoroplethGlobe.tsx +949 -0
- package/src/grapher/mapCharts/ChoroplethMap.tsx +662 -0
- package/src/grapher/mapCharts/GeoFeatures.ts +184 -0
- package/src/grapher/mapCharts/GlobeController.ts +496 -0
- package/src/grapher/mapCharts/MapAnnotationPlacements.json +1040 -0
- package/src/grapher/mapCharts/MapAnnotationPlacements.ts +31 -0
- package/src/grapher/mapCharts/MapAnnotations.ts +723 -0
- package/src/grapher/mapCharts/MapChart.sample.ts +59 -0
- package/src/grapher/mapCharts/MapChart.scss +5 -0
- package/src/grapher/mapCharts/MapChart.tsx +720 -0
- package/src/grapher/mapCharts/MapChartConstants.ts +260 -0
- package/src/grapher/mapCharts/MapChartState.ts +416 -0
- package/src/grapher/mapCharts/MapChartThumbnail.tsx +25 -0
- package/src/grapher/mapCharts/MapComponents.tsx +338 -0
- package/src/grapher/mapCharts/MapConfig.ts +156 -0
- package/src/grapher/mapCharts/MapHelpers.ts +181 -0
- package/src/grapher/mapCharts/MapProjections.ts +49 -0
- package/src/grapher/mapCharts/MapSparkline.tsx +257 -0
- package/src/grapher/mapCharts/MapTooltip.scss +49 -0
- package/src/grapher/mapCharts/MapTooltip.tsx +409 -0
- package/src/grapher/mapCharts/MapTopology.ts +1766 -0
- package/src/grapher/mapCharts/d3-bboxCollide.js +204 -0
- package/src/grapher/mapCharts/d3-geo-projection.ts +198 -0
- package/src/grapher/modal/DownloadIcons.tsx +39 -0
- package/src/grapher/modal/DownloadModal.scss +300 -0
- package/src/grapher/modal/DownloadModal.tsx +1226 -0
- package/src/grapher/modal/EmbedModal.scss +40 -0
- package/src/grapher/modal/EmbedModal.tsx +160 -0
- package/src/grapher/modal/EntitySelectorModal.tsx +59 -0
- package/src/grapher/modal/Modal.scss +31 -0
- package/src/grapher/modal/Modal.tsx +90 -0
- package/src/grapher/modal/ModalHeader.scss +12 -0
- package/src/grapher/modal/ModalHeader.tsx +16 -0
- package/src/grapher/modal/SourcesDescriptions.scss +87 -0
- package/src/grapher/modal/SourcesDescriptions.tsx +89 -0
- package/src/grapher/modal/SourcesKeyDataTable.scss +49 -0
- package/src/grapher/modal/SourcesKeyDataTable.tsx +87 -0
- package/src/grapher/modal/SourcesModal.scss +301 -0
- package/src/grapher/modal/SourcesModal.tsx +568 -0
- package/src/grapher/noDataModal/NoDataModal.tsx +125 -0
- package/src/grapher/scatterCharts/ConnectedScatterLegend.tsx +143 -0
- package/src/grapher/scatterCharts/MultiColorPolyline.tsx +129 -0
- package/src/grapher/scatterCharts/NoDataSection.scss +14 -0
- package/src/grapher/scatterCharts/NoDataSection.tsx +56 -0
- package/src/grapher/scatterCharts/ScatterPlotChart.tsx +792 -0
- package/src/grapher/scatterCharts/ScatterPlotChartConstants.ts +157 -0
- package/src/grapher/scatterCharts/ScatterPlotChartState.ts +678 -0
- package/src/grapher/scatterCharts/ScatterPlotChartThumbnail.tsx +155 -0
- package/src/grapher/scatterCharts/ScatterPlotTooltip.tsx +560 -0
- package/src/grapher/scatterCharts/ScatterPoints.tsx +153 -0
- package/src/grapher/scatterCharts/ScatterPointsWithLabels.tsx +708 -0
- package/src/grapher/scatterCharts/ScatterSizeLegend.tsx +327 -0
- package/src/grapher/scatterCharts/ScatterUtils.ts +265 -0
- package/src/grapher/scatterCharts/Triangle.tsx +41 -0
- package/src/grapher/schema/README.md +33 -0
- package/src/grapher/schema/defaultGrapherConfig.ts +100 -0
- package/src/grapher/schema/grapher-schema.009.yaml +781 -0
- package/src/grapher/schema/migrations/helpers.ts +58 -0
- package/src/grapher/schema/migrations/migrate.ts +75 -0
- package/src/grapher/schema/migrations/migrations.ts +158 -0
- package/src/grapher/selection/MapSelectionArray.ts +99 -0
- package/src/grapher/selection/SelectionArray.ts +71 -0
- package/src/grapher/selection/readme.md +16 -0
- package/src/grapher/sidePanel/SidePanel.scss +10 -0
- package/src/grapher/sidePanel/SidePanel.tsx +23 -0
- package/src/grapher/slideInDrawer/SlideInDrawer.scss +57 -0
- package/src/grapher/slideInDrawer/SlideInDrawer.tsx +125 -0
- package/src/grapher/slideshowController/SlideShowController.tsx +43 -0
- package/src/grapher/slideshowController/readme.md +7 -0
- package/src/grapher/slopeCharts/MarkX.tsx +45 -0
- package/src/grapher/slopeCharts/Slope.tsx +102 -0
- package/src/grapher/slopeCharts/SlopeChart.tsx +1152 -0
- package/src/grapher/slopeCharts/SlopeChartConstants.ts +33 -0
- package/src/grapher/slopeCharts/SlopeChartHelpers.ts +73 -0
- package/src/grapher/slopeCharts/SlopeChartState.ts +392 -0
- package/src/grapher/slopeCharts/SlopeChartThumbnail.tsx +368 -0
- package/src/grapher/stackedCharts/AbstractStackedChartState.ts +370 -0
- package/src/grapher/stackedCharts/MarimekkoBars.tsx +190 -0
- package/src/grapher/stackedCharts/MarimekkoBarsForOneEntity.tsx +168 -0
- package/src/grapher/stackedCharts/MarimekkoChart.tsx +1144 -0
- package/src/grapher/stackedCharts/MarimekkoChartConstants.ts +112 -0
- package/src/grapher/stackedCharts/MarimekkoChartHelpers.ts +21 -0
- package/src/grapher/stackedCharts/MarimekkoChartState.ts +465 -0
- package/src/grapher/stackedCharts/MarimekkoChartThumbnail.tsx +168 -0
- package/src/grapher/stackedCharts/MarimekkoInternalLabels.tsx +124 -0
- package/src/grapher/stackedCharts/StackedAreaChart.tsx +678 -0
- package/src/grapher/stackedCharts/StackedAreaChartState.ts +34 -0
- package/src/grapher/stackedCharts/StackedAreaChartThumbnail.tsx +215 -0
- package/src/grapher/stackedCharts/StackedAreas.tsx +223 -0
- package/src/grapher/stackedCharts/StackedBarChart.tsx +619 -0
- package/src/grapher/stackedCharts/StackedBarChartState.ts +80 -0
- package/src/grapher/stackedCharts/StackedBarChartThumbnail.tsx +220 -0
- package/src/grapher/stackedCharts/StackedBarSegment.tsx +87 -0
- package/src/grapher/stackedCharts/StackedBars.tsx +102 -0
- package/src/grapher/stackedCharts/StackedConstants.ts +109 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChart.tsx +270 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChartState.ts +296 -0
- package/src/grapher/stackedCharts/StackedDiscreteBarChartThumbnail.tsx +27 -0
- package/src/grapher/stackedCharts/StackedDiscreteBars.tsx +648 -0
- package/src/grapher/stackedCharts/StackedUtils.ts +142 -0
- package/src/grapher/tabs/Tabs.scss +169 -0
- package/src/grapher/tabs/Tabs.tsx +54 -0
- package/src/grapher/tabs/TabsWithDropdown.scss +62 -0
- package/src/grapher/tabs/TabsWithDropdown.tsx +114 -0
- package/src/grapher/testData/OwidTestData.sample.ts +273 -0
- package/src/grapher/testData/OwidTestData.ts +64 -0
- package/src/grapher/timeline/TimelineComponent.scss +139 -0
- package/src/grapher/timeline/TimelineComponent.tsx +658 -0
- package/src/grapher/timeline/TimelineController.ts +368 -0
- package/src/grapher/timeline/readme.md +7 -0
- package/src/grapher/tooltip/Tooltip.scss +510 -0
- package/src/grapher/tooltip/Tooltip.tsx +294 -0
- package/src/grapher/tooltip/TooltipContents.tsx +383 -0
- package/src/grapher/tooltip/TooltipProps.ts +123 -0
- package/src/grapher/tooltip/TooltipState.ts +81 -0
- package/src/grapher/verticalLabels/VerticalLabels.tsx +31 -0
- package/src/grapher/verticalLabels/VerticalLabelsState.ts +154 -0
- package/src/index.ts +226 -0
- package/src/styles/charts.scss +15 -0
- package/src/types/NominalType.ts +30 -0
- package/src/types/OwidOrigin.ts +18 -0
- package/src/types/OwidSource.ts +9 -0
- package/src/types/OwidVariable.ts +133 -0
- package/src/types/OwidVariableDisplayConfigInterface.ts +49 -0
- package/src/types/analyticsTypes.ts +54 -0
- package/src/types/dbTypes/Tags.ts +11 -0
- package/src/types/domainTypes/Archive.ts +139 -0
- package/src/types/domainTypes/Author.ts +28 -0
- package/src/types/domainTypes/ContentGraph.ts +76 -0
- package/src/types/domainTypes/CoreTableTypes.ts +305 -0
- package/src/types/domainTypes/DeployStatus.ts +23 -0
- package/src/types/domainTypes/Layout.ts +34 -0
- package/src/types/domainTypes/Posts.ts +34 -0
- package/src/types/domainTypes/Search.ts +299 -0
- package/src/types/domainTypes/Site.ts +8 -0
- package/src/types/domainTypes/StaticViz.ts +64 -0
- package/src/types/domainTypes/Toc.ts +11 -0
- package/src/types/domainTypes/Tombstone.ts +19 -0
- package/src/types/domainTypes/Various.ts +79 -0
- package/src/types/gdocTypes/Gdoc.ts +280 -0
- package/src/types/grapherTypes/BinningStrategyTypes.ts +46 -0
- package/src/types/grapherTypes/GrapherConstants.ts +53 -0
- package/src/types/grapherTypes/GrapherTypes.ts +743 -0
- package/src/types/index.ts +316 -0
- package/src/types/wordpressTypes/WordpressTypes.ts +9 -0
- package/src/utils/Bounds.ts +439 -0
- package/src/utils/BrowserUtils.ts +12 -0
- package/src/utils/FuzzySearch.ts +74 -0
- package/src/utils/MultiDimDataPageConfig.ts +31 -0
- package/src/utils/OwidVariable.ts +82 -0
- package/src/utils/PointVector.ts +97 -0
- package/src/utils/PromiseCache.ts +36 -0
- package/src/utils/PromiseSwitcher.ts +52 -0
- package/src/utils/TimeBounds.ts +130 -0
- package/src/utils/Tippy.tsx +57 -0
- package/src/utils/Util.ts +2369 -0
- package/src/utils/archival/archivalDate.ts +48 -0
- package/src/utils/dayjs.ts +32 -0
- package/src/utils/formatValue.ts +242 -0
- package/src/utils/grapherConfigUtils.ts +81 -0
- package/src/utils/image.ts +225 -0
- package/src/utils/index.ts +318 -0
- package/src/utils/isPresent.ts +5 -0
- package/src/utils/metadataHelpers.ts +329 -0
- package/src/utils/persistable/Persistable.ts +82 -0
- package/src/utils/persistable/readme.md +50 -0
- package/src/utils/regions.json +5635 -0
- package/src/utils/regions.ts +463 -0
- package/src/utils/serializers.ts +16 -0
- package/src/utils/string.ts +42 -0
- package/src/utils/urls/Url.ts +195 -0
- package/src/utils/urls/UrlMigration.ts +10 -0
- package/src/utils/urls/UrlUtils.ts +54 -0
- package/src/utils/urls/readme.md +90 -0
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
import * as _ from "lodash-es"
|
|
2
|
+
import {
|
|
3
|
+
anyToString,
|
|
4
|
+
csvEscape,
|
|
5
|
+
formatYear,
|
|
6
|
+
formatDay,
|
|
7
|
+
sortNumeric,
|
|
8
|
+
dateDiffInDays,
|
|
9
|
+
omitUndefinedValues,
|
|
10
|
+
isPresent,
|
|
11
|
+
dayjs,
|
|
12
|
+
OwidSource,
|
|
13
|
+
formatValue,
|
|
14
|
+
checkIsVeryShortUnit,
|
|
15
|
+
TickFormattingOptions,
|
|
16
|
+
OwidVariableDisplayConfigInterface,
|
|
17
|
+
ColumnSlug,
|
|
18
|
+
PrimitiveType,
|
|
19
|
+
imemo,
|
|
20
|
+
ToleranceStrategy,
|
|
21
|
+
IndicatorTitleWithFragments,
|
|
22
|
+
stripOuterParentheses,
|
|
23
|
+
} from "../utils/index.js"
|
|
24
|
+
import { CoreTable } from "./CoreTable.js"
|
|
25
|
+
import {
|
|
26
|
+
Time,
|
|
27
|
+
JsTypes,
|
|
28
|
+
CoreValueType,
|
|
29
|
+
ColumnTypeNames,
|
|
30
|
+
CoreColumnDef,
|
|
31
|
+
EntityName,
|
|
32
|
+
OwidVariableRow,
|
|
33
|
+
ErrorValue,
|
|
34
|
+
OwidVariableRoundingMode,
|
|
35
|
+
} from "../types/index.js"
|
|
36
|
+
import { ErrorValueTypes, isNotErrorValue } from "./ErrorValues.js"
|
|
37
|
+
import {
|
|
38
|
+
getOriginalStartTimeColumnSlug,
|
|
39
|
+
getOriginalTimeColumnSlug,
|
|
40
|
+
getOriginalValueColumnSlug,
|
|
41
|
+
} from "./OwidTableUtil.js"
|
|
42
|
+
import * as R from "remeda"
|
|
43
|
+
|
|
44
|
+
export abstract class AbstractCoreColumn<JS_TYPE extends PrimitiveType> {
|
|
45
|
+
def: CoreColumnDef
|
|
46
|
+
table: CoreTable
|
|
47
|
+
|
|
48
|
+
constructor(table: CoreTable, def: CoreColumnDef) {
|
|
49
|
+
this.table = table
|
|
50
|
+
this.def = def
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
abstract jsType: JsTypes
|
|
54
|
+
|
|
55
|
+
parse(val: unknown): any {
|
|
56
|
+
return val
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@imemo get isMissing(): boolean {
|
|
60
|
+
return this instanceof MissingColumn
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@imemo get isTimeColumn(): boolean {
|
|
64
|
+
return this instanceof TimeColumn
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@imemo get hasNumberFormatting(): boolean {
|
|
68
|
+
return this instanceof AbstractColumnWithNumberFormatting
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// todo: migrate from unitConversionFactor to computed columns instead. then delete this.
|
|
72
|
+
// note: unitConversionFactor is used >400 times in charts and >800 times in variables!!!
|
|
73
|
+
@imemo get unitConversionFactor(): number {
|
|
74
|
+
return this.display?.conversionFactor ?? 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@imemo get isAllIntegers(): boolean {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@imemo get tolerance(): number {
|
|
82
|
+
return this.display?.tolerance ?? this.def.tolerance ?? 0
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@imemo get toleranceStrategy(): ToleranceStrategy | undefined {
|
|
86
|
+
return this.def.toleranceStrategy
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@imemo get display(): OwidVariableDisplayConfigInterface | undefined {
|
|
90
|
+
return this.def.display
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
abstract formatValue(
|
|
94
|
+
value: unknown,
|
|
95
|
+
options?: TickFormattingOptions
|
|
96
|
+
): string
|
|
97
|
+
|
|
98
|
+
formatValueForMobile(
|
|
99
|
+
value: unknown,
|
|
100
|
+
options?: TickFormattingOptions
|
|
101
|
+
): string {
|
|
102
|
+
return this.formatValue(value, options)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
formatValueShortWithAbbreviations(
|
|
106
|
+
value: unknown,
|
|
107
|
+
options?: TickFormattingOptions
|
|
108
|
+
): string {
|
|
109
|
+
return this.formatValue(value, options)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
formatValueShort(value: unknown, options?: TickFormattingOptions): string {
|
|
113
|
+
return this.formatValue(value, options)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
formatValueLong(value: unknown, options?: TickFormattingOptions): string {
|
|
117
|
+
return this.formatValue(value, options)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
formatForTick(value: unknown, options?: TickFormattingOptions): string {
|
|
121
|
+
return this.formatValueShort(value, options)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// A method for formatting for CSV
|
|
125
|
+
formatForCsv(value: JS_TYPE): string {
|
|
126
|
+
return csvEscape(anyToString(value))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
formatTime(time: number): string {
|
|
130
|
+
return this.originalTimeColumn.formatValue(time)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@imemo get roundingMode(): OwidVariableRoundingMode {
|
|
134
|
+
return (
|
|
135
|
+
this.display?.roundingMode ?? OwidVariableRoundingMode.decimalPlaces
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@imemo get roundsToFixedDecimals(): boolean {
|
|
140
|
+
return this.roundingMode === OwidVariableRoundingMode.decimalPlaces
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@imemo get roundsToSignificantFigures(): boolean {
|
|
144
|
+
return this.roundingMode === OwidVariableRoundingMode.significantFigures
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@imemo get numDecimalPlaces(): number {
|
|
148
|
+
return this.display?.numDecimalPlaces ?? 2
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@imemo get numSignificantFigures(): number {
|
|
152
|
+
return this.display?.numSignificantFigures ?? 3
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@imemo get unit(): string | undefined {
|
|
156
|
+
const unit = this.display?.unit ?? this.def.unit
|
|
157
|
+
return unit?.trim()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@imemo get shortUnit(): string | undefined {
|
|
161
|
+
const shortUnit =
|
|
162
|
+
this.display?.shortUnit ?? this.def.shortUnit ?? undefined
|
|
163
|
+
if (shortUnit !== undefined) return shortUnit
|
|
164
|
+
|
|
165
|
+
const unit = this.unit
|
|
166
|
+
|
|
167
|
+
if (!unit) return undefined
|
|
168
|
+
|
|
169
|
+
if (unit.length < 3) return unit
|
|
170
|
+
if (checkIsVeryShortUnit(unit[0])) return unit[0]
|
|
171
|
+
|
|
172
|
+
return undefined
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Returns the full unit string for display, but only if it is different from the shortUnit.
|
|
177
|
+
* This avoids redundant display of units when the short and full units are the same.
|
|
178
|
+
* Also strips parentheses from the beginning and end of the unit.
|
|
179
|
+
*/
|
|
180
|
+
@imemo get displayUnit(): string | undefined {
|
|
181
|
+
// The unit is considered trivial if it is the same as the short unit
|
|
182
|
+
const tooTrivial = this.unit === this.shortUnit
|
|
183
|
+
const displayUnit = !tooTrivial ? this.unit : undefined
|
|
184
|
+
|
|
185
|
+
// Remove parentheses from the beginning and end of the unit
|
|
186
|
+
const strippedUnit = displayUnit
|
|
187
|
+
? stripOuterParentheses(displayUnit)
|
|
188
|
+
: undefined
|
|
189
|
+
|
|
190
|
+
return strippedUnit
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Returns a map where the key is a series slug such as "name" and the value is a set
|
|
194
|
+
// of all the unique values that this column has for that particular series.
|
|
195
|
+
getUniqueValuesGroupedBy(
|
|
196
|
+
indexColumnSlug: ColumnSlug
|
|
197
|
+
): Map<PrimitiveType, Set<PrimitiveType>> {
|
|
198
|
+
const map = new Map<PrimitiveType, Set<PrimitiveType>>()
|
|
199
|
+
const values = this.values
|
|
200
|
+
const indexValues = this.table.getValuesAtIndices(
|
|
201
|
+
indexColumnSlug,
|
|
202
|
+
this.validRowIndices
|
|
203
|
+
) as PrimitiveType[]
|
|
204
|
+
indexValues.forEach((indexVal, index) => {
|
|
205
|
+
if (!map.has(indexVal)) map.set(indexVal, new Set())
|
|
206
|
+
map.get(indexVal)!.add(values[index])
|
|
207
|
+
})
|
|
208
|
+
return map
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@imemo get description(): string | undefined {
|
|
212
|
+
return this.def.description
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@imemo get isEmpty(): boolean {
|
|
216
|
+
return this.valuesIncludingErrorValues.length === 0
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@imemo get name(): string {
|
|
220
|
+
return this.def.name ?? this.def.slug
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@imemo get nonEmptyName(): string {
|
|
224
|
+
return this.def.name || this.def.slug
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@imemo get displayName(): string {
|
|
228
|
+
return (
|
|
229
|
+
this.display?.name ??
|
|
230
|
+
// this is a bit of an unusual fallback - if display.name is not given, titlePublic is the next best thing before name
|
|
231
|
+
this.def.presentation?.titlePublic ??
|
|
232
|
+
this.name ??
|
|
233
|
+
""
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@imemo get nonEmptyDisplayName(): string {
|
|
238
|
+
return (
|
|
239
|
+
this.display?.name ||
|
|
240
|
+
// this is a bit of an unusual fallback - if display.name is not given, titlePublic is the next best thing before name
|
|
241
|
+
this.def.presentation?.titlePublic ||
|
|
242
|
+
this.nonEmptyName
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@imemo get titlePublicOrDisplayName(): IndicatorTitleWithFragments {
|
|
247
|
+
return this.def.presentation?.titlePublic
|
|
248
|
+
? {
|
|
249
|
+
title: this.def.presentation?.titlePublic,
|
|
250
|
+
attributionShort: this.def.presentation?.attributionShort,
|
|
251
|
+
titleVariant: this.def.presentation?.titleVariant,
|
|
252
|
+
}
|
|
253
|
+
: { title: this.display?.name || this.name || "" }
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@imemo get datasetId(): number | undefined {
|
|
257
|
+
return this.def.datasetId
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@imemo get datasetName(): string | undefined {
|
|
261
|
+
return this.def.datasetName
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// todo: is the isString necessary?
|
|
265
|
+
@imemo get sortedUniqNonEmptyStringVals(): JS_TYPE[] {
|
|
266
|
+
return Array.from(
|
|
267
|
+
new Set(this.values.filter(R.isString).filter((i) => i))
|
|
268
|
+
).sort()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@imemo get slug(): string {
|
|
272
|
+
return this.def.slug
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@imemo get valuesToIndices(): Map<any, number[]> {
|
|
276
|
+
const map = new Map<any, number[]>()
|
|
277
|
+
this.valuesIncludingErrorValues.forEach((value, index) => {
|
|
278
|
+
if (!map.has(value)) map.set(value, [])
|
|
279
|
+
map.get(value)!.push(index)
|
|
280
|
+
})
|
|
281
|
+
return map
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
indicesWhere(value: JS_TYPE | JS_TYPE[]): any {
|
|
285
|
+
const queries = Array.isArray(value) ? value : [value]
|
|
286
|
+
return _.union(
|
|
287
|
+
...queries
|
|
288
|
+
.map((val) => this.valuesToIndices.get(val))
|
|
289
|
+
.filter(isPresent)
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// We approximate whether a column is parsed simply by looking at the first row.
|
|
294
|
+
needsParsing(value: unknown): boolean {
|
|
295
|
+
// Skip parsing if explicit flag is set
|
|
296
|
+
if (this.def.skipParsing) return false
|
|
297
|
+
|
|
298
|
+
// Never parse computeds. The computed should return the correct JS type. Ideally we can provide some error messaging around this.
|
|
299
|
+
if (this.def.transform) return false
|
|
300
|
+
|
|
301
|
+
// If we already tried to parse it and failed we consider it "parsed"
|
|
302
|
+
if (value instanceof ErrorValue) return false
|
|
303
|
+
|
|
304
|
+
// If the passed value is of the correct type consider the column parsed.
|
|
305
|
+
if (typeof value === this.jsType) return false
|
|
306
|
+
return true
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@imemo get isProjection(): boolean {
|
|
310
|
+
return !!this.display?.isProjection
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@imemo get uniqValues(): JS_TYPE[] {
|
|
314
|
+
const set = this.uniqValuesAsSet
|
|
315
|
+
|
|
316
|
+
// Turn into array, faster than spread operator
|
|
317
|
+
const arr = new Array(set.size)
|
|
318
|
+
let i = 0
|
|
319
|
+
set.forEach((val) => (arr[i++] = val))
|
|
320
|
+
return arr
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@imemo get uniqValuesAsSet(): Set<JS_TYPE> {
|
|
324
|
+
return new Set(this.values)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Returns all values including ErrorValues..
|
|
329
|
+
* Normally you want just the valid values, like `[45000, 50000, ...]`. But sometimes you
|
|
330
|
+
* need the ErrorValues too like `[45000, DivideByZeroError, 50000,...]`
|
|
331
|
+
*/
|
|
332
|
+
@imemo get valuesIncludingErrorValues(): CoreValueType[] {
|
|
333
|
+
const { table, slug } = this
|
|
334
|
+
return table.has(slug) ? table.columnStore[slug] : []
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@imemo get validRowIndices(): number[] {
|
|
338
|
+
const indices: number[] = []
|
|
339
|
+
for (let i = 0; i < this.valuesIncludingErrorValues.length; i++) {
|
|
340
|
+
const value = this.valuesIncludingErrorValues[i]
|
|
341
|
+
if (isNotErrorValue(value)) indices.push(i)
|
|
342
|
+
}
|
|
343
|
+
return indices
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
@imemo get values(): JS_TYPE[] {
|
|
347
|
+
const values: JS_TYPE[] = []
|
|
348
|
+
|
|
349
|
+
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
350
|
+
for (let i = 0; i < this.valuesIncludingErrorValues.length; i++) {
|
|
351
|
+
const value = this.valuesIncludingErrorValues[i]
|
|
352
|
+
if (isNotErrorValue(value)) values.push(value as JS_TYPE)
|
|
353
|
+
}
|
|
354
|
+
return values
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@imemo get originalTimeColumnSlug(): string {
|
|
358
|
+
return getOriginalTimeColumnSlug(this.table, this.slug)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@imemo get originalTimeColumn(): CoreColumn {
|
|
362
|
+
return this.table.get(this.originalTimeColumnSlug)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
@imemo get originalStartTimeColumnSlug(): string {
|
|
366
|
+
return getOriginalStartTimeColumnSlug(this.table, this.slug)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
@imemo get originalStartTimeColumn(): CoreColumn {
|
|
370
|
+
return this.table.get(this.originalStartTimeColumnSlug)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
@imemo get originalTimes(): number[] {
|
|
374
|
+
const { originalTimeColumnSlug } = this
|
|
375
|
+
if (!originalTimeColumnSlug) return []
|
|
376
|
+
return this.table.getValuesAtIndices(
|
|
377
|
+
originalTimeColumnSlug,
|
|
378
|
+
this.validRowIndices
|
|
379
|
+
) as number[]
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@imemo get originalValueColumnSlug(): string | undefined {
|
|
383
|
+
return getOriginalValueColumnSlug(this.table, this.slug)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
@imemo get originalValues(): JS_TYPE[] {
|
|
387
|
+
const { originalValueColumnSlug } = this
|
|
388
|
+
if (!originalValueColumnSlug) return []
|
|
389
|
+
return this.table.getValuesAtIndices(
|
|
390
|
+
originalValueColumnSlug,
|
|
391
|
+
this.validRowIndices
|
|
392
|
+
) as JS_TYPE[]
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
@imemo get minValue(): JS_TYPE | undefined {
|
|
396
|
+
return _.min(this.values)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
@imemo get maxValue(): JS_TYPE | undefined {
|
|
400
|
+
return _.max(this.values)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
@imemo get numErrorValues(): number {
|
|
404
|
+
return this.valuesIncludingErrorValues.length - this.numValues
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Number of correctly parsed values
|
|
408
|
+
@imemo get numValues(): number {
|
|
409
|
+
return this.values.length
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
@imemo get numUniqs(): number {
|
|
413
|
+
return this.uniqValuesAsSet.size
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
@imemo get valuesAscending(): JS_TYPE[] {
|
|
417
|
+
const values = this.values.slice()
|
|
418
|
+
return this.jsType === "string" ? values.sort() : sortNumeric(values)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
get source(): OwidSource {
|
|
422
|
+
const { def } = this
|
|
423
|
+
return {
|
|
424
|
+
name: def.sourceName,
|
|
425
|
+
link: def.sourceLink,
|
|
426
|
+
dataPublishedBy: def.dataPublishedBy,
|
|
427
|
+
dataPublisherSource: def.dataPublisherSource,
|
|
428
|
+
retrievedDate: def.retrievedDate,
|
|
429
|
+
additionalInfo: def.additionalInfo,
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// todo: remove. should not be on coretable
|
|
434
|
+
@imemo private get allTimes(): Time[] {
|
|
435
|
+
return this.table.getTimesAtIndices(this.validRowIndices)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// todo: remove. should not be on coretable
|
|
439
|
+
@imemo get uniqTimesAsc(): Time[] {
|
|
440
|
+
return sortNumeric(_.uniq(this.allTimes))
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// todo: remove. should not be on coretable
|
|
444
|
+
@imemo get maxTime(): Time {
|
|
445
|
+
return _.max(this.allTimes) as Time
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// todo: remove. should not be on coretable
|
|
449
|
+
@imemo get minTime(): Time {
|
|
450
|
+
return _.min(this.allTimes) as Time
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// todo: remove? Should not be on CoreTable
|
|
454
|
+
@imemo get uniqEntityNames(): EntityName[] {
|
|
455
|
+
return _.uniq(this.allEntityNames)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// todo: remove? Should not be on CoreTable
|
|
459
|
+
@imemo private get allEntityNames(): EntityName[] {
|
|
460
|
+
return this.table.getValuesAtIndices(
|
|
461
|
+
this.table.entityNameSlug,
|
|
462
|
+
this.validRowIndices
|
|
463
|
+
) as EntityName[]
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// todo: remove? Should not be on CoreTable
|
|
467
|
+
// assumes table is sorted by time
|
|
468
|
+
@imemo get owidRows(): OwidVariableRow<JS_TYPE>[] {
|
|
469
|
+
const entities = this.allEntityNames
|
|
470
|
+
const times = this.allTimes
|
|
471
|
+
const values = this.values
|
|
472
|
+
const originalTimes = this.originalTimes
|
|
473
|
+
const originalValues = this.originalValues
|
|
474
|
+
return _.range(0, originalTimes.length).map((index) => {
|
|
475
|
+
return omitUndefinedValues({
|
|
476
|
+
entityName: entities[index],
|
|
477
|
+
time: times[index],
|
|
478
|
+
value: values[index],
|
|
479
|
+
originalTime: originalTimes[index],
|
|
480
|
+
originalValue: originalValues[index],
|
|
481
|
+
})
|
|
482
|
+
})
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// todo: remove? Should not be on CoreTable
|
|
486
|
+
@imemo get owidRowsByEntityName(): Map<
|
|
487
|
+
EntityName,
|
|
488
|
+
OwidVariableRow<JS_TYPE>[]
|
|
489
|
+
> {
|
|
490
|
+
const map = new Map<EntityName, OwidVariableRow<JS_TYPE>[]>()
|
|
491
|
+
this.owidRows.forEach((row) => {
|
|
492
|
+
if (!map.has(row.entityName)) map.set(row.entityName, [])
|
|
493
|
+
map.get(row.entityName)!.push(row)
|
|
494
|
+
})
|
|
495
|
+
return map
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// todo: remove? Should not be on CoreTable
|
|
499
|
+
@imemo get owidRowByEntityNameAndTime(): Map<
|
|
500
|
+
EntityName,
|
|
501
|
+
Map<Time, OwidVariableRow<JS_TYPE>>
|
|
502
|
+
> {
|
|
503
|
+
const valueByEntityNameAndTime = new Map<
|
|
504
|
+
EntityName,
|
|
505
|
+
Map<Time, OwidVariableRow<JS_TYPE>>
|
|
506
|
+
>()
|
|
507
|
+
this.owidRows.forEach((row) => {
|
|
508
|
+
if (!valueByEntityNameAndTime.has(row.entityName))
|
|
509
|
+
valueByEntityNameAndTime.set(row.entityName, new Map())
|
|
510
|
+
valueByEntityNameAndTime.get(row.entityName)!.set(row.time, row)
|
|
511
|
+
})
|
|
512
|
+
return valueByEntityNameAndTime
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// todo: remove? Should not be on CoreTable
|
|
516
|
+
@imemo get valuesByTime(): Map<Time, JS_TYPE[]> {
|
|
517
|
+
const map = new Map<Time, JS_TYPE[]>()
|
|
518
|
+
this.owidRows.forEach((row) => {
|
|
519
|
+
if (!map.has(row.time)) map.set(row.time, [])
|
|
520
|
+
map.get(row.time)!.push(row.value)
|
|
521
|
+
})
|
|
522
|
+
return map
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// todo: remove? Should not be on CoreTable
|
|
526
|
+
@imemo get valueByTimeAndEntityName(): Map<Time, Map<EntityName, JS_TYPE>> {
|
|
527
|
+
const valueByTimeAndEntityName = new Map<
|
|
528
|
+
Time,
|
|
529
|
+
Map<EntityName, JS_TYPE>
|
|
530
|
+
>()
|
|
531
|
+
this.owidRows.forEach((row) => {
|
|
532
|
+
if (!valueByTimeAndEntityName.has(row.time))
|
|
533
|
+
valueByTimeAndEntityName.set(row.time, new Map())
|
|
534
|
+
valueByTimeAndEntityName
|
|
535
|
+
.get(row.time)!
|
|
536
|
+
.set(row.entityName, row.value)
|
|
537
|
+
})
|
|
538
|
+
return valueByTimeAndEntityName
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// todo: remove? Should not be on CoreTable
|
|
542
|
+
// NOTE: this uses the original times, so any tolerance is effectively unapplied.
|
|
543
|
+
@imemo get valueByEntityNameAndOriginalTime(): Map<
|
|
544
|
+
EntityName,
|
|
545
|
+
Map<Time, JS_TYPE>
|
|
546
|
+
> {
|
|
547
|
+
const valueByEntityNameAndTime = new Map<
|
|
548
|
+
EntityName,
|
|
549
|
+
Map<Time, JS_TYPE>
|
|
550
|
+
>()
|
|
551
|
+
this.owidRows.forEach((row) => {
|
|
552
|
+
if (!valueByEntityNameAndTime.has(row.entityName))
|
|
553
|
+
valueByEntityNameAndTime.set(row.entityName, new Map())
|
|
554
|
+
valueByEntityNameAndTime
|
|
555
|
+
.get(row.entityName)!
|
|
556
|
+
.set(row.originalTime, row.value)
|
|
557
|
+
})
|
|
558
|
+
return valueByEntityNameAndTime
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export type CoreColumn = AbstractCoreColumn<any>
|
|
563
|
+
|
|
564
|
+
export class MissingColumn extends AbstractCoreColumn<any> {
|
|
565
|
+
jsType = JsTypes.string
|
|
566
|
+
|
|
567
|
+
formatValue(): string {
|
|
568
|
+
return ""
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
class StringColumn extends AbstractCoreColumn<string> {
|
|
573
|
+
jsType = JsTypes.string
|
|
574
|
+
|
|
575
|
+
formatValue(value: unknown): string {
|
|
576
|
+
return anyToString(value)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
override parse(val: unknown): any {
|
|
580
|
+
if (val === null) return ErrorValueTypes.NullButShouldBeString
|
|
581
|
+
if (val === undefined) return ErrorValueTypes.UndefinedButShouldBeString
|
|
582
|
+
return String(val) || ""
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
class SeriesAnnotationColumn extends StringColumn {}
|
|
587
|
+
class CategoricalColumn extends StringColumn {}
|
|
588
|
+
|
|
589
|
+
class OrdinalColumn extends CategoricalColumn {
|
|
590
|
+
@imemo get allowedValuesSorted(): string[] | undefined {
|
|
591
|
+
return this.def.sort
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
@imemo override get sortedUniqNonEmptyStringVals(): string[] {
|
|
595
|
+
return this.allowedValuesSorted
|
|
596
|
+
? this.allowedValuesSorted
|
|
597
|
+
: super.sortedUniqNonEmptyStringVals
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
class RegionColumn extends OrdinalColumn {}
|
|
602
|
+
class ContinentColumn extends RegionColumn {}
|
|
603
|
+
class ColorColumn extends CategoricalColumn {}
|
|
604
|
+
|
|
605
|
+
class BooleanColumn extends AbstractCoreColumn<boolean> {
|
|
606
|
+
jsType = JsTypes.boolean
|
|
607
|
+
|
|
608
|
+
formatValue(value: unknown): "true" | "false" {
|
|
609
|
+
return value ? "true" : "false"
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
override parse(val: unknown): boolean {
|
|
613
|
+
return !!val
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
abstract class AbstractColumnWithNumberFormatting<
|
|
618
|
+
T extends PrimitiveType,
|
|
619
|
+
> extends AbstractCoreColumn<T> {
|
|
620
|
+
jsType = JsTypes.number
|
|
621
|
+
|
|
622
|
+
formatValue(value: unknown, options?: TickFormattingOptions): string {
|
|
623
|
+
if (_.isNumber(value)) {
|
|
624
|
+
return formatValue(value, {
|
|
625
|
+
roundingMode: this.roundingMode,
|
|
626
|
+
numDecimalPlaces: this.numDecimalPlaces,
|
|
627
|
+
numSignificantFigures: this.numSignificantFigures,
|
|
628
|
+
...options,
|
|
629
|
+
})
|
|
630
|
+
}
|
|
631
|
+
return ""
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
override formatValueShortWithAbbreviations(
|
|
635
|
+
value: unknown,
|
|
636
|
+
options?: TickFormattingOptions
|
|
637
|
+
): string {
|
|
638
|
+
return super.formatValueShortWithAbbreviations(value, {
|
|
639
|
+
numberAbbreviation: "short",
|
|
640
|
+
// only include a unit if it's very short (e.g. %, $ or £)
|
|
641
|
+
...omitUndefinedValues({
|
|
642
|
+
unit:
|
|
643
|
+
this.shortUnit !== undefined &&
|
|
644
|
+
checkIsVeryShortUnit(this.shortUnit)
|
|
645
|
+
? this.shortUnit
|
|
646
|
+
: undefined,
|
|
647
|
+
}),
|
|
648
|
+
...options,
|
|
649
|
+
})
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
override formatValueShort(
|
|
653
|
+
value: unknown,
|
|
654
|
+
options?: TickFormattingOptions
|
|
655
|
+
): string {
|
|
656
|
+
return super.formatValueShort(value, {
|
|
657
|
+
...omitUndefinedValues({
|
|
658
|
+
unit: this.shortUnit,
|
|
659
|
+
}),
|
|
660
|
+
...options,
|
|
661
|
+
})
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
override formatValueLong(
|
|
665
|
+
value: unknown,
|
|
666
|
+
options?: TickFormattingOptions
|
|
667
|
+
): string {
|
|
668
|
+
return super.formatValueLong(value, {
|
|
669
|
+
...omitUndefinedValues({
|
|
670
|
+
unit: this.unit,
|
|
671
|
+
}),
|
|
672
|
+
...options,
|
|
673
|
+
})
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
@imemo override get isAllIntegers(): boolean {
|
|
677
|
+
return this.values.every(
|
|
678
|
+
(val) => typeof val === "number" && val % 1 === 0
|
|
679
|
+
)
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* We strive to have clearly typed variables in the future, but for now our
|
|
685
|
+
* grapher variables are still untyped. Most are number-only, but we also have some
|
|
686
|
+
* string-only, and even some mixed ones.
|
|
687
|
+
* Hence, NumberOrStringColumn is used to store grapher variables.
|
|
688
|
+
* It extends AbstractColumnWithNumberFormatting, which ensures that we have
|
|
689
|
+
* implementations of formatValueShortWithAbbreviations and the like already.
|
|
690
|
+
* -- @marcelgerber, 2022-07-01
|
|
691
|
+
*/
|
|
692
|
+
class NumberOrStringColumn extends AbstractColumnWithNumberFormatting<
|
|
693
|
+
number | string
|
|
694
|
+
> {
|
|
695
|
+
override formatValue(
|
|
696
|
+
value: unknown,
|
|
697
|
+
options?: TickFormattingOptions
|
|
698
|
+
): string {
|
|
699
|
+
if (_.isNumber(value)) {
|
|
700
|
+
return super.formatValue(value, options)
|
|
701
|
+
}
|
|
702
|
+
return anyToString(value)
|
|
703
|
+
}
|
|
704
|
+
override parse(val: unknown): number | string | ErrorValue {
|
|
705
|
+
if (val === null) return ErrorValueTypes.NullButShouldBeNumber
|
|
706
|
+
if (val === undefined) return ErrorValueTypes.UndefinedButShouldBeNumber
|
|
707
|
+
if (Number.isNaN(val)) return ErrorValueTypes.NaNButShouldBeNumber
|
|
708
|
+
|
|
709
|
+
const valAsString = String(val)
|
|
710
|
+
const num = parseFloat(valAsString)
|
|
711
|
+
if (Number.isNaN(num)) return valAsString // return string value
|
|
712
|
+
|
|
713
|
+
return num
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
abstract class AbstractNumericColumn extends AbstractColumnWithNumberFormatting<number> {
|
|
718
|
+
override parse(val: unknown): number | ErrorValue {
|
|
719
|
+
if (val === null) return ErrorValueTypes.NullButShouldBeNumber
|
|
720
|
+
if (val === undefined) return ErrorValueTypes.UndefinedButShouldBeNumber
|
|
721
|
+
if (val === "") return ErrorValueTypes.BlankButShouldBeNumber
|
|
722
|
+
if (isNaN(Number(val))) return ErrorValueTypes.NaNButShouldBeNumber
|
|
723
|
+
|
|
724
|
+
const res = this._parse(val)
|
|
725
|
+
if (isNaN(res))
|
|
726
|
+
return ErrorValueTypes.NotAParseableNumberButShouldBeNumber
|
|
727
|
+
|
|
728
|
+
return res
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
protected _parse(val: unknown): number {
|
|
732
|
+
return parseFloat(String(val))
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
class NumericColumn extends AbstractNumericColumn {}
|
|
737
|
+
class NumericCategoricalColumn extends AbstractNumericColumn {}
|
|
738
|
+
|
|
739
|
+
class IntegerColumn extends NumericColumn {
|
|
740
|
+
override formatValue(
|
|
741
|
+
value: unknown,
|
|
742
|
+
options?: TickFormattingOptions
|
|
743
|
+
): string {
|
|
744
|
+
return super.formatValue(value, {
|
|
745
|
+
numDecimalPlaces: 0,
|
|
746
|
+
...options,
|
|
747
|
+
})
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
protected override _parse(val: unknown): number {
|
|
751
|
+
return parseInt(String(val))
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
class CurrencyColumn extends NumericColumn {
|
|
756
|
+
override formatValue(
|
|
757
|
+
value: unknown,
|
|
758
|
+
options?: TickFormattingOptions
|
|
759
|
+
): string {
|
|
760
|
+
return super.formatValue(value, {
|
|
761
|
+
roundingMode: OwidVariableRoundingMode.decimalPlaces,
|
|
762
|
+
numDecimalPlaces: 0,
|
|
763
|
+
unit: this.shortUnit,
|
|
764
|
+
...options,
|
|
765
|
+
})
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
@imemo override get shortUnit(): string {
|
|
769
|
+
return "$"
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Expects 50% to be 50
|
|
774
|
+
class PercentageColumn extends NumericColumn {
|
|
775
|
+
override formatValue(
|
|
776
|
+
value: number,
|
|
777
|
+
options?: TickFormattingOptions
|
|
778
|
+
): string {
|
|
779
|
+
return super.formatValue(value, {
|
|
780
|
+
unit: this.shortUnit,
|
|
781
|
+
numDecimalPlaces: 1,
|
|
782
|
+
...options,
|
|
783
|
+
})
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
@imemo override get shortUnit(): string {
|
|
787
|
+
return "%"
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Same as %, but indicates it's part of a group of columns that add up to 100%.
|
|
792
|
+
// Might not need this.
|
|
793
|
+
class RelativePercentageColumn extends PercentageColumn {}
|
|
794
|
+
|
|
795
|
+
class PercentChangeOverTimeColumn extends PercentageColumn {
|
|
796
|
+
override formatValue(
|
|
797
|
+
value: number,
|
|
798
|
+
options?: TickFormattingOptions
|
|
799
|
+
): string {
|
|
800
|
+
return super.formatValue(value, {
|
|
801
|
+
showPlus: true,
|
|
802
|
+
...options,
|
|
803
|
+
})
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
class DecimalPercentageColumn extends PercentageColumn {}
|
|
808
|
+
class RatioColumn extends NumericColumn {}
|
|
809
|
+
|
|
810
|
+
// todo: remove. should not be in coretable
|
|
811
|
+
class EntityIdColumn extends NumericCategoricalColumn {}
|
|
812
|
+
class EntityCodeColumn extends CategoricalColumn {}
|
|
813
|
+
class EntityNameColumn extends CategoricalColumn {}
|
|
814
|
+
|
|
815
|
+
// todo: cleanup time columns. current schema is a little incorrect.
|
|
816
|
+
export abstract class TimeColumn extends AbstractCoreColumn<number> {
|
|
817
|
+
jsType = JsTypes.number
|
|
818
|
+
|
|
819
|
+
abstract preposition: string
|
|
820
|
+
|
|
821
|
+
@imemo override get displayName(): string {
|
|
822
|
+
return _.capitalize(this.name)
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
override formatTime(time: number): string {
|
|
826
|
+
return this.formatValue(time)
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
override parse(val: unknown): number | ErrorValue {
|
|
830
|
+
return parseInt(String(val))
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
class YearColumn extends TimeColumn {
|
|
835
|
+
preposition = "in"
|
|
836
|
+
|
|
837
|
+
formatValue(value: number): string {
|
|
838
|
+
// Include BCE
|
|
839
|
+
return formatYear(value)
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
class DayColumn extends TimeColumn {
|
|
844
|
+
preposition = "on"
|
|
845
|
+
|
|
846
|
+
// We cache these values because running `formatDay` thousands of times takes some time.
|
|
847
|
+
static formatValueCache = new Map<number, string>()
|
|
848
|
+
formatValue(value: number): string {
|
|
849
|
+
if (!DayColumn.formatValueCache.has(value)) {
|
|
850
|
+
const formatted = formatDay(value)
|
|
851
|
+
DayColumn.formatValueCache.set(value, formatted)
|
|
852
|
+
return formatted
|
|
853
|
+
}
|
|
854
|
+
return DayColumn.formatValueCache.get(value)!
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
static formatValueForMobileCache = new Map<number, string>()
|
|
858
|
+
override formatValueForMobile(value: number): string {
|
|
859
|
+
if (!DayColumn.formatValueForMobileCache.has(value)) {
|
|
860
|
+
const formatted = formatDay(value, { format: "MMM D, 'YY" })
|
|
861
|
+
DayColumn.formatValueForMobileCache.set(value, formatted)
|
|
862
|
+
return formatted
|
|
863
|
+
}
|
|
864
|
+
return DayColumn.formatValueForMobileCache.get(value)!
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
static formatForCsvCache = new Map<number, string>()
|
|
868
|
+
override formatForCsv(value: number): string {
|
|
869
|
+
if (!DayColumn.formatForCsvCache.has(value)) {
|
|
870
|
+
const formatted = formatDay(value, { format: "YYYY-MM-DD" })
|
|
871
|
+
DayColumn.formatForCsvCache.set(value, formatted)
|
|
872
|
+
return formatted
|
|
873
|
+
}
|
|
874
|
+
return DayColumn.formatForCsvCache.get(value)!
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const dateToTimeCache = new Map<string, Time>() // Cache for performance
|
|
879
|
+
class DateColumn extends DayColumn {
|
|
880
|
+
override parse(val: unknown): number {
|
|
881
|
+
// skip parsing if a date is a number, it's already been parsed
|
|
882
|
+
if (typeof val === "number") return val
|
|
883
|
+
const valAsString = String(val)
|
|
884
|
+
if (!dateToTimeCache.has(valAsString))
|
|
885
|
+
dateToTimeCache.set(
|
|
886
|
+
valAsString,
|
|
887
|
+
dateDiffInDays(
|
|
888
|
+
dayjs.utc(valAsString).toDate(),
|
|
889
|
+
dayjs.utc("2020-01-21").toDate()
|
|
890
|
+
)
|
|
891
|
+
)
|
|
892
|
+
return dateToTimeCache.get(valAsString)!
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
class QuarterColumn extends TimeColumn {
|
|
897
|
+
preposition = "in"
|
|
898
|
+
|
|
899
|
+
private static regEx = /^([+-]?\d+)-Q([1-4])$/
|
|
900
|
+
|
|
901
|
+
override parse(val: unknown): number | ErrorValue {
|
|
902
|
+
// skip parsing if a date is a number, it's already been parsed
|
|
903
|
+
if (typeof val === "number") return val
|
|
904
|
+
if (typeof val === "string") {
|
|
905
|
+
const match = val.match(QuarterColumn.regEx)
|
|
906
|
+
if (match) {
|
|
907
|
+
const [, year, quarter] = match
|
|
908
|
+
return parseInt(year) * 4 + (parseInt(quarter) - 1)
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return ErrorValueTypes.InvalidQuarterValue
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
private static numToQuarter(value: number): number[] {
|
|
915
|
+
const year = Math.floor(value / 4)
|
|
916
|
+
const quarter = (Math.abs(value) % 4) + 1
|
|
917
|
+
return [year, quarter]
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
formatValue(value: number): string {
|
|
921
|
+
const [year, quarter] = QuarterColumn.numToQuarter(value)
|
|
922
|
+
return `Q${quarter}/${year}`
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
override formatForCsv(value: number): string {
|
|
926
|
+
const [year, quarter] = QuarterColumn.numToQuarter(value)
|
|
927
|
+
return `${year}-Q${quarter}`
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
class PopulationColumn extends IntegerColumn {}
|
|
932
|
+
class PopulationDensityColumn extends NumericColumn {}
|
|
933
|
+
|
|
934
|
+
class AgeColumn extends NumericColumn {}
|
|
935
|
+
|
|
936
|
+
export const ColumnTypeMap = {
|
|
937
|
+
String: StringColumn,
|
|
938
|
+
SeriesAnnotation: SeriesAnnotationColumn,
|
|
939
|
+
Categorical: CategoricalColumn,
|
|
940
|
+
Ordinal: OrdinalColumn,
|
|
941
|
+
Region: RegionColumn,
|
|
942
|
+
Continent: ContinentColumn,
|
|
943
|
+
NumberOrString: NumberOrStringColumn,
|
|
944
|
+
Numeric: NumericColumn,
|
|
945
|
+
Day: DayColumn,
|
|
946
|
+
Date: DateColumn,
|
|
947
|
+
Year: YearColumn,
|
|
948
|
+
Quarter: QuarterColumn,
|
|
949
|
+
Time: TimeColumn,
|
|
950
|
+
Boolean: BooleanColumn,
|
|
951
|
+
Currency: CurrencyColumn,
|
|
952
|
+
Percentage: PercentageColumn,
|
|
953
|
+
RelativePercentage: RelativePercentageColumn,
|
|
954
|
+
Integer: IntegerColumn,
|
|
955
|
+
DecimalPercentage: DecimalPercentageColumn,
|
|
956
|
+
PercentChangeOverTime: PercentChangeOverTimeColumn,
|
|
957
|
+
Ratio: RatioColumn,
|
|
958
|
+
Color: ColorColumn,
|
|
959
|
+
EntityCode: EntityCodeColumn,
|
|
960
|
+
EntityId: EntityIdColumn,
|
|
961
|
+
EntityName: EntityNameColumn,
|
|
962
|
+
Population: PopulationColumn,
|
|
963
|
+
PopulationDensity: PopulationDensityColumn,
|
|
964
|
+
Age: AgeColumn,
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Keep this in. This is used as a compile-time check that ColumnTypeMap covers all
|
|
968
|
+
// column names defined in ColumnTypeNames, since that is quite difficult to ensure
|
|
969
|
+
// otherwise without losing inferred type information.
|
|
970
|
+
|
|
971
|
+
const _ColumnTypeMap: {
|
|
972
|
+
[key in ColumnTypeNames]: unknown
|
|
973
|
+
} = ColumnTypeMap
|