Skip to content

Commit

Permalink
Merge pull request #1568 from visualize-admin/fix/temporal-entity-fil…
Browse files Browse the repository at this point in the history
…tering

feat: Add temporal entity dimension filtering to dashboard filters
  • Loading branch information
bprusinowski authored Jun 6, 2024
2 parents bb597a9 + ca65c75 commit 4363e67
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 62 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ You can also check the [release page](https://github.com/visualize-admin/visuali

# Unreleased

- Features
- Added TemporalEntityDimension support for global dashboard filters
- Fixes
- Fixed using a time range brush in column charts when X dimension is a TemporalEntityDimension
- Whiskers should now display correctly at the initial render

# [4.6.1] - 2024-06-05
Expand Down
19 changes: 17 additions & 2 deletions app/charts/area/areas-state-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { usePlottableData } from "@/charts/shared/chart-helpers";
import {
BaseVariables,
ChartStateData,
InteractiveFiltersVariables,
NumericalYVariables,
SegmentVariables,
SortingVariables,
TemporalXVariables,
useBaseVariables,
useChartData,
useInteractiveFiltersVariables,
useNumericalYVariables,
useSegmentVariables,
useTemporalXVariables,
Expand All @@ -22,7 +24,8 @@ export type AreasStateVariables = BaseVariables &
SortingVariables &
TemporalXVariables &
NumericalYVariables &
SegmentVariables;
SegmentVariables &
InteractiveFiltersVariables;

export const useAreasStateVariables = (
props: ChartProps<AreaConfig>
Expand All @@ -42,6 +45,10 @@ export const useAreasStateVariables = (
dimensionsByIri,
observations,
});
const interactiveFiltersVariables = useInteractiveFiltersVariables(
chartConfig.interactiveFiltersConfig,
{ dimensionsByIri }
);

const { getX } = temporalXVariables;
const sortData: AreasStateVariables["sortData"] = useCallback(
Expand All @@ -59,6 +66,7 @@ export const useAreasStateVariables = (
...temporalXVariables,
...numericalYVariables,
...segmentVariables,
...interactiveFiltersVariables,
};
};

Expand All @@ -67,7 +75,13 @@ export const useAreasStateData = (
variables: AreasStateVariables
): ChartStateData => {
const { chartConfig, observations } = chartProps;
const { sortData, getX, getY, getSegmentAbbreviationOrLabel } = variables;
const {
sortData,
getX,
getY,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
} = variables;
const plottableData = usePlottableData(observations, {
getX,
getY,
Expand All @@ -79,6 +93,7 @@ export const useAreasStateData = (
chartConfig,
getXAsDate: getX,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
});

return {
Expand Down
37 changes: 28 additions & 9 deletions app/charts/column/columns-grouped-state-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
BandXVariables,
BaseVariables,
ChartStateData,
InteractiveFiltersVariables,
NumericalYErrorVariables,
NumericalYVariables,
RenderingVariables,
Expand All @@ -15,12 +16,14 @@ import {
useBandXVariables,
useBaseVariables,
useChartData,
useInteractiveFiltersVariables,
useNumericalYErrorVariables,
useNumericalYVariables,
useSegmentVariables,
} from "@/charts/shared/chart-state";
import { useRenderingKeyVariable } from "@/charts/shared/rendering-utils";
import { ColumnConfig, useChartConfigFilters } from "@/configurator";
import { Observation, isTemporalEntityDimension } from "@/domain/data";
import { sortByIndex } from "@/utils/array";

import { ChartProps } from "../shared/ChartProps";
Expand All @@ -31,7 +34,8 @@ export type ColumnsGroupedStateVariables = BaseVariables &
NumericalYVariables &
NumericalYErrorVariables &
SegmentVariables &
RenderingVariables;
RenderingVariables &
InteractiveFiltersVariables;

export const useColumnsGroupedStateVariables = (
props: ChartProps<ColumnConfig>
Expand All @@ -46,6 +50,7 @@ export const useColumnsGroupedStateVariables = (
} = props;
const { fields, interactiveFiltersConfig } = chartConfig;
const { x, y, segment, animation } = fields;
const xDimension = dimensionsByIri[x.componentIri];
const filters = useChartConfigFilters(chartConfig);

const baseVariables = useBaseVariables(chartConfig);
Expand All @@ -65,31 +70,38 @@ export const useColumnsGroupedStateVariables = (
dimensionsByIri,
observations,
});
const interactiveFiltersVariables = useInteractiveFiltersVariables(
interactiveFiltersConfig,
{ dimensionsByIri }
);

const { getX } = bandXVariables;
const { getX, getXAsDate } = bandXVariables;
const { getY } = numericalYVariables;
const sortData: ColumnsGroupedStateVariables["sortData"] = useCallback(
(data) => {
const { sortingOrder, sortingType } = x.sorting ?? {};
const xGetter = isTemporalEntityDimension(xDimension)
? (d: Observation) => getXAsDate(d).getTime().toString()
: getX;
const order = [
...rollup(
data,
(v) => sum(v, (d) => getY(d)),
(d) => getX(d)
(d) => xGetter(d)
),
]
.sort((a, b) => ascending(a[1], b[1]))
.map((d) => d[0]);

if (sortingType === "byDimensionLabel") {
return orderBy(data, getX, sortingOrder);
return orderBy(data, xGetter, sortingOrder);
} else if (sortingType === "byMeasure") {
return sortByIndex({ data, order, getCategory: getX, sortingOrder });
return sortByIndex({ data, order, getCategory: xGetter, sortingOrder });
} else {
return orderBy(data, getX, "asc");
return orderBy(data, xGetter, "asc");
}
},
[getX, getY, x.sorting]
[getX, getXAsDate, getY, x.sorting, xDimension]
);

const getRenderingKey = useRenderingKeyVariable(
Expand All @@ -106,6 +118,7 @@ export const useColumnsGroupedStateVariables = (
...numericalYVariables,
...numericalYErrorVariables,
...segmentVariables,
...interactiveFiltersVariables,
getRenderingKey,
};
};
Expand All @@ -115,8 +128,13 @@ export const useColumnsGroupedStateData = (
variables: ColumnsGroupedStateVariables
): ChartStateData => {
const { chartConfig, observations } = chartProps;
const { sortData, getXAsDate, getY, getSegmentAbbreviationOrLabel } =
variables;
const {
sortData,
getXAsDate,
getY,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
} = variables;
const plottableData = usePlottableData(observations, {
getY,
});
Expand All @@ -127,6 +145,7 @@ export const useColumnsGroupedStateData = (
chartConfig,
getXAsDate,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
});

return {
Expand Down
32 changes: 23 additions & 9 deletions app/charts/column/columns-stacked-state-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ import {
BandXVariables,
BaseVariables,
ChartStateData,
InteractiveFiltersVariables,
NumericalYVariables,
RenderingVariables,
SegmentVariables,
SortingVariables,
useBandXVariables,
useBaseVariables,
useChartData,
useInteractiveFiltersVariables,
useNumericalYVariables,
useSegmentVariables,
} from "@/charts/shared/chart-state";
import { useRenderingKeyVariable } from "@/charts/shared/rendering-utils";
import { ColumnConfig, useChartConfigFilters } from "@/configurator";
import { Observation } from "@/domain/data";
import { Observation, isTemporalEntityDimension } from "@/domain/data";
import { sortByIndex } from "@/utils/array";

import { ChartProps } from "../shared/ChartProps";
Expand All @@ -28,7 +30,8 @@ export type ColumnsStackedStateVariables = BaseVariables &
BandXVariables &
NumericalYVariables &
SegmentVariables &
RenderingVariables;
RenderingVariables &
InteractiveFiltersVariables;

export const useColumnsStackedStateVariables = (
props: ChartProps<ColumnConfig>
Expand All @@ -42,6 +45,7 @@ export const useColumnsStackedStateVariables = (
} = props;
const { fields, interactiveFiltersConfig } = chartConfig;
const { x, y, segment, animation } = fields;
const xDimension = dimensionsByIri[x.componentIri];
const filters = useChartConfigFilters(chartConfig);

const baseVariables = useBaseVariables(chartConfig);
Expand All @@ -56,31 +60,38 @@ export const useColumnsStackedStateVariables = (
dimensionsByIri,
observations,
});
const interactiveFiltersVariables = useInteractiveFiltersVariables(
interactiveFiltersConfig,
{ dimensionsByIri }
);

const { getX } = bandXVariables;
const { getX, getXAsDate } = bandXVariables;
const sortData: ColumnsStackedStateVariables["sortData"] = useCallback(
(data, { plottableDataWide }) => {
const { sortingOrder, sortingType } = x.sorting ?? {};
const xGetter = isTemporalEntityDimension(xDimension)
? (d: Observation) => getXAsDate(d).getTime().toString()
: getX;
const xOrder = plottableDataWide
.sort((a, b) => ascending(a.total ?? undefined, b.total ?? undefined))
.map(getX);
.map(xGetter);

if (sortingOrder === "desc" && sortingType === "byDimensionLabel") {
return [...data].sort((a, b) => descending(getX(a), getX(b)));
return [...data].sort((a, b) => descending(xGetter(a), xGetter(b)));
} else if (sortingOrder === "asc" && sortingType === "byDimensionLabel") {
return [...data].sort((a, b) => ascending(getX(a), getX(b)));
return [...data].sort((a, b) => ascending(xGetter(a), xGetter(b)));
} else if (sortingType === "byMeasure") {
return sortByIndex({
data,
order: xOrder,
getCategory: getX,
getCategory: xGetter,
sortingOrder,
});
} else {
return [...data].sort((a, b) => ascending(getX(a), getX(b)));
return [...data].sort((a, b) => ascending(xGetter(a), xGetter(b)));
}
},
[getX, x.sorting]
[getX, getXAsDate, x.sorting, xDimension]
);

const getRenderingKey = useRenderingKeyVariable(
Expand All @@ -96,6 +107,7 @@ export const useColumnsStackedStateVariables = (
...bandXVariables,
...numericalYVariables,
...segmentVariables,
...interactiveFiltersVariables,
getRenderingKey,
};
};
Expand All @@ -118,6 +130,7 @@ export const useColumnsStackedStateData = (
getY,
getSegment,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
} = variables;
const plottableData = usePlottableData(observations, {
getY,
Expand All @@ -142,6 +155,7 @@ export const useColumnsStackedStateData = (
chartConfig,
getXAsDate,
getSegmentAbbreviationOrLabel,
getTimeRangeDate,
});

return {
Expand Down
Loading

0 comments on commit 4363e67

Please sign in to comment.