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

feat: Add temporal entity dimension filtering to dashboard filters #1568

Merged
merged 9 commits into from
Jun 6, 2024
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
Loading