Skip to content

Commit

Permalink
perf(table): optimize tableForSelection calls
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelgerber committed Apr 12, 2024
1 parent 2d9eb0d commit aafd093
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 18 deletions.
44 changes: 44 additions & 0 deletions packages/@ourworldindata/core-table/src/OwidTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,50 @@ export class OwidTable extends CoreTable<OwidRow, OwidColumnDef> {
)
}

dropEntitiesThatHaveNoDataInSomeColumn(columnSlugs: ColumnSlug[]): this {
const indexesByEntityName = this.rowIndicesByEntityName

// Iterate over all entities, and remove them as we go if they have no data in some column
const entityNamesToKeep = new Set(indexesByEntityName.keys())

for (let i = 0; i <= columnSlugs.length; i++) {
const slug = columnSlugs[i]
const col = this.get(slug)

// Optimization, if there are no error values in this column, we can skip this column
if (col.numErrorValues === 0) continue

for (const entityName of entityNamesToKeep) {
const indicesForEntityName = indexesByEntityName.get(entityName)
if (!indicesForEntityName)
throw new Error("Unexpected: entity not found in index map")

// Optimization: We don't care about the number of valid/error values, we just need
// to know if there is at least one valid value
const hasSomeValidValueForEntityInCol =
indicesForEntityName.some((index) =>
isNotErrorValue(col.valuesIncludingErrorValues[index])
)

// Optimization: If we find a column that this entity has no data in we can remove
// it immediately, no need to iterate over other columns also
if (!hasSomeValidValueForEntityInCol)
entityNamesToKeep.delete(entityName)
}
}

// const entityNamesToDrop = differenceOfSets([
// this.availableEntityNameSet,
// entityNamesToKeep,
// ])

return this.columnFilter(
this.entityNameSlug,
(rowEntityName) => entityNamesToKeep.has(rowEntityName as string),
`Drop entities that have no data in some column: ${columnSlugs.join(", ")}`
)
}

private sumsByTime(columnSlug: ColumnSlug): Map<number, number> {
const timeValues = this.timeColumn.values
const values = this.get(columnSlug).values as number[]
Expand Down
11 changes: 3 additions & 8 deletions packages/@ourworldindata/grapher/src/lineCharts/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ import {
OwidTable,
CoreColumn,
isNotErrorValue,
BlankOwidTable,
} from "@ourworldindata/core-table"
import {
autoDetectSeriesStrategy,
Expand Down Expand Up @@ -312,13 +311,9 @@ export class LineChart
this.yColumnSlugs
)

const groupedByEntity = table
.groupBy(table.entityNameColumn.slug)
.filter((t) => !t.hasAnyColumnNoValidValue(this.yColumnSlugs))

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

table = groupedByEntity[0].concat(groupedByEntity.slice(1))
table = table.dropEntitiesThatHaveNoDataInSomeColumn(
this.yColumnSlugs
)
}

return table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
import {
OwidTable,
CoreColumn,
BlankOwidTable,
isNotErrorValueOrEmptyCell,
} from "@ourworldindata/core-table"
import {
Expand Down Expand Up @@ -103,15 +102,7 @@ export class AbstractStackedChart
})
}

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

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

table = groupedByEntity[0].concat(groupedByEntity.slice(1))
table = table.dropRowsWithErrorValuesForAnyColumn(this.yColumnSlugs)
}

return table
Expand Down

0 comments on commit aafd093

Please sign in to comment.