Skip to content

Commit

Permalink
Merge pull request #786 from visualize-admin/feat/automatic-sort
Browse files Browse the repository at this point in the history
  • Loading branch information
ptbrowne authored Oct 20, 2022
2 parents 57d4b84 + 0e9a664 commit 9d9fed8
Show file tree
Hide file tree
Showing 28 changed files with 669 additions and 478 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ You can also check the [release page](https://github.com/visualize-admin/visuali
- Maintain segment sorting type correctly when switching from / to Pie chart
- Fix sorting by measure when undefined values are present in the data
- Enable CSS Color Module Level 3 color specifications in the color picker (instead of just HEX)
- New "Automatic" sorting option using "identifier" or "position" or "label"
- Sorting is enabled for line charts (sorts legend items and tooltip values)
- Map:
- area & symbol layers now use the same approach as for segment field (optional select element), to be more consistent across the app
- it's now possible to use discrete color mapping in symbol layer
- Errors:
- Make missing timeFormat error message more explicit

## [3.10.0] - 2022-10-19

- Improve loading performance for larger cubes

## [3.9.6] - 2022-10-12

- Fix: IRIs of NFI cubes (previously there was None-None- includes in IRI; it was removed recently and we now migrate old IRIs to new IRIs)
Expand Down
83 changes: 32 additions & 51 deletions app/charts/area/areas-state.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
ascending,
descending,
extent,
group,
max,
Expand All @@ -19,7 +18,7 @@ import {
sum,
} from "d3";
import keyBy from "lodash/keyBy";
import sortBy from "lodash/sortBy";
import orderBy from "lodash/orderBy";
import { ReactNode, useCallback, useMemo } from "react";

import { LEFT_MARGIN_OFFSET } from "@/charts/area/constants";
Expand Down Expand Up @@ -49,10 +48,9 @@ import {
useTimeFormatUnit,
} from "@/configurator/components/ui-helpers";
import { Observation } from "@/domain/data";
import { useLocale } from "@/locales/use-locale";
import { sortByIndex } from "@/utils/array";
import { estimateTextWidth } from "@/utils/estimate-text-width";
import { makeOrdinalDimensionSorter } from "@/utils/sorting-values";
import { makeDimensionValueSorters } from "@/utils/sorting-values";

export interface AreasState {
chartType: "area";
Expand Down Expand Up @@ -92,7 +90,6 @@ const useAreasState = (
interactiveFiltersConfig,
aspectRatio,
} = chartProps;
const locale = useLocale();
const width = useWidth();
const formatNumber = useFormatNumber();
const timeFormatUnit = useTimeFormatUnit();
Expand Down Expand Up @@ -211,60 +208,42 @@ const useAreasState = (
const yAxisDescription = yMeasure.description || undefined;

/** Ordered segments */
const segmentSortingType = fields.segment?.sorting?.sortingType;
const segmentSortingOrder = fields.segment?.sorting?.sortingOrder;
const segmentSorting = fields.segment?.sorting;
const segmentSortingType = segmentSorting?.sortingType;
const segmentSortingOrder = segmentSorting?.sortingOrder;

const segments = useMemo(() => {
const getSegmentsOrderedByName = () =>
Array.from(new Set(plottableSortedData.map((d) => getSegment(d)))).sort(
(a, b) =>
segmentSortingOrder === "asc"
? a.localeCompare(b, locale)
: b.localeCompare(a, locale)
);

const getSegmentsOrderedByTotalValue = () =>
[
...rollup(
plottableSortedData,
(v) => sum(v, (x) => getY(x)),
(x) => getSegment(x)
),
]
.sort((a, b) =>
segmentSortingOrder === "asc"
? ascending(a[1], b[1])
: descending(a[1], b[1])
)
.map((d) => d[0]);

const getSegmentsOrderedByPosition = () => {
const segments = Array.from(
new Set(plottableSortedData.map((d) => getSegment(d)))
);
const sorter = dimension ? makeOrdinalDimensionSorter(dimension) : null;
return sorter ? sortBy(segments, sorter) : segments;
};

const totalValueBySegment = Object.fromEntries([
...rollup(
plottableSortedData,
(v) => sum(v, (x) => getY(x)),
(x) => getSegment(x)
),
]);

const uniqueSegments = Array.from(
new Set(plottableSortedData.map((d) => getSegment(d)))
);
const dimension = dimensions.find(
(dim) => dim.iri === fields.segment?.componentIri
);
if (dimension?.__typename === "OrdinalDimension") {
return getSegmentsOrderedByPosition();
}

return segmentSortingType === "byDimensionLabel"
? getSegmentsOrderedByName()
: getSegmentsOrderedByTotalValue();
const sorters = makeDimensionValueSorters(dimension, {
sorting: segmentSorting,
sumsBySegment: totalValueBySegment,
});
return orderBy(
uniqueSegments,
sorters,
segmentSortingOrder === "desc" ? "desc" : "asc"
);
}, [
plottableSortedData,
dimensions,
fields.segment?.componentIri,
getSegment,
getY,
locale,
segmentSorting,
segmentSortingOrder,
segmentSortingType,
plottableSortedData,
getY,
getSegment,
fields.segment?.componentIri,
]);

/** Transform data */
Expand Down Expand Up @@ -321,9 +300,11 @@ const useAreasState = (

colors.domain(orderedSegmentLabelsAndColors.map((s) => s.label));
colors.range(orderedSegmentLabelsAndColors.map((s) => s.color));
colors.unknown(() => undefined);
} else {
colors.domain(segments);
colors.range(getPalette(fields.segment?.palette));
colors.unknown(() => undefined);
}
return { colors, xScale, yScale, xEntireScale };
}, [
Expand Down
8 changes: 8 additions & 0 deletions app/charts/chart-config-ui-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,21 @@ const SEGMENT_COMPONENT_TYPES: ComponentType[] = [
];

export const AREA_SEGMENT_SORTING: EncodingSortingOption[] = [
{ sortingType: "byAuto", sortingOrder: ["asc", "desc"] },
{ sortingType: "byDimensionLabel", sortingOrder: ["asc", "desc"] },
{ sortingType: "byTotalSize", sortingOrder: ["asc", "desc"] },
];

export const LINE_SEGMENT_SORTING: EncodingSortingOption[] = [
{ sortingType: "byAuto", sortingOrder: ["asc", "desc"] },
{ sortingType: "byDimensionLabel", sortingOrder: ["asc", "desc"] },
];

export const COLUMN_SEGMENT_SORTING: EncodingSortingOption[] =
AREA_SEGMENT_SORTING;

export const PIE_SEGMENT_SORTING: EncodingSortingOption[] = [
{ sortingType: "byAuto", sortingOrder: ["asc", "desc"] },
{ sortingType: "byMeasure", sortingOrder: ["asc", "desc"] },
{ sortingType: "byDimensionLabel", sortingOrder: ["asc", "desc"] },
];
Expand Down Expand Up @@ -216,6 +223,7 @@ export const chartConfigOptionsUISpec: ChartSpecs = {
optional: true,
componentTypes: SEGMENT_COMPONENT_TYPES,
filters: true,
sorting: LINE_SEGMENT_SORTING,
options: [{ field: "color", type: "palette" }],
},
],
Expand Down
Loading

1 comment on commit 9d9fed8

@vercel
Copy link

@vercel vercel bot commented on 9d9fed8 Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

visualization-tool – ./

visualization-tool-ixt1.vercel.app
visualization-tool-alpha.vercel.app
visualization-tool-git-main-ixt1.vercel.app

Please sign in to comment.