@buildcanada/charts 0.1.1 → 0.2.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/package.json +2 -2
- package/src/components/Button/Button.scss +17 -17
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/MarkdownTextWrap/MarkdownTextWrap.tsx +1 -1
- package/src/components/index.ts +1 -1
- package/src/components/stubs/DataCitation.tsx +1 -1
- package/src/components/stubs/IndicatorKeyData.tsx +1 -1
- package/src/components/stubs/IndicatorProcessing.tsx +1 -1
- package/src/components/stubs/IndicatorSources.tsx +1 -1
- package/src/components/styles/colors.scss +1 -1
- package/src/components/styles/mixins.scss +5 -5
- package/src/core-table/{OwidTable.ts → ChartsTable.ts} +31 -31
- package/src/core-table/CoreTable.ts +12 -12
- package/src/core-table/CoreTableColumns.ts +24 -24
- package/src/core-table/CoreTableUtils.ts +7 -7
- package/src/core-table/{OwidTableSynthesizers.ts → TableSynthesizers.ts} +24 -24
- package/src/core-table/{OwidTableUtil.ts → TableUtil.ts} +5 -5
- package/src/core-table/index.ts +3 -3
- package/src/explorer/ColumnGrammar.ts +1 -1
- package/src/explorer/Explorer.sample.ts +7 -7
- package/src/explorer/Explorer.scss +1 -1
- package/src/explorer/Explorer.tsx +23 -23
- package/src/explorer/ExplorerConstants.ts +2 -2
- package/src/explorer/ExplorerGrammar.ts +3 -3
- package/src/explorer/ExplorerProgram.ts +21 -18
- package/src/explorer/ExplorerUtils.ts +1 -1
- package/src/explorer/gridLang/readme.md +1 -1
- package/src/grapher/axis/Axis.ts +3 -3
- package/src/grapher/barCharts/DiscreteBarChart.tsx +2 -2
- package/src/grapher/barCharts/DiscreteBarChartState.ts +8 -8
- package/src/grapher/captionedChart/Logos.tsx +11 -13
- package/src/grapher/captionedChart/LogosSVG.tsx +2 -2
- package/src/grapher/chart/ChartAreaContent.tsx +1 -1
- package/src/grapher/chart/ChartDimension.ts +15 -15
- package/src/grapher/chart/ChartInterface.ts +6 -6
- package/src/grapher/chart/ChartManager.ts +3 -3
- package/src/grapher/chart/ChartUtils.tsx +3 -3
- package/src/grapher/color/ColorConstants.ts +2 -2
- package/src/grapher/color/ColorScale.ts +4 -4
- package/src/grapher/color/ColorSchemes.ts +26 -26
- package/src/grapher/color/CustomSchemes.ts +227 -227
- package/src/grapher/controls/DataTableFilterDropdown.tsx +2 -2
- package/src/grapher/controls/MapZoomDropdown.tsx +3 -3
- package/src/grapher/controls/ShareMenu.tsx +1 -1
- package/src/grapher/controls/entityPicker/EntityPicker.tsx +8 -8
- package/src/grapher/controls/entityPicker/EntityPickerConstants.ts +3 -3
- package/src/grapher/controls/globalEntitySelector/GlobalEntitySelector.tsx +1 -1
- package/src/grapher/core/EntitiesByRegionType.ts +4 -4
- package/src/grapher/core/EntityUrlBuilder.ts +2 -2
- package/src/grapher/core/FetchingGrapher.tsx +4 -4
- package/src/grapher/core/Grapher.tsx +10 -10
- package/src/grapher/core/GrapherState.tsx +46 -46
- package/src/grapher/core/GrapherUseHelpers.tsx +4 -4
- package/src/grapher/core/{LegacyToOwidTable.ts → LegacyToChartsTable.ts} +100 -100
- package/src/grapher/core/loadGrapherTableHelpers.ts +13 -13
- package/src/grapher/core/loadVariable.ts +5 -5
- package/src/grapher/dataTable/DataTable.sample.ts +12 -12
- package/src/grapher/dataTable/DataTable.tsx +22 -22
- package/src/grapher/dataTable/DataTableConstants.ts +9 -9
- package/src/grapher/entitySelector/EntitySelector.tsx +12 -12
- package/src/grapher/facet/FacetChart.tsx +4 -4
- package/src/grapher/facet/FacetMap.tsx +6 -6
- package/src/grapher/footer/Footer.tsx +4 -4
- package/src/grapher/footer/FooterManager.ts +2 -2
- package/src/grapher/header/Header.tsx +5 -5
- package/src/grapher/header/HeaderManager.ts +1 -1
- package/src/grapher/index.ts +8 -8
- package/src/grapher/lineCharts/LineChartHelpers.ts +3 -3
- package/src/grapher/lineCharts/LineChartState.ts +9 -9
- package/src/grapher/mapCharts/ChoroplethGlobe.tsx +1 -1
- package/src/grapher/mapCharts/GlobeController.ts +9 -9
- package/src/grapher/mapCharts/MapChartState.ts +16 -16
- package/src/grapher/mapCharts/MapSparkline.tsx +5 -5
- package/src/grapher/mapCharts/MapTooltip.tsx +13 -13
- package/src/grapher/modal/DownloadModal.scss +3 -3
- package/src/grapher/modal/DownloadModal.tsx +24 -29
- package/src/grapher/modal/SourcesDescriptions.scss +1 -1
- package/src/grapher/modal/SourcesKeyDataTable.tsx +2 -2
- package/src/grapher/modal/SourcesModal.tsx +15 -15
- package/src/grapher/scatterCharts/ScatterPlotChart.tsx +2 -2
- package/src/grapher/scatterCharts/ScatterPlotChartConstants.ts +2 -2
- package/src/grapher/scatterCharts/ScatterPlotChartState.ts +8 -8
- package/src/grapher/scatterCharts/ScatterSizeLegend.tsx +2 -2
- package/src/grapher/scatterCharts/ScatterUtils.ts +2 -2
- package/src/grapher/schema/grapher-schema.009.yaml +18 -18
- package/src/grapher/schema/migrations/migrations.ts +4 -4
- package/src/grapher/selection/MapSelectionArray.ts +1 -1
- package/src/grapher/selection/readme.md +1 -1
- package/src/grapher/slopeCharts/SlopeChartConstants.ts +3 -3
- package/src/grapher/slopeCharts/SlopeChartState.ts +10 -10
- package/src/grapher/stackedCharts/AbstractStackedChartState.ts +8 -8
- package/src/grapher/stackedCharts/MarimekkoChart.tsx +5 -5
- package/src/grapher/stackedCharts/MarimekkoChartConstants.ts +2 -2
- package/src/grapher/stackedCharts/MarimekkoChartState.ts +12 -12
- package/src/grapher/stackedCharts/StackedBarChartState.ts +1 -1
- package/src/grapher/stackedCharts/StackedConstants.ts +2 -2
- package/src/grapher/stackedCharts/StackedDiscreteBarChartState.ts +12 -12
- package/src/grapher/stackedCharts/StackedDiscreteBars.tsx +2 -2
- package/src/grapher/testData/{OwidTestData.sample.ts → TestData.sample.ts} +7 -7
- package/src/grapher/testData/{OwidTestData.ts → TestData.ts} +5 -5
- package/src/index.ts +7 -7
- package/src/types/{OwidOrigin.ts → Origin.ts} +3 -3
- package/src/types/{OwidSource.ts → Source.ts} +1 -1
- package/src/types/Variable.ts +133 -0
- package/src/types/{OwidVariableDisplayConfigInterface.ts → VariableDisplayConfigInterface.ts} +11 -11
- package/src/types/domainTypes/ContentGraph.ts +2 -2
- package/src/types/domainTypes/CoreTableTypes.ts +29 -29
- package/src/types/domainTypes/Posts.ts +2 -2
- package/src/types/domainTypes/Search.ts +6 -6
- package/src/types/domainTypes/Various.ts +1 -1
- package/src/types/gdocTypes/Gdoc.ts +42 -42
- package/src/types/grapherTypes/GrapherTypes.ts +21 -21
- package/src/types/index.ts +50 -50
- package/src/utils/MultiDimDataPageConfig.ts +1 -1
- package/src/utils/Util.ts +61 -55
- package/src/utils/{OwidVariable.ts → Variable.ts} +15 -15
- package/src/utils/formatValue.ts +12 -12
- package/src/utils/image.ts +12 -12
- package/src/utils/index.ts +5 -5
- package/src/utils/metadataHelpers.ts +19 -19
- package/src/utils/regions.ts +9 -9
- package/src/types/OwidVariable.ts +0 -133
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
ColumnTypeNames,
|
|
13
13
|
CoreColumnDef,
|
|
14
14
|
ErrorValue,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
EntityCodeColumnDef,
|
|
16
|
+
EntityIdColumnDef,
|
|
17
|
+
EntityNameColumnDef,
|
|
18
|
+
ChartsTableSlugs,
|
|
19
19
|
} from "../types/index.js"
|
|
20
20
|
import { ErrorValueTypes, DroppedForTesting } from "./ErrorValues.js"
|
|
21
21
|
|
|
@@ -135,9 +135,9 @@ export const guessColumnDefFromSlugAndRow = (
|
|
|
135
135
|
name: "Year",
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
if (slug ===
|
|
139
|
-
if (slug ===
|
|
140
|
-
if (slug ===
|
|
138
|
+
if (slug === ChartsTableSlugs.entityName) return EntityNameColumnDef
|
|
139
|
+
if (slug === ChartsTableSlugs.entityCode) return EntityCodeColumnDef
|
|
140
|
+
if (slug === ChartsTableSlugs.entityId) return EntityIdColumnDef
|
|
141
141
|
|
|
142
142
|
if (slug === "date")
|
|
143
143
|
return {
|
|
@@ -3,28 +3,28 @@ import {
|
|
|
3
3
|
sampleFrom,
|
|
4
4
|
getRandomNumberGenerator,
|
|
5
5
|
countries,
|
|
6
|
-
|
|
6
|
+
VariableDisplayConfigInterface,
|
|
7
7
|
ColumnSlug,
|
|
8
8
|
} from "../utils/index.js"
|
|
9
9
|
import {
|
|
10
10
|
TimeRange,
|
|
11
11
|
ColumnTypeNames,
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
ColumnDef,
|
|
13
|
+
ChartsTableSlugs,
|
|
14
14
|
} from "../types/index.js"
|
|
15
|
-
import {
|
|
15
|
+
import { ChartsTable } from "./ChartsTable.js"
|
|
16
16
|
|
|
17
17
|
interface SynthOptions {
|
|
18
18
|
entityCount: number
|
|
19
19
|
entityNames: string[]
|
|
20
20
|
timeRange: TimeRange
|
|
21
|
-
columnDefs:
|
|
21
|
+
columnDefs: ColumnDef[]
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const SynthesizeChartsTable = (
|
|
25
25
|
options?: Partial<SynthOptions>,
|
|
26
26
|
seed = Date.now()
|
|
27
|
-
):
|
|
27
|
+
): ChartsTable => {
|
|
28
28
|
const finalOptions: SynthOptions = {
|
|
29
29
|
entityNames: [],
|
|
30
30
|
entityCount: 2,
|
|
@@ -35,10 +35,10 @@ const SynthesizeOwidTable = (
|
|
|
35
35
|
const { entityCount, columnDefs, timeRange, entityNames } = finalOptions
|
|
36
36
|
const colSlugs = (
|
|
37
37
|
[
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
ChartsTableSlugs.entityName,
|
|
39
|
+
ChartsTableSlugs.entityCode,
|
|
40
|
+
ChartsTableSlugs.entityId,
|
|
41
|
+
ChartsTableSlugs.year,
|
|
42
42
|
] as ColumnSlug[]
|
|
43
43
|
).concat(columnDefs.map((col) => col.slug!))
|
|
44
44
|
|
|
@@ -67,7 +67,7 @@ const SynthesizeOwidTable = (
|
|
|
67
67
|
.join("\n")
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
return new
|
|
70
|
+
return new ChartsTable(
|
|
71
71
|
`${colSlugs.join(",")}\n${rows.join("\n")}`,
|
|
72
72
|
columnDefs
|
|
73
73
|
)
|
|
@@ -76,8 +76,8 @@ const SynthesizeOwidTable = (
|
|
|
76
76
|
export const SynthesizeNonCountryTable = (
|
|
77
77
|
options?: Partial<SynthOptions>,
|
|
78
78
|
seed = Date.now()
|
|
79
|
-
):
|
|
80
|
-
|
|
79
|
+
): ChartsTable =>
|
|
80
|
+
SynthesizeChartsTable(
|
|
81
81
|
{
|
|
82
82
|
entityNames: ["Fire", "Earthquake", "Tornado"],
|
|
83
83
|
columnDefs: [
|
|
@@ -110,9 +110,9 @@ export enum SampleColumnSlugs {
|
|
|
110
110
|
export const SynthesizeGDPTable = (
|
|
111
111
|
options?: Partial<SynthOptions>,
|
|
112
112
|
seed = Date.now(),
|
|
113
|
-
display?:
|
|
114
|
-
):
|
|
115
|
-
|
|
113
|
+
display?: VariableDisplayConfigInterface
|
|
114
|
+
): ChartsTable =>
|
|
115
|
+
SynthesizeChartsTable(
|
|
116
116
|
{
|
|
117
117
|
columnDefs: [
|
|
118
118
|
{
|
|
@@ -173,8 +173,8 @@ const SynthSource = (
|
|
|
173
173
|
export const SynthesizeFruitTable = (
|
|
174
174
|
options?: Partial<SynthOptions>,
|
|
175
175
|
seed = Date.now()
|
|
176
|
-
):
|
|
177
|
-
|
|
176
|
+
): ChartsTable =>
|
|
177
|
+
SynthesizeChartsTable(
|
|
178
178
|
{
|
|
179
179
|
columnDefs: [
|
|
180
180
|
{
|
|
@@ -209,7 +209,7 @@ export const SynthesizeFruitTableWithNonPositives = (
|
|
|
209
209
|
options?: Partial<SynthOptions>,
|
|
210
210
|
howManyNonPositives = 20,
|
|
211
211
|
seed = Date.now()
|
|
212
|
-
):
|
|
212
|
+
): ChartsTable => {
|
|
213
213
|
const rand = getRandomNumberGenerator(-1000, 0)
|
|
214
214
|
return SynthesizeFruitTable(options, seed).replaceRandomCells(
|
|
215
215
|
howManyNonPositives,
|
|
@@ -225,7 +225,7 @@ export const SynthesizeFruitTableWithStringValues = (
|
|
|
225
225
|
options?: Partial<SynthOptions>,
|
|
226
226
|
howMany = 20,
|
|
227
227
|
seed = Date.now()
|
|
228
|
-
):
|
|
228
|
+
): ChartsTable => {
|
|
229
229
|
return SynthesizeFruitTable(options, seed).replaceRandomCells(
|
|
230
230
|
howMany,
|
|
231
231
|
[SampleColumnSlugs.Fruit, SampleColumnSlugs.Vegetables],
|
|
@@ -237,9 +237,9 @@ export const SynthesizeFruitTableWithStringValues = (
|
|
|
237
237
|
export const SynthesizeProjectedPopulationTable = (
|
|
238
238
|
options?: Partial<SynthOptions>,
|
|
239
239
|
seed = Date.now(),
|
|
240
|
-
display?:
|
|
241
|
-
):
|
|
242
|
-
|
|
240
|
+
display?: VariableDisplayConfigInterface
|
|
241
|
+
): ChartsTable =>
|
|
242
|
+
SynthesizeChartsTable(
|
|
243
243
|
{
|
|
244
244
|
columnDefs: [
|
|
245
245
|
{
|
|
@@ -2,15 +2,15 @@ import {
|
|
|
2
2
|
ColumnSlug,
|
|
3
3
|
ColumnTypeNames,
|
|
4
4
|
CoreColumnDef,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
ColumnDef,
|
|
6
|
+
ChartsTableSlugs,
|
|
7
7
|
} from "../types/index.js"
|
|
8
8
|
import { CoreTable } from "./CoreTable.js"
|
|
9
9
|
|
|
10
10
|
export function timeColumnSlugFromColumnDef(
|
|
11
|
-
def:
|
|
12
|
-
):
|
|
13
|
-
return def.isDailyMeasurement ?
|
|
11
|
+
def: ColumnDef
|
|
12
|
+
): ChartsTableSlugs.day | ChartsTableSlugs.year {
|
|
13
|
+
return def.isDailyMeasurement ? ChartsTableSlugs.day : ChartsTableSlugs.year
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function makeOriginalTimeSlugFromColumnSlug(slug: ColumnSlug): string {
|
package/src/core-table/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export {
|
|
|
7
7
|
SynthesizeFruitTableWithNonPositives,
|
|
8
8
|
SynthesizeFruitTableWithStringValues,
|
|
9
9
|
SynthesizeProjectedPopulationTable,
|
|
10
|
-
} from "./
|
|
10
|
+
} from "./TableSynthesizers.js"
|
|
11
11
|
|
|
12
12
|
export {
|
|
13
13
|
type CoreColumn,
|
|
@@ -17,7 +17,7 @@ export {
|
|
|
17
17
|
TimeColumn,
|
|
18
18
|
} from "./CoreTableColumns.js"
|
|
19
19
|
|
|
20
|
-
export {
|
|
20
|
+
export { ChartsTable, BlankChartsTable } from "./ChartsTable.js"
|
|
21
21
|
|
|
22
22
|
export {
|
|
23
23
|
DroppedForTesting,
|
|
@@ -71,7 +71,7 @@ export {
|
|
|
71
71
|
makeOriginalValueSlugFromColumnSlug,
|
|
72
72
|
getOriginalTimeColumnSlug,
|
|
73
73
|
toPercentageColumnDef,
|
|
74
|
-
} from "./
|
|
74
|
+
} from "./TableUtil.js"
|
|
75
75
|
|
|
76
76
|
export {
|
|
77
77
|
insertMissingValuePlaceholders,
|
|
@@ -114,7 +114,7 @@ export const ColumnGrammar: Grammar<ColumnCellDef> = {
|
|
|
114
114
|
...StringCellDef,
|
|
115
115
|
keyword: "dataPublishedBy",
|
|
116
116
|
description:
|
|
117
|
-
"For academic papers this should be a complete reference. For institutional projects, detail the project or report. For data
|
|
117
|
+
"For academic papers this should be a complete reference. For institutional projects, detail the project or report. For data modified extensively, list the organization as the publishers and provide the name of the person in charge of the calculation.",
|
|
118
118
|
},
|
|
119
119
|
dataPublisherSource: {
|
|
120
120
|
...StringCellDef,
|
|
@@ -2,13 +2,13 @@ import { DimensionProperty } from "../utils/index.js"
|
|
|
2
2
|
import { GRAPHER_TAB_CONFIG_OPTIONS } from "../types/index.js"
|
|
3
3
|
import {
|
|
4
4
|
GrapherProgrammaticInterface,
|
|
5
|
-
|
|
5
|
+
legacyToChartsTableAndDimensionsWithMandatorySlug,
|
|
6
6
|
} from "../grapher/index.js"
|
|
7
7
|
import { Explorer, ExplorerProps } from "./Explorer.js"
|
|
8
8
|
|
|
9
9
|
const SampleExplorerOfGraphersProgram = `explorerTitle CO₂ Data Explorer
|
|
10
10
|
isPublished false
|
|
11
|
-
explorerSubtitle Download the complete
|
|
11
|
+
explorerSubtitle Download the complete CO₂ and GHG Emissions Dataset.
|
|
12
12
|
subNavId co2
|
|
13
13
|
time earliest..latest
|
|
14
14
|
selection China United States India United Kingdom World
|
|
@@ -46,7 +46,7 @@ graphers
|
|
|
46
46
|
4244 Nitrous oxide Production-based Per capita false`
|
|
47
47
|
|
|
48
48
|
// Generate realistic CO2 per capita emissions data (tonnes per person)
|
|
49
|
-
// Based on approximate real-world trends from
|
|
49
|
+
// Based on approximate real-world trends from CO2 data
|
|
50
50
|
function generateCO2PerCapitaData() {
|
|
51
51
|
const startYear = 1990
|
|
52
52
|
const endYear = 2024
|
|
@@ -93,7 +93,7 @@ function generateCO2PerCapitaData() {
|
|
|
93
93
|
{
|
|
94
94
|
id: 5,
|
|
95
95
|
name: "World",
|
|
96
|
-
code: "
|
|
96
|
+
code: "WRL",
|
|
97
97
|
// Global average rose from ~4 to ~4.7 tonnes
|
|
98
98
|
baseValue: 4.0,
|
|
99
99
|
trend: (year: number) =>
|
|
@@ -140,7 +140,7 @@ function generateCO2PerCapitaData() {
|
|
|
140
140
|
export const SampleExplorerOfGraphers = (props?: Partial<ExplorerProps>) => {
|
|
141
141
|
const title = "CO₂ emissions per capita"
|
|
142
142
|
const co2Data = generateCO2PerCapitaData()
|
|
143
|
-
const
|
|
143
|
+
const dataset = new Map([[142609, co2Data]])
|
|
144
144
|
const dimensions = [
|
|
145
145
|
{
|
|
146
146
|
variableId: 142609,
|
|
@@ -153,8 +153,8 @@ export const SampleExplorerOfGraphers = (props?: Partial<ExplorerProps>) => {
|
|
|
153
153
|
dimensions,
|
|
154
154
|
tab: GRAPHER_TAB_CONFIG_OPTIONS.chart,
|
|
155
155
|
}
|
|
156
|
-
first.table =
|
|
157
|
-
|
|
156
|
+
first.table = legacyToChartsTableAndDimensionsWithMandatorySlug(
|
|
157
|
+
dataset,
|
|
158
158
|
dimensions,
|
|
159
159
|
{}
|
|
160
160
|
)
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ArchiveContext,
|
|
7
7
|
ColumnTypeNames,
|
|
8
8
|
CoreColumnDef,
|
|
9
|
-
|
|
9
|
+
ColumnDef,
|
|
10
10
|
SortOrder,
|
|
11
11
|
TableSlug,
|
|
12
12
|
GrapherInterface,
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
GRAPHER_TAB_QUERY_PARAMS,
|
|
16
16
|
} from "../types/index.js"
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
ChartsTable,
|
|
19
|
+
BlankChartsTable,
|
|
20
20
|
extractPotentialDataSlugsFromTransform,
|
|
21
21
|
} from "../core-table/index.js"
|
|
22
22
|
import {
|
|
@@ -82,7 +82,7 @@ export interface ExplorerProps extends SerializedGridProgram {
|
|
|
82
82
|
grapherConfigs?: GrapherInterface[]
|
|
83
83
|
partialGrapherConfigs?: GrapherInterface[]
|
|
84
84
|
queryStr?: string
|
|
85
|
-
|
|
85
|
+
isEmbeddedInPage?: boolean
|
|
86
86
|
isInStandalonePage?: boolean
|
|
87
87
|
isPreview?: boolean
|
|
88
88
|
canonicalUrl?: string
|
|
@@ -204,7 +204,7 @@ export class Explorer
|
|
|
204
204
|
analytics = new GrapherAnalytics()
|
|
205
205
|
grapherState: GrapherState
|
|
206
206
|
isOnArchivalPage: boolean
|
|
207
|
-
inputTableTransformer = (table:
|
|
207
|
+
inputTableTransformer = (table: ChartsTable) => table
|
|
208
208
|
|
|
209
209
|
constructor(props: ExplorerProps) {
|
|
210
210
|
super(props)
|
|
@@ -240,7 +240,7 @@ export class Explorer
|
|
|
240
240
|
bounds: props.bounds,
|
|
241
241
|
enableKeyboardShortcuts: this.props.isInStandalonePage,
|
|
242
242
|
manager: this,
|
|
243
|
-
|
|
243
|
+
isEmbeddedInPage: this.props.isEmbeddedInPage,
|
|
244
244
|
adminBaseUrl: this.adminBaseUrl,
|
|
245
245
|
canHideExternalControlsInEmbed: true,
|
|
246
246
|
archiveContext: props.archiveContext,
|
|
@@ -272,7 +272,7 @@ export class Explorer
|
|
|
272
272
|
...explorerConstants,
|
|
273
273
|
grapherConfigs,
|
|
274
274
|
partialGrapherConfigs,
|
|
275
|
-
|
|
275
|
+
isEmbeddedInPage: false,
|
|
276
276
|
isInStandalonePage: true,
|
|
277
277
|
archiveContext,
|
|
278
278
|
}
|
|
@@ -535,7 +535,7 @@ export class Explorer
|
|
|
535
535
|
)
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
-
@action.bound private setGrapherTable(table:
|
|
538
|
+
@action.bound private setGrapherTable(table: ChartsTable) {
|
|
539
539
|
this.grapherState.inputTable = this.inputTableTransformer(table)
|
|
540
540
|
}
|
|
541
541
|
|
|
@@ -548,7 +548,7 @@ export class Explorer
|
|
|
548
548
|
return !this.isNarrow
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
-
private futureGrapherTable = new PromiseSwitcher<
|
|
551
|
+
private futureGrapherTable = new PromiseSwitcher<ChartsTable>({
|
|
552
552
|
onResolve: (table) => this.setGrapherTable(table),
|
|
553
553
|
onReject: (error) => this.grapher?.setError(error),
|
|
554
554
|
})
|
|
@@ -570,12 +570,12 @@ export class Explorer
|
|
|
570
570
|
|
|
571
571
|
@computed private get columnDefsWithoutTableSlugByIdOrSlug(): Record<
|
|
572
572
|
number | string,
|
|
573
|
-
|
|
573
|
+
ColumnDef
|
|
574
574
|
> {
|
|
575
575
|
const { columnDefsWithoutTableSlug } = this.explorerProgram
|
|
576
576
|
return _.keyBy(
|
|
577
577
|
columnDefsWithoutTableSlug,
|
|
578
|
-
(def:
|
|
578
|
+
(def: ColumnDef) => def.variableId ?? def.slug
|
|
579
579
|
)
|
|
580
580
|
}
|
|
581
581
|
|
|
@@ -606,7 +606,7 @@ export class Explorer
|
|
|
606
606
|
const baseVariableIdsAndColumnSlugs =
|
|
607
607
|
this.getBaseColumnsForColumnWithTransform(slug)
|
|
608
608
|
const slugsInColumnBlock: string[] = columnDefsWithoutTableSlug
|
|
609
|
-
.filter((def) => !def.
|
|
609
|
+
.filter((def) => !def.variableId)
|
|
610
610
|
.map((def) => def.slug)
|
|
611
611
|
return baseVariableIdsAndColumnSlugs.filter(
|
|
612
612
|
(variableIdOrColumnSlug) =>
|
|
@@ -645,7 +645,7 @@ export class Explorer
|
|
|
645
645
|
|
|
646
646
|
grapherState.setAuthoredVersion(config)
|
|
647
647
|
grapherState.reset()
|
|
648
|
-
grapherState.inputTable =
|
|
648
|
+
grapherState.inputTable = BlankChartsTable()
|
|
649
649
|
grapherState.updateFromObject(config)
|
|
650
650
|
if (!config.table) {
|
|
651
651
|
const loadFn =
|
|
@@ -657,7 +657,7 @@ export class Explorer
|
|
|
657
657
|
archiveContext: this.props.archiveContext,
|
|
658
658
|
noCache: this.props.isPreview,
|
|
659
659
|
loadMetadataOnly: this.props.loadMetadataOnly,
|
|
660
|
-
}).then((
|
|
660
|
+
}).then((dataTable) => (dataTable ? dataTable : BlankChartsTable()))
|
|
661
661
|
// We use the PromiseSwitcher here to make sure that only the last
|
|
662
662
|
// of several user triggered load operations in quick succession
|
|
663
663
|
// will actually set the table.
|
|
@@ -788,7 +788,7 @@ export class Explorer
|
|
|
788
788
|
config.dimensions = dimensions
|
|
789
789
|
if (ySlugs && yVariableIds) config.ySlugs = ySlugs + " " + yVariableIds
|
|
790
790
|
|
|
791
|
-
this.inputTableTransformer = (table:
|
|
791
|
+
this.inputTableTransformer = (table: ChartsTable) => {
|
|
792
792
|
// add transformed (and intermediate) columns to the grapher table
|
|
793
793
|
if (uniqueSlugsInGrapherRow.length) {
|
|
794
794
|
const allColumnSlugs = _.uniq(
|
|
@@ -811,7 +811,7 @@ export class Explorer
|
|
|
811
811
|
}
|
|
812
812
|
|
|
813
813
|
// update column definitions with manually provided properties
|
|
814
|
-
table = table.updateDefs((def:
|
|
814
|
+
table = table.updateDefs((def: ColumnDef) => {
|
|
815
815
|
const manuallyProvidedDef =
|
|
816
816
|
this.columnDefsWithoutTableSlugByIdOrSlug[def.slug] ?? {}
|
|
817
817
|
const mergedDef = { ...def, ...manuallyProvidedDef }
|
|
@@ -836,7 +836,7 @@ export class Explorer
|
|
|
836
836
|
if (dimensions.length === 0) {
|
|
837
837
|
// If dimensions are empty, explicitly set the table to an empty table
|
|
838
838
|
// so we don't end up confusingly showing stale data from a previous chart
|
|
839
|
-
grapherState.inputTable =
|
|
839
|
+
grapherState.inputTable = BlankChartsTable()
|
|
840
840
|
} else {
|
|
841
841
|
const loadFn =
|
|
842
842
|
this.props.loadInputTableForConfig ?? fetchInputTableForConfig
|
|
@@ -847,7 +847,7 @@ export class Explorer
|
|
|
847
847
|
dataApiUrl: this.props.dataApiUrl,
|
|
848
848
|
noCache: this.props.isPreview,
|
|
849
849
|
loadMetadataOnly: this.props.loadMetadataOnly,
|
|
850
|
-
}).then((
|
|
850
|
+
}).then((dataTable) => (dataTable ? dataTable : BlankChartsTable()))
|
|
851
851
|
// We use the PromiseSwitcher here to make sure that only the last
|
|
852
852
|
// of several user triggered load operations in quick succession
|
|
853
853
|
// will actually set the table.
|
|
@@ -880,7 +880,7 @@ export class Explorer
|
|
|
880
880
|
this.grapher?.clearErrors()
|
|
881
881
|
// Set a table immediately. A BlankTable shows a loading animation.
|
|
882
882
|
this.setGrapherTable(
|
|
883
|
-
|
|
883
|
+
BlankChartsTable(tableSlug, `Loading table '${tableSlug}'`)
|
|
884
884
|
)
|
|
885
885
|
// We use the PromiseSwitcher here to make sure that only the last
|
|
886
886
|
// of several user triggered load operations in quick succession
|
|
@@ -1007,7 +1007,7 @@ export class Explorer
|
|
|
1007
1007
|
}
|
|
1008
1008
|
|
|
1009
1009
|
@computed private get showExplorerControls() {
|
|
1010
|
-
if (!this.props.
|
|
1010
|
+
if (!this.props.isEmbeddedInPage && !this.isInIFrame) return true
|
|
1011
1011
|
// Only allow hiding controls on embedded pages
|
|
1012
1012
|
return !(
|
|
1013
1013
|
this.explorerProgram.hideControls ||
|
|
@@ -1120,7 +1120,7 @@ export class Explorer
|
|
|
1120
1120
|
Explorer: true,
|
|
1121
1121
|
"mobile-explorer": this.isNarrow,
|
|
1122
1122
|
HideControls: !showExplorerControls,
|
|
1123
|
-
"is-embed": this.props.
|
|
1123
|
+
"is-embed": this.props.isEmbeddedInPage,
|
|
1124
1124
|
})}
|
|
1125
1125
|
>
|
|
1126
1126
|
{showHeaderElement && this.renderHeaderElement()}
|
|
@@ -1169,10 +1169,10 @@ export class Explorer
|
|
|
1169
1169
|
this.initialQueryParams.pickerMetric
|
|
1170
1170
|
entityPickerSort: SortOrder | undefined = this.initialQueryParams.pickerSort
|
|
1171
1171
|
|
|
1172
|
-
entityPickerTable:
|
|
1172
|
+
entityPickerTable: ChartsTable | undefined = undefined
|
|
1173
1173
|
entityPickerTableIsLoading: boolean = false
|
|
1174
1174
|
|
|
1175
|
-
private futureEntityPickerTable = new PromiseSwitcher<
|
|
1175
|
+
private futureEntityPickerTable = new PromiseSwitcher<ChartsTable>({
|
|
1176
1176
|
onResolve: (table) => {
|
|
1177
1177
|
this.entityPickerTable = table
|
|
1178
1178
|
this.entityPickerTableIsLoading = false
|
|
@@ -74,8 +74,8 @@ export const GetAllExplorersRoute = "allExplorers.json"
|
|
|
74
74
|
|
|
75
75
|
export const GetAllExplorersTagsRoute = "allExplorersTags.json"
|
|
76
76
|
|
|
77
|
-
export const EXPLORERS_ROUTE_FOLDER = "explorers" // Url path:
|
|
78
|
-
export const EXPLORERS_GIT_CMS_FOLDER = "explorers" // Disk path:
|
|
77
|
+
export const EXPLORERS_ROUTE_FOLDER = "explorers" // Url path: /{explorers}
|
|
78
|
+
export const EXPLORERS_GIT_CMS_FOLDER = "explorers" // Disk path: git-content/{explorers}
|
|
79
79
|
export const EXPLORERS_PREVIEW_ROUTE = `${EXPLORERS_ROUTE_FOLDER}/preview`
|
|
80
80
|
|
|
81
81
|
export interface ExplorersRouteResponse {
|
|
@@ -27,8 +27,8 @@ export const ExplorerGrammar: Grammar = {
|
|
|
27
27
|
...UrlCellDef,
|
|
28
28
|
keyword: "table",
|
|
29
29
|
valuePlaceholder: "",
|
|
30
|
-
regex: new RegExp(`(${UrlCellDef.regex?.source ?? ""}|^[\\w -()]+$)`), // URL or
|
|
31
|
-
description: "A link to a CSV or TSV or the name of
|
|
30
|
+
regex: new RegExp(`(${UrlCellDef.regex?.source ?? ""}|^[\\w -()]+$)`), // URL or dataset name
|
|
31
|
+
description: "A link to a CSV or TSV or the name of a dataset.",
|
|
32
32
|
positionalCellDefs: [
|
|
33
33
|
{
|
|
34
34
|
...SlugDeclarationCellDef,
|
|
@@ -85,7 +85,7 @@ export const ExplorerGrammar: Grammar = {
|
|
|
85
85
|
keyword: "googleSheet",
|
|
86
86
|
valuePlaceholder: "https://docs.google.com/spreadsheets/d/1qeX...",
|
|
87
87
|
description:
|
|
88
|
-
"Create a Google Sheet, share it with
|
|
88
|
+
"Create a Google Sheet, share it with your team, then put the link here.",
|
|
89
89
|
},
|
|
90
90
|
downloadDataLink: {
|
|
91
91
|
...UrlCellDef,
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
CoreMatrix,
|
|
5
5
|
ColumnTypeNames,
|
|
6
6
|
CoreTableInputOption,
|
|
7
|
-
|
|
7
|
+
ColumnDef,
|
|
8
8
|
TableSlug,
|
|
9
9
|
SubNavId,
|
|
10
10
|
FacetAxisDomain,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "../types/index.js"
|
|
15
15
|
import {
|
|
16
16
|
CoreTable,
|
|
17
|
-
|
|
17
|
+
ChartsTable,
|
|
18
18
|
isNotErrorValue,
|
|
19
19
|
} from "../core-table/index.js"
|
|
20
20
|
import {
|
|
@@ -49,7 +49,7 @@ export const EXPLORER_FILE_SUFFIX = ".explorer.tsv"
|
|
|
49
49
|
|
|
50
50
|
export interface TableDef {
|
|
51
51
|
url?: string
|
|
52
|
-
columnDefinitions?:
|
|
52
|
+
columnDefinitions?: ColumnDef[]
|
|
53
53
|
inlineData?: string[][]
|
|
54
54
|
slug?: TableSlug
|
|
55
55
|
}
|
|
@@ -291,8 +291,8 @@ export class ExplorerProgram extends GridProgram {
|
|
|
291
291
|
return ""
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
-
get columnDefsByTableSlug(): Map<TableSlug | undefined,
|
|
295
|
-
const columnDefs = new Map<TableSlug | undefined,
|
|
294
|
+
get columnDefsByTableSlug(): Map<TableSlug | undefined, ColumnDef[]> {
|
|
295
|
+
const columnDefs = new Map<TableSlug | undefined, ColumnDef[]>()
|
|
296
296
|
const colDefsRows = this.getAllRowsMatchingWords(
|
|
297
297
|
ExplorerGrammar.columns.keyword
|
|
298
298
|
)
|
|
@@ -311,7 +311,7 @@ export class ExplorerProgram extends GridProgram {
|
|
|
311
311
|
return columnDefs
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
get columnDefsWithoutTableSlug():
|
|
314
|
+
get columnDefsWithoutTableSlug(): ColumnDef[] {
|
|
315
315
|
return this.columnDefsByTableSlug.get(undefined) ?? []
|
|
316
316
|
}
|
|
317
317
|
|
|
@@ -447,14 +447,14 @@ export class ExplorerProgram extends GridProgram {
|
|
|
447
447
|
}
|
|
448
448
|
)
|
|
449
449
|
|
|
450
|
-
async constructTable(tableSlug?: TableSlug): Promise<
|
|
450
|
+
async constructTable(tableSlug?: TableSlug): Promise<ChartsTable> {
|
|
451
451
|
const tableDef = this.getTableDef(tableSlug)
|
|
452
452
|
if (!tableDef) {
|
|
453
453
|
throw new Error(`Table definitions not found for '${tableSlug}'`)
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
if (tableDef.inlineData) {
|
|
457
|
-
return new
|
|
457
|
+
return new ChartsTable(
|
|
458
458
|
tableDef.inlineData,
|
|
459
459
|
tableDef.columnDefinitions,
|
|
460
460
|
{
|
|
@@ -466,7 +466,7 @@ export class ExplorerProgram extends GridProgram {
|
|
|
466
466
|
const input = await ExplorerProgram.tableDataLoader.get(
|
|
467
467
|
tableDef.url
|
|
468
468
|
)
|
|
469
|
-
return new
|
|
469
|
+
return new ChartsTable(input, tableDef.columnDefinitions, {
|
|
470
470
|
tableDescription: `Loaded from ${tableDef.url}`,
|
|
471
471
|
})
|
|
472
472
|
}
|
|
@@ -485,12 +485,15 @@ export class ExplorerProgram extends GridProgram {
|
|
|
485
485
|
const inlineData = this.getBlock(tableDefRow)
|
|
486
486
|
let url = inlineData ? undefined : this.lines[tableDefRow][1]
|
|
487
487
|
|
|
488
|
+
// If URL doesn't contain protocol, it's treated as a dataset slug
|
|
489
|
+
// Note: This legacy feature requires a full URL to be configured
|
|
488
490
|
if (url && !url.includes("://")) {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
+
console.warn(
|
|
492
|
+
`Dataset slug "${url}" provided without full URL. Please provide a complete URL.`
|
|
493
|
+
)
|
|
491
494
|
}
|
|
492
495
|
|
|
493
|
-
const columnDefinitions:
|
|
496
|
+
const columnDefinitions: ColumnDef[] | undefined =
|
|
494
497
|
this.columnDefsByTableSlug.get(tableSlug)
|
|
495
498
|
|
|
496
499
|
return {
|
|
@@ -523,14 +526,14 @@ export const trimAndParseObject = (config: any, grammar: Grammar) => {
|
|
|
523
526
|
return trimmedRow
|
|
524
527
|
}
|
|
525
528
|
|
|
526
|
-
const parseColumnDefs = (block: string[][]):
|
|
529
|
+
const parseColumnDefs = (block: string[][]): ColumnDef[] => {
|
|
527
530
|
/**
|
|
528
531
|
* A column def line can have:
|
|
529
532
|
* - a column named `variableId`, which contains a variable id
|
|
530
533
|
* - a column named `slug`, which is the referenced column in its data file
|
|
531
534
|
*
|
|
532
535
|
* We want to filter out any rows that contain neither of those, and we also
|
|
533
|
-
* want to rename `variableId` to `
|
|
536
|
+
* want to rename `variableId` to `variableId`.
|
|
534
537
|
*/
|
|
535
538
|
const columnsTable = new CoreTable(block)
|
|
536
539
|
.appendColumnsIfNew([
|
|
@@ -541,16 +544,16 @@ const parseColumnDefs = (block: string[][]): OwidColumnDef[] => {
|
|
|
541
544
|
name: "variableId",
|
|
542
545
|
},
|
|
543
546
|
])
|
|
544
|
-
.renameColumn("variableId", "
|
|
545
|
-
// Filter out rows that neither have a slug nor an
|
|
547
|
+
.renameColumn("variableId", "variableId")
|
|
548
|
+
// Filter out rows that neither have a slug nor an variableId
|
|
546
549
|
.rowFilter(
|
|
547
|
-
(row) => !!(row.slug || typeof row.
|
|
550
|
+
(row) => !!(row.slug || typeof row.variableId === "number"),
|
|
548
551
|
"Keep only column defs with a slug or variable id"
|
|
549
552
|
)
|
|
550
553
|
return columnsTable.rows.map((row) => {
|
|
551
554
|
// ignore slug if a variable id is given
|
|
552
555
|
const hasValidVariableId =
|
|
553
|
-
row.
|
|
556
|
+
row.variableId && isNotErrorValue(row.variableId)
|
|
554
557
|
if (hasValidVariableId && row.slug) delete row.slug
|
|
555
558
|
|
|
556
559
|
for (const field in row) {
|
|
@@ -43,7 +43,7 @@ export async function buildExplorerProps(
|
|
|
43
43
|
}
|
|
44
44
|
const props: ExplorerProps = {
|
|
45
45
|
...deserializeJSONFromHTML(html, EMBEDDED_EXPLORER_DELIMITER),
|
|
46
|
-
|
|
46
|
+
isEmbeddedInPage: true,
|
|
47
47
|
adminBaseUrl: explorerConstants.adminBaseUrl,
|
|
48
48
|
bakedBaseUrl: explorerConstants.bakedBaseUrl,
|
|
49
49
|
bakedGrapherUrl: explorerConstants.bakedGrapherUrl,
|
|
@@ -6,7 +6,7 @@ GridLang is a library for building 2-dimensional domain specific languages desig
|
|
|
6
6
|
|
|
7
7
|
Unlike traditional computer languages that parse tokens in-order, tokens in GridLanguages are parsed in a lazy, non-linear manner, based upon there position in a 2-d matrix.
|
|
8
8
|
|
|
9
|
-
Our "Explorer"—a DSL for building
|
|
9
|
+
Our "Explorer"—a DSL for building data explorers and Graphers—is a GridLang.
|
|
10
10
|
|
|
11
11
|
GridLangs are also intrinsically "patchable"—a great way for perserving user state.
|
|
12
12
|
|
package/src/grapher/axis/Axis.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TickFormattingOptions,
|
|
14
14
|
Tickmark,
|
|
15
15
|
ValueRange,
|
|
16
|
-
|
|
16
|
+
VariableRoundingMode,
|
|
17
17
|
} from "../../utils/index.js"
|
|
18
18
|
import { ComparisonLineConfig } from "../../types/index.js"
|
|
19
19
|
import { AxisConfig, AxisManager } from "./AxisConfig"
|
|
@@ -434,7 +434,7 @@ abstract class AbstractAxis {
|
|
|
434
434
|
private getTickFormattingOptions(): TickFormattingOptions {
|
|
435
435
|
const options: TickFormattingOptions = {
|
|
436
436
|
...this.config.tickFormattingOptions,
|
|
437
|
-
roundingMode:
|
|
437
|
+
roundingMode: VariableRoundingMode.decimalPlaces,
|
|
438
438
|
}
|
|
439
439
|
|
|
440
440
|
// The chart's tick formatting function is used by default to format axis ticks. This means
|
|
@@ -485,7 +485,7 @@ abstract class AbstractAxis {
|
|
|
485
485
|
// the value at the middle of the range.
|
|
486
486
|
// We instead want to customize what happens - sometimes we want to place the point
|
|
487
487
|
// at the start of the range instead.
|
|
488
|
-
// see
|
|
488
|
+
// see # legacy PR 1367#issuecomment-1090845181.
|
|
489
489
|
//
|
|
490
490
|
// -@marcelgerber, 2022-04-12
|
|
491
491
|
switch (this.config.singleValueAxisPointAlign) {
|