From f3882f12da0472b7de82e05edfb35d2ccc814e1b Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard29 Date: Thu, 28 Dec 2023 16:52:49 +0100 Subject: [PATCH 1/7] feat(COR-1857): Reversed variants in graph and legend items --- .../variants/data-selection/get-variant-bar-chart-data.ts | 2 +- .../app/src/domain/variants/variants-stacked-bar-chart-tile.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts b/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts index 64cd45edcb..1d633ff2d1 100644 --- a/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts +++ b/packages/app/src/domain/variants/data-selection/get-variant-bar-chart-data.ts @@ -20,7 +20,7 @@ export function getVariantBarChartData(variants: NlVariants) { return EMPTY_VALUES; } - const sortedVariants = variants.values.sort((a, b) => b.last_value.order - a.last_value.order); + const sortedVariants = variants.values.sort((a, b) => a.last_value.order - b.last_value.order); const firstVariantInList = sortedVariants.shift(); diff --git a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx index 85116b018c..b5855aeeb8 100644 --- a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx +++ b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx @@ -59,7 +59,7 @@ export const VariantsStackedBarChartTile = ({ title, description, tooltipLabels, timeframeInitialValue={TimeframeOption.THIRTY_DAYS} onSelectTimeframe={setVariantTimeFrame} > - + Date: Wed, 3 Jan 2024 14:40:08 +0100 Subject: [PATCH 2/7] feat(COR-1857): Add logic for tooltip --- .../variants/logic/reorder-and-filter.ts | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 983bb63249..91d635991a 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -17,18 +17,40 @@ const hasMetricProperty = (config: any): config is { metricProperty: string } => * @param selectionOptions - Currently selected variants */ export const reorderAndFilter = (context: TooltipData, selectionOptions: P[]) => { - const hasSelectedMetrics = context.config.length !== selectionOptions.length; // Check whether the user has selected any variants from the interactive legend. + const filterSelectionActive = context.config.length !== selectionOptions.length; // Check whether the user has selected any variants from the interactive legend. /* Filter out any variants that have an occcurrence value of 0 */ - const filteredValues = Object.fromEntries( + const valuesFromContext = Object.fromEntries( Object.entries(context.value).filter(([key, value]) => (key.includes('occurrence') ? value !== 0 && isPresent(value) && !isNaN(Number(value)) : value)) ) as VariantChartValue; - /* Rebuild tooltip data context with filtered values */ + const sortedValuesFromContext = Object.fromEntries( + Object.entries(valuesFromContext).sort((a, b) => { + if (a[0].includes('occurrence') && typeof a[1] === 'number') { + if (a[0] === b[0]) { + return 0; + } else { + return a[0] < b[0] ? -1 : 1; + } + } else { + return 0; + } + }) + ); + + /** + * Generate filtered tooltip context. + * If user has selected any variants to filter: + * - return all properties from context config + * If user has not selected any variants to filter: + * return only properties from context config that are either: + * - Do NOT contain key 'metricProperty' + * - Do contain key 'metricProperty' and it's value matches with keyname in valuesFromContext object + */ const reorderContext = { ...context, - config: [...context.config.filter((value) => !hasMetricProperty(value) || filteredValues[value.metricProperty] || hasSelectedMetrics)].filter(isDefined), - value: !hasSelectedMetrics ? filteredValues : context.value, + config: [...context.config.filter((value) => !hasMetricProperty(value) || sortedValuesFromContext[value.metricProperty] || filterSelectionActive)].filter(isDefined), + value: !filterSelectionActive ? valuesFromContext : context.value, }; return reorderContext as TooltipData; From bf2ce465ed680af0e7d2f5c9c0a10b5774880749 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard29 Date: Wed, 3 Jan 2024 15:49:18 +0100 Subject: [PATCH 3/7] feat(COR-1857): Removed newline --- packages/app/src/domain/variants/logic/reorder-and-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 91d635991a..a19d9ca8fc 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -36,7 +36,7 @@ export const reorderAndFilter = (context: TooltipData Date: Wed, 10 Jan 2024 17:11:07 +0100 Subject: [PATCH 4/7] feat(COR-1857): Reorder tooltip --- .../variants/logic/reorder-and-filter.ts | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index a19d9ca8fc..15722d9730 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -19,37 +19,35 @@ const hasMetricProperty = (config: any): config is { metricProperty: string } => export const reorderAndFilter = (context: TooltipData, selectionOptions: P[]) => { const filterSelectionActive = context.config.length !== selectionOptions.length; // Check whether the user has selected any variants from the interactive legend. - /* Filter out any variants that have an occcurrence value of 0 */ + // If the user has no filter selected -> Filter out any variants that have an occurrence value of 0 const valuesFromContext = Object.fromEntries( Object.entries(context.value).filter(([key, value]) => (key.includes('occurrence') ? value !== 0 && isPresent(value) && !isNaN(Number(value)) : value)) ) as VariantChartValue; - const sortedValuesFromContext = Object.fromEntries( - Object.entries(valuesFromContext).sort((a, b) => { - if (a[0].includes('occurrence') && typeof a[1] === 'number') { - if (a[0] === b[0]) { - return 0; - } else { - return a[0] < b[0] ? -1 : 1; - } - } else { - return 0; - } + // If the user has no filter selected -> Filter out configs that do not contain a 'metricProperty' key OR have an occurrence value of 0 + const filteredConfigs = context.config + .filter((value) => { + return !hasMetricProperty(value) || valuesFromContext[value.metricProperty] || filterSelectionActive; }) - ) as VariantChartValue; + .filter(isDefined); + + // Sort variants by occurrence + const sortedConfigs = filteredConfigs.sort((a: any, b: any) => { + return context.value[b.metricProperty] - context.value[a.metricProperty]; + }); + + // Move config entry 'other variants' to end + sortedConfigs.push( + sortedConfigs.splice( + sortedConfigs.map((configEntry: any) => configEntry.metricProperty).findIndex((e) => e === 'other_variants_percentage' || e === 'other_variants_occurrence'), + 1 + )[0] + ); - /** - * Generate filtered tooltip context. - * If user has selected any variants to filter: - * - return all properties from context config - * If user has not selected any variants to filter: - * return only properties from context config that are either: - * - Do NOT contain key 'metricProperty' - * - Do contain key 'metricProperty' and it's value matches with keyname in valuesFromContext object - */ + // Generate filtered tooltip context const reorderContext = { ...context, - config: [...context.config.filter((value) => !hasMetricProperty(value) || sortedValuesFromContext[value.metricProperty] || filterSelectionActive)].filter(isDefined), + config: sortedConfigs.filter(isDefined), value: !filterSelectionActive ? valuesFromContext : context.value, }; From 72aee372cf135570622f762cdc0c095c438d58f9 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard29 Date: Tue, 16 Jan 2024 15:55:47 +0100 Subject: [PATCH 5/7] feat(COR-1857): Make mechanism for putting other variants at end more elegant --- .../variants/logic/reorder-and-filter.ts | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 15722d9730..274fe35ab2 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -31,23 +31,29 @@ export const reorderAndFilter = (context: TooltipData { + if (a.metricProperty.includes('other_variants')) return 1; + if (b.metricProperty.includes('other_variants')) return -1; return context.value[b.metricProperty] - context.value[a.metricProperty]; }); - // Move config entry 'other variants' to end - sortedConfigs.push( - sortedConfigs.splice( - sortedConfigs.map((configEntry: any) => configEntry.metricProperty).findIndex((e) => e === 'other_variants_percentage' || e === 'other_variants_occurrence'), - 1 - )[0] - ); + /** + * { + * "type": "stacked-bar", + * "metricProperty": "JN_1_occurrence", + * "color": "#C80000", + * "label": "Omikron JN.1", + * "fillOpacity": 1, + * "shape": "gapped-area" + * } + */ // Generate filtered tooltip context const reorderContext = { ...context, - config: sortedConfigs.filter(isDefined), + config: sortedConfigs, value: !filterSelectionActive ? valuesFromContext : context.value, }; From 82fe2e8bcfea1927a3ce2915227a76e6221689df Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard29 Date: Tue, 16 Jan 2024 16:56:33 +0100 Subject: [PATCH 6/7] feat(COR-1857): Remove todo and skeleton code --- .../src/domain/variants/logic/reorder-and-filter.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 274fe35ab2..60b7bf6281 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -32,24 +32,12 @@ export const reorderAndFilter = (context: TooltipData { if (a.metricProperty.includes('other_variants')) return 1; if (b.metricProperty.includes('other_variants')) return -1; return context.value[b.metricProperty] - context.value[a.metricProperty]; }); - /** - * { - * "type": "stacked-bar", - * "metricProperty": "JN_1_occurrence", - * "color": "#C80000", - * "label": "Omikron JN.1", - * "fillOpacity": 1, - * "shape": "gapped-area" - * } - */ - // Generate filtered tooltip context const reorderContext = { ...context, From 2dea5bf8eb2a8d5abe1618ebb660fa934d8aea63 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard29 Date: Wed, 17 Jan 2024 17:22:26 +0100 Subject: [PATCH 7/7] feat(COR-1857): Add ordering based on rank in tooltip --- .../time-series-chart/logic/series.ts | 1 + .../data-selection/get-variant-orders.ts | 21 ++++++++++++++++ .../domain/variants/data-selection/index.ts | 1 + .../domain/variants/data-selection/types.ts | 5 ++++ .../variants/logic/reorder-and-filter.ts | 1 + .../domain/variants/logic/use-bar-config.ts | 8 +++++-- .../variants-stacked-bar-chart-tile.tsx | 24 +++++++++++++------ .../app/src/pages/landelijk/varianten.tsx | 7 +++++- 8 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 packages/app/src/domain/variants/data-selection/get-variant-orders.ts diff --git a/packages/app/src/components/time-series-chart/logic/series.ts b/packages/app/src/components/time-series-chart/logic/series.ts index 8bbbd580b2..1c29fbb654 100644 --- a/packages/app/src/components/time-series-chart/logic/series.ts +++ b/packages/app/src/components/time-series-chart/logic/series.ts @@ -186,6 +186,7 @@ export interface StackedBarSeriesDefinition extends shortLabel?: string; color: string; fillOpacity?: number; + order: number; } /** diff --git a/packages/app/src/domain/variants/data-selection/get-variant-orders.ts b/packages/app/src/domain/variants/data-selection/get-variant-orders.ts new file mode 100644 index 0000000000..d3a6a5d4eb --- /dev/null +++ b/packages/app/src/domain/variants/data-selection/get-variant-orders.ts @@ -0,0 +1,21 @@ +import { NlVariants } from '@corona-dashboard/common'; +import { OrderMatch } from '~/domain/variants/data-selection/types'; +import { isDefined } from 'ts-is-present'; + +export const getVariantOrders = (variants: NlVariants): OrderMatch[] => { + if (!isDefined(variants) || !isDefined(variants.values)) { + return []; + } + + const order = variants.values + .sort((a, b) => a.last_value.order - b.last_value.order) + .map((variant) => { + const variantOrder = variant.last_value.order; + return { + variant: variant.variant_code, + order: variantOrder, + }; + }); + + return order; +}; diff --git a/packages/app/src/domain/variants/data-selection/index.ts b/packages/app/src/domain/variants/data-selection/index.ts index 7589614493..4e7e3b7772 100644 --- a/packages/app/src/domain/variants/data-selection/index.ts +++ b/packages/app/src/domain/variants/data-selection/index.ts @@ -2,3 +2,4 @@ export * from './get-variant-bar-chart-data'; export * from './get-archived-variant-chart-data'; export * from './get-variant-order-colors'; export * from './get-variant-table-data'; +export * from './get-variant-orders'; diff --git a/packages/app/src/domain/variants/data-selection/types.ts b/packages/app/src/domain/variants/data-selection/types.ts index 682bbc6651..79a9f442d1 100644 --- a/packages/app/src/domain/variants/data-selection/types.ts +++ b/packages/app/src/domain/variants/data-selection/types.ts @@ -9,6 +9,11 @@ export type ColorMatch = { color: string; }; +export type OrderMatch = { + variant: VariantCode; + order: number; +}; + export type VariantTableData = ReturnType; export type VariantChartValue = { diff --git a/packages/app/src/domain/variants/logic/reorder-and-filter.ts b/packages/app/src/domain/variants/logic/reorder-and-filter.ts index 60b7bf6281..3d4b7cdaf7 100644 --- a/packages/app/src/domain/variants/logic/reorder-and-filter.ts +++ b/packages/app/src/domain/variants/logic/reorder-and-filter.ts @@ -35,6 +35,7 @@ export const reorderAndFilter = (context: TooltipData { if (a.metricProperty.includes('other_variants')) return 1; if (b.metricProperty.includes('other_variants')) return -1; + if (context.value[a.metricProperty] === context.value[b.metricProperty]) return b.order - a.order; return context.value[b.metricProperty] - context.value[a.metricProperty]; }); diff --git a/packages/app/src/domain/variants/logic/use-bar-config.ts b/packages/app/src/domain/variants/logic/use-bar-config.ts index 966d672936..2ee46bc239 100644 --- a/packages/app/src/domain/variants/logic/use-bar-config.ts +++ b/packages/app/src/domain/variants/logic/use-bar-config.ts @@ -1,4 +1,4 @@ -import { ColorMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; +import { ColorMatch, OrderMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; import { useMemo } from 'react'; import { getValuesInTimeframe, TimeframeOption } from '@corona-dashboard/common'; import { isPresent } from 'ts-is-present'; @@ -25,6 +25,7 @@ export const useBarConfig = ( variantLabels: VariantDynamicLabels, tooltipLabels: VariantsOverTimeGraphText, colors: ColorMatch[], + orders: OrderMatch[], timeframe: TimeframeOption, today: Date ) => { @@ -54,6 +55,8 @@ export const useBarConfig = ( const color = colors.find((variantColors) => variantColors.variant === variantCodeName)?.color; + const order = orders.find((varianOrders) => varianOrders.variant === variantCodeName)?.order; + if (variantDynamicLabel) { const barChartConfigEntry = { type: 'stacked-bar', @@ -62,6 +65,7 @@ export const useBarConfig = ( label: variantDynamicLabel, fillOpacity: 1, shape: 'gapped-area', + order: order, }; barChartConfig.push(barChartConfigEntry as StackedBarSeriesDefinition); @@ -69,5 +73,5 @@ export const useBarConfig = ( }); return barChartConfig; - }, [values, tooltipLabels.tooltip_labels.other_percentage, variantLabels, colors, timeframe, today]); + }, [values, tooltipLabels.tooltip_labels.other_percentage, variantLabels, colors, orders, timeframe, today]); }; diff --git a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx index b5855aeeb8..07aff84a78 100644 --- a/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx +++ b/packages/app/src/domain/variants/variants-stacked-bar-chart-tile.tsx @@ -2,7 +2,7 @@ import { ChartTile, MetadataProps, TimeSeriesChart } from '~/components'; import { Spacer } from '~/components/base'; import { TimeframeOption, TimeframeOptionsList } from '@corona-dashboard/common'; import { useState } from 'react'; -import { ColorMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; +import { ColorMatch, OrderMatch, VariantChartValue, VariantDynamicLabels, VariantsOverTimeGraphText } from '~/domain/variants/data-selection/types'; import { useBarConfig } from '~/domain/variants/logic/use-bar-config'; import { InteractiveLegend, SelectOption } from '~/components/interactive-legend'; import { useList } from '~/utils/use-list'; @@ -13,13 +13,14 @@ import { reorderAndFilter } from '~/domain/variants/logic/reorder-and-filter'; import { useIntl } from '~/intl'; interface VariantsStackedBarChartTileProps { - title: string; description: string; - values: VariantChartValue[]; + metadata: MetadataProps; + title: string; tooltipLabels: VariantsOverTimeGraphText; - variantLabels: VariantDynamicLabels; + values: VariantChartValue[]; variantColors: ColorMatch[]; - metadata: MetadataProps; + variantLabels: VariantDynamicLabels; + variantOrders: OrderMatch[]; } const alwaysEnabled: (keyof VariantChartValue)[] = []; @@ -35,12 +36,21 @@ const alwaysEnabled: (keyof VariantChartValue)[] = []; * @param metadata - Metadata block * @constructor */ -export const VariantsStackedBarChartTile = ({ title, description, tooltipLabels, values, variantLabels, variantColors, metadata }: VariantsStackedBarChartTileProps) => { +export const VariantsStackedBarChartTile = ({ + title, + description, + tooltipLabels, + values, + variantLabels, + variantColors, + variantOrders, + metadata, +}: VariantsStackedBarChartTileProps) => { const today = useCurrentDate(); const { commonTexts } = useIntl(); const { list, toggle, clear } = useList(alwaysEnabled); const [variantTimeFrame, setVariantTimeFrame] = useState(TimeframeOption.THIRTY_DAYS); - const barSeriesConfig = useBarConfig(values, variantLabels, tooltipLabels, variantColors, variantTimeFrame, today); + const barSeriesConfig = useBarConfig(values, variantLabels, tooltipLabels, variantColors, variantOrders, variantTimeFrame, today); const text = commonTexts.variants_page; diff --git a/packages/app/src/pages/landelijk/varianten.tsx b/packages/app/src/pages/landelijk/varianten.tsx index 3cb104209d..569b51a6c9 100644 --- a/packages/app/src/pages/landelijk/varianten.tsx +++ b/packages/app/src/pages/landelijk/varianten.tsx @@ -18,7 +18,7 @@ import { getLastInsertionDateOfPage } from '~/utils/get-last-insertion-date-of-p import { getPageInformationHeaderContent } from '~/utils/get-page-information-header-content'; import { BorderedKpiSection } from '~/components/kpi/bordered-kpi-section'; import { useState } from 'react'; -import { getArchivedVariantChartData, getVariantBarChartData, getVariantOrderColors, getVariantTableData } from '~/domain/variants/data-selection'; +import { getArchivedVariantChartData, getVariantBarChartData, getVariantOrderColors, getVariantOrders, getVariantTableData } from '~/domain/variants/data-selection'; import { VariantsStackedAreaTile, VariantsStackedBarChartTile, VariantsTableTile } from '~/domain/variants'; import { VariantDynamicLabels } from '~/domain/variants/data-selection/types'; import { NlVariantsVariant } from '@corona-dashboard/common'; @@ -51,11 +51,14 @@ export const getStaticProps = createGetStaticProps( const variantColors = getVariantOrderColors(variants); + const variantOrders = getVariantOrders(variants); + return { ...getVariantTableData(variants, data.selectedNlData.named_difference, variantColors), ...getVariantBarChartData(variants), ...getArchivedVariantChartData(variants_archived_20231101), variantColors, + variantOrders, }; }, async (context: GetStaticPropsContext) => { @@ -83,6 +86,7 @@ export default function CovidVariantenPage(props: StaticProps