Skip to content

Commit

Permalink
feat ⚡️: dots on line chart
Browse files Browse the repository at this point in the history
  • Loading branch information
squiles committed Jan 13, 2025
1 parent 03585ef commit 035a330
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 2 deletions.
9 changes: 9 additions & 0 deletions app/charts/chart-config-ui-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ type EncodingOption<T extends ChartConfig = ChartConfig> =
| {
field: "sorting";
}
| {
field: "showDots";
}
| {
field: "showDotsSize";
}
| {
field: "size";
componentTypes: ComponentType[];
Expand Down Expand Up @@ -802,6 +808,7 @@ const chartConfigOptionsUISpec: ChartSpecs = {
},
options: {
showStandardError: {},
showConfidenceInterval: {},
},
},
{
Expand Down Expand Up @@ -937,6 +944,8 @@ const chartConfigOptionsUISpec: ChartSpecs = {
options: {
showStandardError: {},
showConfidenceInterval: {},
showDots: {},
showDotsSize: {},
},
},
{
Expand Down
3 changes: 2 additions & 1 deletion app/charts/line/chart-lines.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { memo } from "react";

import { ChartDataWrapper } from "@/charts/chart-data-wrapper";
import { ErrorWhiskers, Lines } from "@/charts/line/lines";
import { ErrorWhiskers, Lines, Points } from "@/charts/line/lines";
import { LineChart } from "@/charts/line/lines-state";
import { AxisHeightLinear } from "@/charts/shared/axis-height-linear";
import { AxisTime, AxisTimeDomain } from "@/charts/shared/axis-width-time";
Expand Down Expand Up @@ -37,6 +37,7 @@ const ChartLines = memo((props: ChartProps<LineConfig>) => {
<ChartSvg>
<AxisHeightLinear /> <AxisTime /> <AxisTimeDomain />
<Lines />
<Points chartConfig={chartConfig} />
<ErrorWhiskers />
<InteractionHorizontal />
{shouldShowBrush(
Expand Down
71 changes: 71 additions & 0 deletions app/charts/line/lines.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { bisector } from "d3-array";
import { line } from "d3-shape";
import { Fragment, memo, useEffect, useMemo, useRef } from "react";

Expand All @@ -8,6 +9,7 @@ import {
renderContainer,
renderVerticalWhiskers,
} from "@/charts/shared/rendering-utils";
import { LineConfig } from "@/config-types";
import { Observation } from "@/domain/data";
import { useTransitionStore } from "@/stores/transition";

Expand Down Expand Up @@ -122,3 +124,72 @@ const Line = memo(function Line({
}) {
return <path d={path} stroke={color} fill="none" />;
});

const getPointRadius = (chartConfig: LineConfig) => {
const { showDotsSize } = chartConfig.fields.y;
switch (showDotsSize) {
case "Small":
return 2;
case "Medium":
return 3;
case "Large":
return 4;
case undefined:
return 2;
default:
const _check: never = showDotsSize;

Check failure on line 140 in app/charts/line/lines.tsx

View workflow job for this annotation

GitHub Actions / base-checks (typecheck)

'_check' is declared but its value is never read.
return 2;
}
};

export const Points = ({ chartConfig }: { chartConfig: LineConfig }) => {
const { getX, xScale, getY, yScale, bounds, chartData, getSegment, colors } =
useChartState() as LinesState;

const { showDots } = chartConfig.fields.y;

const { margins, chartHeight, width } = bounds;

const ticksPos = useMemo(() => {
return xScale.ticks(bounds.chartWidth / 90).map((tick) => {
const x = xScale(tick);
const date = xScale.invert(x);

const bisectDate = bisector(
(d: Observation, date: Date) => getX(d).getTime() - date.getTime()
).center;

const i = bisectDate(chartData, date, 1);
const y = yScale(getY(chartData[i]) as number);

const segment = getSegment(chartData[i]);
const color = colors(segment);

return { x, y, color };
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
width,
chartHeight,
xScale,
yScale,
getY,
bounds.chartWidth,
chartData,
getX,
]);

if (!showDots) {
return null;
}

const radius = getPointRadius(chartConfig);

return (
<g transform={`translate(${margins.left} ${margins.top})`}>
{ticksPos.map(({ x, y, color }, i) => (
<circle key={i} cx={x} cy={y} r={radius} fill={color} />
))}
</g>
);
};
13 changes: 12 additions & 1 deletion app/config-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,18 @@ export type LineSegmentField = t.TypeOf<typeof LineSegmentField>;
const LineFields = t.intersection([
t.type({
x: GenericField,
y: t.intersection([GenericField, UncertaintyFieldExtension]),
y: t.intersection([
GenericField,
UncertaintyFieldExtension,
t.partial({
showDots: t.boolean,
showDotsSize: t.union([
t.literal("Small"),
t.literal("Medium"),
t.literal("Large"),
]),
}),
]),
}),
t.partial({
segment: LineSegmentField,
Expand Down
37 changes: 37 additions & 0 deletions app/configurator/components/chart-options-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,43 @@ const EncodingOptionsPanel = (props: EncodingOptionsPanelProps) => {
</ControlSectionContent>
</ControlSection>
)}
{encoding.options?.showDots && (
<ControlSection collapse>
<SubsectionTitle iconName="chartLine">
<Trans id="controls.section.data-points">Data Points</Trans>
</SubsectionTitle>
<ControlSectionContent>
<Stack direction="column" gap={4}>
<ChartOptionSwitchField
path="showDots"
field={encoding.field}
defaultValue
label={t({ id: "controls.section.show-dots" })}
sx={{ mt: 2 }}
/>
<Typography variant="caption" sx={{ mt: 2 }}>
<Trans id="controls.section.dots-size">Select a Size</Trans>
</Typography>
<Flex justifyContent="flex-start">
{["Small", "Medium", "Large"].map((d) => (
<ChartOptionRadioField
key={d}
label={`${d}`}
field="y"
path="showDotsSize"
value={d}
disabled={
"y" in fields &&
"showDots" in fields.y &&
!fields.y.showDots
}
/>
))}
</Flex>
</Stack>
</ControlSectionContent>
</ControlSection>
)}
{isComboChartConfig(chartConfig) && encoding.field === "y" && (
<ChartComboYField chartConfig={chartConfig} measures={measures} />
)}
Expand Down
24 changes: 24 additions & 0 deletions app/locales/de/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@ msgstr "Horizontale Achse"
msgid "controls.axis.vertical"
msgstr "Vertikale Achse"

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.grouped"
msgstr ""

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.stacked"
msgstr ""

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.calculation.disabled-by-grouped"
msgstr "Der 100%-Modus kann nicht mit einem gruppierten Layout verwendet werden."
Expand Down Expand Up @@ -828,6 +837,10 @@ msgstr "Spalten"
msgid "controls.section.columnstyle"
msgstr "Spaltenstil"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.data-points"
msgstr "Datenpunkte"

#: app/components/chart-filters-list.tsx
#: app/components/chart-filters-list.tsx
#: app/configurator/components/chart-configurator.tsx
Expand All @@ -852,6 +865,10 @@ msgstr "Datensätze"
msgid "controls.section.description"
msgstr "Titel & Beschreibung"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.dots-size"
msgstr "Wählen Sie eine Größe"

#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/table/table-chart-options.tsx
Expand Down Expand Up @@ -901,6 +918,10 @@ msgstr "Konfidenzintervall anzeigen"
msgid "controls.section.show-confidence-interval.explanation"
msgstr "Zeigen Sie Unsicherheiten an, die sich aus Datenpunkten ergeben, um Konfidenzintervalle darzustellen"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-dots"
msgstr "Datenpunkte anzeigen"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-standard-error"
msgstr "Standardfehler anzeigen"
Expand Down Expand Up @@ -934,6 +955,7 @@ msgstr "Fügen Sie einen Titel oder eine Beschreibung hinzu"
msgid "controls.segment"
msgstr "Segmentierung"

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.segment.stacked.disabled-by-scale-type"
Expand Down Expand Up @@ -1545,6 +1567,8 @@ msgid "logo.swiss.confederation"
msgstr "Logo der Schweizerischen Eidgenossenschaft"

#: app/components/chart-footnotes.tsx
#: app/components/chart-published.tsx
#: app/components/chart-shared.tsx
msgid "metadata.link.created.with"
msgstr "Erstellt mit"

Expand Down
24 changes: 24 additions & 0 deletions app/locales/en/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@ msgstr "Horizontal Axis"
msgid "controls.axis.vertical"
msgstr "Vertical Axis"

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.grouped"
msgstr "Grouped"

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.stacked"
msgstr "Stacked"

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.calculation.disabled-by-grouped"
msgstr "100% mode can't be used with grouped layout."
Expand Down Expand Up @@ -828,6 +837,10 @@ msgstr "Columns"
msgid "controls.section.columnstyle"
msgstr "Column Style"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.data-points"
msgstr "Data Points"

#: app/components/chart-filters-list.tsx
#: app/components/chart-filters-list.tsx
#: app/configurator/components/chart-configurator.tsx
Expand All @@ -852,6 +865,10 @@ msgstr "Datasets"
msgid "controls.section.description"
msgstr "Title & Description"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.dots-size"
msgstr "Select a Size"

#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/table/table-chart-options.tsx
Expand Down Expand Up @@ -901,6 +918,10 @@ msgstr "Show confidence interval"
msgid "controls.section.show-confidence-interval.explanation"
msgstr "Show uncertainties extending from data points to represent confidence intervals"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-dots"
msgstr "Show Data Points"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-standard-error"
msgstr "Show standard error"
Expand Down Expand Up @@ -934,6 +955,7 @@ msgstr "Please add a title or description."
msgid "controls.segment"
msgstr "Segmentation"

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.segment.stacked.disabled-by-scale-type"
Expand Down Expand Up @@ -1545,6 +1567,8 @@ msgid "logo.swiss.confederation"
msgstr "Logo of the Swiss Confederation"

#: app/components/chart-footnotes.tsx
#: app/components/chart-published.tsx
#: app/components/chart-shared.tsx
msgid "metadata.link.created.with"
msgstr "Created with"

Expand Down
24 changes: 24 additions & 0 deletions app/locales/fr/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@ msgstr "Axe horizontal"
msgid "controls.axis.vertical"
msgstr "Axe vertical"

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.grouped"
msgstr ""

#: app/configurator/components/field-i18n.ts
msgid "controls.bar.stacked"
msgstr ""

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.calculation.disabled-by-grouped"
msgstr "Le mode 100% ne peut pas être utilisé avec une mise en page groupée."
Expand Down Expand Up @@ -828,6 +837,10 @@ msgstr "Colonnes"
msgid "controls.section.columnstyle"
msgstr "Style de la colonne"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.data-points"
msgstr "Points de données"

#: app/components/chart-filters-list.tsx
#: app/components/chart-filters-list.tsx
#: app/configurator/components/chart-configurator.tsx
Expand All @@ -852,6 +865,10 @@ msgstr "Ensembles de données"
msgid "controls.section.description"
msgstr "Titre & description"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.dots-size"
msgstr "Sélectionner une taille"

#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/components/chart-options-selector.tsx
#: app/configurator/table/table-chart-options.tsx
Expand Down Expand Up @@ -901,6 +918,10 @@ msgstr "Afficher l'intervalle de confiance"
msgid "controls.section.show-confidence-interval.explanation"
msgstr "Afficher les incertitudes s'étendant des points de données pour représenter les intervalles de confiance"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-dots"
msgstr "Afficher les points de données"

#: app/configurator/components/chart-options-selector.tsx
msgid "controls.section.show-standard-error"
msgstr "Afficher l'erreur type"
Expand Down Expand Up @@ -934,6 +955,7 @@ msgstr "Ajoutez un titre et une description"
msgid "controls.segment"
msgstr "Segmentation"

#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
#: app/charts/chart-config-ui-options.ts
msgid "controls.segment.stacked.disabled-by-scale-type"
Expand Down Expand Up @@ -1545,6 +1567,8 @@ msgid "logo.swiss.confederation"
msgstr "Logo de la Confédération Suisse"

#: app/components/chart-footnotes.tsx
#: app/components/chart-published.tsx
#: app/components/chart-shared.tsx
msgid "metadata.link.created.with"
msgstr "Créé avec"

Expand Down
Loading

0 comments on commit 035a330

Please sign in to comment.