Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(grapher): don't offer non-plottable entities for selection #2763

Merged
merged 7 commits into from
Dec 18, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface ChartInterface {

transformTable: ChartTableTransformer
transformTableForDisplay?: ChartTableTransformer
transformTableForSelection?: ChartTableTransformer

yAxis?: HorizontalAxis | VerticalAxis
xAxis?: HorizontalAxis | VerticalAxis
Expand Down
23 changes: 14 additions & 9 deletions packages/@ourworldindata/grapher/src/core/Grapher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -675,16 +675,21 @@ export class Grapher
// Depending on the chart type, the criteria for being able to select an entity are
// different; e.g. for scatterplots, the entity needs to (1) not be excluded and
// (2) needs to have data for the x and y dimension.
let table =
this.isScatter || this.isSlopeChart
? this.tableAfterAuthorTimelineAndActiveChartTransform
: this.inputTable

if (!this.isReady) return table

// Some chart types (e.g. stacked area charts) choose not to show an entity
// with incomplete data. Such chart types define a custom transform function
// to ensure that the entity selector only offers entities that are actually plotted.
if (this.chartInstance.transformTableForSelection) {
table = this.chartInstance.transformTableForSelection(table)
}

if (this.isScatter || this.isSlopeChart)
// for scatter and slope charts, the `transformTable()` call takes care of removing
// all entities that cannot be selected
return this.tableAfterAuthorTimelineAndActiveChartTransform

// for other chart types, the `transformTable()` call would sometimes remove too many
// entities, and we want to use the inputTable instead (which should have exactly the
// entities where data is available)
return this.inputTable
return table
}

// If an author sets a timeline filter run it early in the pipeline so to the charts it's as if the filtered times do not exist
Expand Down
21 changes: 21 additions & 0 deletions packages/@ourworldindata/grapher/src/lineCharts/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
CoreValueType,
isNotErrorValue,
EntityName,
BlankOwidTable,
} from "@ourworldindata/core-table"
import {
autoDetectSeriesStrategy,
Expand Down Expand Up @@ -300,6 +301,26 @@ export class LineChart
return table
}

transformTableForSelection(table: OwidTable): OwidTable {
// if entities with partial data are not plotted,
// make sure they don't show up in the entity selector
if (this.missingDataStrategy === MissingDataStrategy.hide) {
table = table.replaceNonNumericCellsWithErrorValues(
this.yColumnSlugs
)

const groupedByEntity = table
.groupBy("entityName")
.filter((t) => !t.hasAnyColumnNoValidValue(this.yColumnSlugs))

if (groupedByEntity.length === 0) return BlankOwidTable()

table = groupedByEntity[0].concat(groupedByEntity.slice(1))
sophiamersmann marked this conversation as resolved.
Show resolved Hide resolved
}

return table
}

@computed private get missingDataStrategy(): MissingDataStrategy {
return this.manager.missingDataStrategy || MissingDataStrategy.auto
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import {
StackedRawSeries,
StackedSeries,
} from "./StackedConstants"
import { OwidTable, CoreColumn } from "@ourworldindata/core-table"
import {
OwidTable,
CoreColumn,
BlankOwidTable,
} from "@ourworldindata/core-table"
import {
autoDetectSeriesStrategy,
autoDetectYColumnSlugs,
Expand Down Expand Up @@ -84,6 +88,34 @@ export class AbstractStackedChart
return table
}

transformTableForSelection(table: OwidTable): OwidTable {
// if entities with partial data are not plotted,
// make sure they don't show up in the entity selector
if (this.missingDataStrategy !== MissingDataStrategy.show) {
table = table
.replaceNonNumericCellsWithErrorValues(this.yColumnSlugs)
.dropRowsWithErrorValuesForAllColumns(this.yColumnSlugs)

if (this.shouldRunLinearInterpolation) {
this.yColumnSlugs.forEach((slug) => {
table = table.interpolateColumnLinearly(slug)
})
}

const groupedByEntity = table
.groupBy("entityName")
.map((t: OwidTable) =>
t.dropRowsWithErrorValuesForAnyColumn(this.yColumnSlugs)
)

if (groupedByEntity.length === 0) return BlankOwidTable()

table = groupedByEntity[0].concat(groupedByEntity.slice(1))
sophiamersmann marked this conversation as resolved.
Show resolved Hide resolved
}

return table
}

@computed private get missingDataStrategy(): MissingDataStrategy {
return this.manager.missingDataStrategy || MissingDataStrategy.auto
}
Expand Down
Loading