Skip to content

Commit

Permalink
feat: Handle same labels in column chart
Browse files Browse the repository at this point in the history
  • Loading branch information
bprusinowski committed Apr 11, 2023
1 parent 60cdbc3 commit fa3317e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 24 deletions.
83 changes: 63 additions & 20 deletions app/charts/column/columns-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
ScaleTime,
} from "d3";
import get from "lodash/get";
import keyBy from "lodash/keyBy";
import orderBy from "lodash/orderBy";
import { ReactNode, useCallback, useMemo } from "react";

Expand Down Expand Up @@ -57,7 +56,6 @@ import {
TemporalDimension,
TimeUnit,
} from "@/graphql/query-hooks";
import { getPalette } from "@/palettes";
import {
getSortingOrders,
makeDimensionValueSorters,
Expand All @@ -68,6 +66,7 @@ export interface ColumnsState extends CommonChartState {
preparedData: Observation[];
allData: Observation[];
getX: (d: Observation) => string;
getXLabel: (d: string) => string;
getXAsDate: (d: Observation) => Date;
xIsTime: boolean;
timeUnit: TimeUnit | undefined;
Expand Down Expand Up @@ -113,10 +112,42 @@ const useColumnsState = (
? (xDimension as TemporalDimension).timeUnit
: undefined;

const { getAbbreviationOrLabelByValue: getX } = useMaybeAbbreviations({
useAbbreviations: fields.x.useAbbreviations ?? false,
dimension: xDimension,
});
const { getAbbreviationOrLabelByValue: getXLabelOrAbbrevation } =
useMaybeAbbreviations({
useAbbreviations: fields.x.useAbbreviations ?? false,
dimension: xDimension,
});

const getXIri = useCallback(
(d: Observation) => {
return d[`${fields.x.componentIri}/__iri__`] as string | undefined;
},
[fields.x.componentIri]
);

const observationLabelsLookup = useMemo(() => {
const lookup = new Map<string, string>();
data.forEach((d) => {
const label = getXLabelOrAbbrevation(d);
const iri = getXIri(d);
lookup.set(iri ?? label, label);
});

return lookup;
}, [data, getXLabelOrAbbrevation, getXIri]);

const getX = useCallback(
(d: Observation) => {
return getXIri(d) ?? getXLabelOrAbbrevation(d);
},
[getXIri, getXLabelOrAbbrevation]
);
const getXLabel = useCallback(
(d: string) => {
return observationLabelsLookup.get(d) ?? d;
},
[observationLabelsLookup]
);

const getXAsDate = useTemporalVariable(fields.x.componentIri);
const getY = useOptionalNumericVariable(fields.y.componentIri);
Expand All @@ -131,7 +162,13 @@ const useColumnsState = (

// All data
const sortedData = useMemo(() => {
return sortData({ data, sortingType, sortingOrder, getX, getY });
return sortData({
data,
sortingType,
sortingOrder,
getX,
getY,
});
}, [data, getX, getY, sortingType, sortingOrder]);

// Data
Expand All @@ -155,7 +192,7 @@ const useColumnsState = (
sorting: fields.x.sorting,
useAbbreviations: fields.x.useAbbreviations,
dimensionFilter: xDimension?.iri
? chartConfig.filters[xDimension?.iri]
? chartConfig.filters[xDimension.iri]
: undefined,
});
const sortingOrders = getSortingOrders(sorters, fields.x.sorting);
Expand Down Expand Up @@ -195,7 +232,14 @@ const useColumnsState = (
);

const yScale = scaleLinear().domain([minValue, maxValue]).nice();
return { xScale, yScale, xEntireScale, xScaleInteraction, bandDomain };

return {
xScale,
yScale,
xEntireScale,
xScaleInteraction,
bandDomain,
};
}, [
getX,
getXAsDate,
Expand Down Expand Up @@ -258,10 +302,10 @@ const useColumnsState = (
}, []);

// Tooltip
const getAnnotationInfo = (datum: Observation): TooltipInfo => {
const xRef = xScale(getX(datum)) as number;
const getAnnotationInfo = (d: Observation): TooltipInfo => {
const xRef = xScale(getX(d)) as number;
const xOffset = xScale.bandwidth() / 2;
const yRef = yScale(Math.max(getY(datum) ?? NaN, 0));
const yRef = yScale(Math.max(getY(d) ?? NaN, 0));
const yAnchor = yRef;

const yPlacement = "top";
Expand All @@ -285,6 +329,7 @@ const useColumnsState = (
: xRef + xOffset * 2;
};
const xAnchor = getXAnchor();
const xLabel = getXLabelOrAbbrevation(d);

const yValueFormatter = (value: number | null) =>
formatNumberWithUnit(
Expand All @@ -297,17 +342,14 @@ const useColumnsState = (
xAnchor,
yAnchor,
placement: { x: xPlacement, y: yPlacement },
xValue:
xIsTime && timeUnit
? timeFormatUnit(getX(datum), timeUnit)
: getX(datum),
xValue: xIsTime && timeUnit ? timeFormatUnit(xLabel, timeUnit) : xLabel,
datum: {
label: fields.segment?.componentIri && getSegment(datum),
value: `${yValueFormatter(getY(datum))}`,
label: fields.segment?.componentIri && getSegment(d),
value: `${yValueFormatter(getY(d))}`,
error: getYError
? `${getYError(datum)}${errorMeasure?.unit ?? ""}`
? `${getYError(d)}${errorMeasure?.unit ?? ""}`
: undefined,
color: colors(getSegment(datum)) as string,
color: colors(getSegment(d)) as string,
},
values: undefined,
};
Expand All @@ -319,6 +361,7 @@ const useColumnsState = (
preparedData,
allData: plottableSortedData,
getX,
getXLabel,
getXAsDate,
xScale,
xEntireScale,
Expand Down
8 changes: 4 additions & 4 deletions app/charts/shared/axis-width-band.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { axisBottom } from "d3";
import { select, Selection } from "d3";
import { axisBottom, select, Selection } from "d3";
import { useEffect, useRef } from "react";

import { ColumnsState } from "@/charts/column/columns-state";
Expand All @@ -9,7 +8,7 @@ import { useTimeFormatUnit } from "@/formatters";

export const AxisWidthBand = () => {
const ref = useRef<SVGGElement>(null);
const { xScale, yScale, bounds, xIsTime, timeUnit } =
const { xScale, yScale, bounds, xIsTime, timeUnit, getXLabel } =
useChartState() as ColumnsState;

const formatDate = useTimeFormatUnit();
Expand All @@ -29,8 +28,9 @@ export const AxisWidthBand = () => {

if (xIsTime && timeUnit) {
axis.tickFormat((d) => formatDate(d, timeUnit));
} else {
axis.tickFormat((d) => getXLabel(d));
}

const fontSize =
xScale.bandwidth() > labelFontSize ? labelFontSize : xScale.bandwidth();

Expand Down

0 comments on commit fa3317e

Please sign in to comment.