Skip to content

Commit

Permalink
Fix landing chart data labels
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickCleary committed Feb 5, 2025
1 parent dc7a0bf commit eea22bb
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 28 deletions.
8 changes: 7 additions & 1 deletion common/constants/charts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export const DATA_LABELS_LANDING: LabelOptions = {
font: {
size: 12,
},
display: (context) => context.dataIndex === context.dataset.data.length - 1,
display: (context) => {
const lastNonNullIndex = context.dataset.data.reduce(
(lastIndex, item, index) => (item != null ? index : lastIndex),
-1
);
return context.dataIndex === lastNonNullIndex;
},
formatter: (value) => `${value}%`, // Format the label content
};
6 changes: 3 additions & 3 deletions modules/landing/charts/OverallRidershipChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import React from 'react';
import type { RidershipCount } from '../../../common/types/dataPoints';
import { RidershipBaseline } from '../../../copy/landingCopy';
import type { Line as LineType } from '../../../common/types/lines';
import { convertToRidershipDataset } from '../utils';
import { convertToRidershipDataset, LANDING_CHART_LABELS } from '../utils';
import { LandingChartDiv } from '../LandingChartDiv';
import { LandingPageChart } from './LandingPageChart';

interface OverallRidershipChartProps {
ridershipData: { [key in LineType]: RidershipCount[] };
}
export const OverallRidershipChart: React.FC<OverallRidershipChartProps> = ({ ridershipData }) => {
const labels = Object.values(ridershipData)[0].map((point) => point.date);
const datasets = convertToRidershipDataset(ridershipData);
const labels = LANDING_CHART_LABELS;
const datasets = convertToRidershipDataset(ridershipData, labels);

return (
<LandingChartDiv>
Expand Down
6 changes: 3 additions & 3 deletions modules/landing/charts/OverallServiceChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import type { DeliveredTripMetrics } from '../../../common/types/dataPoints';
import type { Line } from '../../../common/types/lines';
import { ServiceBaseline } from '../../../copy/landingCopy';
import { LandingChartDiv } from '../LandingChartDiv';
import { convertToServiceDataset } from '../utils';
import { convertToServiceDataset, LANDING_CHART_LABELS } from '../utils';
import { LandingPageChart } from './LandingPageChart';

interface OverallServiceChartProps {
serviceData: { [key in Line]?: DeliveredTripMetrics[] };
}
export const OverallServiceChart: React.FC<OverallServiceChartProps> = ({ serviceData }) => {
const labels = Object.values(serviceData)[0].map((point) => point.date);
const datasets = convertToServiceDataset(serviceData);
const labels = LANDING_CHART_LABELS;
const datasets = convertToServiceDataset(serviceData, labels);

return (
<LandingChartDiv>
Expand Down
6 changes: 3 additions & 3 deletions modules/landing/charts/OverallSpeedChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import type { DeliveredTripMetrics } from '../../../common/types/dataPoints';
import { SpeedBaseline } from '../../../copy/landingCopy';
import type { Line } from '../../../common/types/lines';
import { LandingChartDiv } from '../LandingChartDiv';
import { convertToSpeedDataset } from '../utils';
import { convertToSpeedDataset, LANDING_CHART_LABELS } from '../utils';
import { LandingPageChart } from './LandingPageChart';

interface OverallSpeedChartProps {
speedData: { [key in Line]?: DeliveredTripMetrics[] };
}
export const OverallSpeedChart: React.FC<OverallSpeedChartProps> = ({ speedData }) => {
const labels = Object.values(speedData)[0].map((point) => point.date);
const datasets = convertToSpeedDataset(speedData);
const labels = LANDING_CHART_LABELS

Check failure on line 13 in modules/landing/charts/OverallSpeedChart.tsx

View workflow job for this annotation

GitHub Actions / frontend (20, 3.12)

Insert `;`
const datasets = convertToSpeedDataset(speedData, labels);
return (
<LandingChartDiv>
<LandingPageChart datasets={datasets} labels={labels} id="system-speed" />
Expand Down
72 changes: 54 additions & 18 deletions modules/landing/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ChartDataset } from 'chart.js';
import { round } from 'lodash';
import dayjs from 'dayjs';
import {
PEAK_RIDERSHIP,
PEAK_SCHEDULED_SERVICE,
Expand All @@ -10,6 +11,7 @@ import type { RidershipCount, DeliveredTripMetrics } from '../../common/types/da
import type { Line } from '../../common/types/lines';
import type { AggregateDataPoint, SingleDayDataPoint } from '../../common/types/charts';
import { getStationDistance } from '../../common/utils/stations';
import { DATE_FORMAT } from '../../common/constants/dates';

const getDatasetOptions = (line: Line): Partial<ChartDataset<'line'>> => {
return {
Expand All @@ -29,7 +31,10 @@ const getDatasetOptions = (line: Line): Partial<ChartDataset<'line'>> => {
};
};

export const convertToSpeedDataset = (data: { [key in Line]?: DeliveredTripMetrics[] }) => {
export const convertToSpeedDataset = (
data: { [key in Line]?: DeliveredTripMetrics[] },
labels: string[]
) => {
return Object.keys(data).map((line: Line) => {
// We don't need to show the Mattapan line on the landing page
if (line === 'line-mattapan') {
Expand All @@ -40,14 +45,18 @@ export const convertToSpeedDataset = (data: { [key in Line]?: DeliveredTripMetri
return {
...datasetOptions,
data:
data[line]?.map((datapoint) =>
datapoint.miles_covered
labels?.map((label) => {
const datapoint = data[line]?.find((datapoint) => datapoint.date === label);
if (!datapoint) {
return null;
}
return datapoint.miles_covered
? round(
(100 * datapoint.miles_covered) / (datapoint.total_time / 3600) / PEAK_SPEED[line],
1
)
: Number.NaN
) ?? [],
(100 * datapoint.miles_covered) / (datapoint.total_time / 3600) / PEAK_SPEED[line],

Check failure on line 55 in modules/landing/utils.ts

View workflow job for this annotation

GitHub Actions / frontend (20, 3.12)

Insert `··`
1

Check failure on line 56 in modules/landing/utils.ts

View workflow job for this annotation

GitHub Actions / frontend (20, 3.12)

Insert `··`
)

Check failure on line 57 in modules/landing/utils.ts

View workflow job for this annotation

GitHub Actions / frontend (20, 3.12)

Insert `··`
: null;
}) ?? [],
};
});
};
Expand Down Expand Up @@ -100,7 +109,10 @@ export const convertToAggregateStationSpeedDataset = (
return ret;
};

export const convertToServiceDataset = (data: { [key in Line]?: DeliveredTripMetrics[] }) => {
export const convertToServiceDataset = (
data: { [key in Line]?: DeliveredTripMetrics[] },
labels: string[]
) => {
return Object.keys(data).map((line: Line) => {
// We don't need to show the Mattapan line on the landing page
if (line === 'line-mattapan') {
Expand All @@ -111,16 +123,21 @@ export const convertToServiceDataset = (data: { [key in Line]?: DeliveredTripMet
return {
...datasetOptions,
data:
data[line]?.map((datapoint) =>
datapoint.miles_covered
labels.map((label) => {
const datapoint = data[line]?.find((datapoint) => datapoint.date === label);
if (!datapoint) return null;
return datapoint.miles_covered
? round((100 * datapoint.count) / PEAK_SCHEDULED_SERVICE[line], 1)
: Number.NaN
) ?? [],
: null;
}) ?? [],
};
});
};

export const convertToRidershipDataset = (data: { [key in Line]: RidershipCount[] }) => {
export const convertToRidershipDataset = (
data: { [key in Line]: RidershipCount[] },
labels: string[]
) => {
return (
Object.keys(data).map((line: Line) => {
// We don't need to show the Mattapan line on the landing page
Expand All @@ -131,12 +148,31 @@ export const convertToRidershipDataset = (data: { [key in Line]: RidershipCount[
const datasetOptions = getDatasetOptions(line);
return {
...datasetOptions,
data: data[line]?.map((datapoint) =>
datapoint.count
data: labels.map((labels) => {
const datapoint = data[line]?.find((datapoint) => datapoint.date === labels);
if (!datapoint) return null;
return datapoint.count
? Math.round(10 * 100 * (datapoint.count / PEAK_RIDERSHIP[line])) / 10
: Number.NaN
),
: null;
}),
};
}) ?? []
);
};

const getLabels = () => {
// Get the most recent Monday. This date may or may not be in the dataset, but we can still use it to construct the labels.
// It's important to use Monday, that is the day the weekly trip metrics are based on.
const latestDate: dayjs.Dayjs = dayjs().startOf('week').add(1, 'day');

// Generate the labels for the last 14 weeks, starting from the most recent Monday.
// The endpoint returns 12 weeks, but we add 2 extra weeks in case the past Monday is not in the dataset.
// There's no harm in having extra labels.
const labels: string[] = [];
for (let i = 13; i >= 0; i--) {
labels.push(latestDate.subtract(i, 'weeks').format(DATE_FORMAT));
}
return labels;
};

export const LANDING_CHART_LABELS = getLabels();

0 comments on commit eea22bb

Please sign in to comment.