Skip to content

Commit

Permalink
feat(components): number of sequences over time: implement bar chart …
Browse files Browse the repository at this point in the history
…view

closes #316
  • Loading branch information
fengelniederhammer committed Jul 12, 2024
1 parent 83b0868 commit f7af2c9
Show file tree
Hide file tree
Showing 14 changed files with 1,999 additions and 295 deletions.
1,640 changes: 1,354 additions & 286 deletions components/src/preact/numberSequencesOverTime/__mockData__/twoVariantsEG.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { NumberOfSequencesDatasets } from '../../query/queryNumberOfSequencesOverTime';
import type { TemporalGranularity } from '../../types';
import { generateAllInRange, getMinMaxTemporal, type Temporal } from '../../utils/temporal';

export const getNumberOfSequencesOverTimeTableData = (
type TableRow<DateRangeKey extends string> = { [K in DateRangeKey]: string } & { [key: string]: number };

export const getNumberOfSequencesOverTimeTableData = <DateRangeKey extends string>(
data: NumberOfSequencesDatasets,
granularity: TemporalGranularity,
dateRangeKey: DateRangeKey,
) => {
const datasetsWithCountByDate = data.map(({ displayName, content }) => ({
displayName,
Expand Down Expand Up @@ -32,7 +33,7 @@ export const getNumberOfSequencesOverTimeTableData = (
...acc,
[dataset.displayName]: dataset.content.get(dateRange?.toString())?.count ?? 0,
}),
{ [granularity]: dateRange?.toString() ?? 'Unknown' } as Record<string, number | string>,
{ [dateRangeKey]: dateRange?.toString() ?? 'Unknown' } as TableRow<DateRangeKey>,
);
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Chart, type ChartConfiguration, type ChartDataset, registerables } from 'chart.js';
import { useMemo } from 'preact/hooks';

import { getNumberOfSequencesOverTimeTableData } from './getNumberOfSequencesOverTimeTableData';
import { type NumberOfSequencesDatasets } from '../../query/queryNumberOfSequencesOverTime';
import GsChart from '../components/chart';
import { singleGraphColorRGBAById } from '../shared/charts/colors';

interface NumberSequencesOverBarChartProps {
data: NumberOfSequencesDatasets;
}

Chart.register(...registerables);

export const NumberSequencesOverTimeBarChart = ({ data }: NumberSequencesOverBarChartProps) => {
const config: ChartConfiguration = useMemo(
() => ({
type: 'bar',
data: {
datasets: getDatasets(data),
},
options: {
maintainAspectRatio: false,
animation: false,
plugins: {
legend: {
display: false,
},
tooltip: {
mode: 'index',
intersect: false,
},
},
},
}),
[data],
);

return <GsChart configuration={config} />;
};

const getDatasets = (data: NumberOfSequencesDatasets) => {
const tableData = getNumberOfSequencesOverTimeTableData(data, 'date');

return data.map(
({ displayName }, index) =>
({
borderWidth: 1,
label: displayName,
backgroundColor: singleGraphColorRGBAById(index, 0.3),
borderColor: singleGraphColorRGBAById(index),
data: tableData.map((row) => ({
x: row.date,
y: row[displayName],
})),
}) as ChartDataset<'bar', { x: string; y: number }[]>,
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useContext } from 'preact/hooks';

import { NumberSequencesOverTimeBarChart } from './number-sequences-over-time-bar-chart';
import { NumberSequencesOverTimeTable } from './number-sequences-over-time-table';
import {
type NumberOfSequencesDatasets,
Expand Down Expand Up @@ -87,7 +88,7 @@ const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }: Num
const getTab = (view: NumberSequencesOverTimeView) => {
switch (view) {
case 'bar':
return { title: 'Bar', content: <div>not implemented, TODO #316</div> };
return { title: 'Bar', content: <NumberSequencesOverTimeBarChart data={data} /> };
case 'line':
return { title: 'Line', content: <div>not implemented, TODO #317</div> };
case 'table':
Expand Down
1 change: 1 addition & 0 deletions components/src/query/queryNumberOfSequencesOverTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sortNullToBeginningThenByDate } from '../utils/sort';
import { makeArray } from '../utils/utils';

export type NumberOfSequencesDatasets = Awaited<ReturnType<typeof queryNumberOfSequencesOverTime>>;
export type NumberOfSequencesDataset = NumberOfSequencesDatasets[number];

export async function queryNumberOfSequencesOverTime(
lapis: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
import oneVariantEG from '../../preact/numberSequencesOverTime/__mockData__/oneVariantEG.json';
import twoVariantsEG from '../../preact/numberSequencesOverTime/__mockData__/twoVariantsEG.json';
import twoVariantsJN1 from '../../preact/numberSequencesOverTime/__mockData__/twoVariantsJN1.json';
import twoVariantsXBB from '../../preact/numberSequencesOverTime/__mockData__/twoVariantsXBB.json';
import type { NumberSequencesOverTimeProps } from '../../preact/numberSequencesOverTime/number-sequences-over-time';
import { withinShadowRoot } from '../withinShadowRoot.story';

Expand Down Expand Up @@ -104,12 +105,23 @@ const Template: StoryObj<NumberSequencesOverTimeProps> = {
},
};

export const OneDatasetBarChart: StoryObj<NumberSequencesOverTimeProps> = {
...Template,
play: async ({ canvasElement }) => {
const canvas = await withinShadowRoot(canvasElement, 'gs-number-sequences-over-time');

await waitFor(() => expect(canvas.getByRole('button', { name: 'Bar' })).toBeVisible());

await fireEvent.click(canvas.getByRole('button', { name: 'Bar' }));
},
};

export const OneDatasetTable: StoryObj<NumberSequencesOverTimeProps> = {
...Template,
play: async ({ canvasElement }) => {
const canvas = await withinShadowRoot(canvasElement, 'gs-number-sequences-over-time');

await waitFor(() => expect(canvas.getByRole('button', { name: 'Table' })).toBeInTheDocument());
await waitFor(() => expect(canvas.getByRole('button', { name: 'Table' })).toBeVisible());

await fireEvent.click(canvas.getByRole('button', { name: 'Table' }));
},
Expand All @@ -121,8 +133,8 @@ export const TwoDatasets: StoryObj<NumberSequencesOverTimeProps> = {
...Template.args,
lapisFilter: [
{
displayName: 'EG until 2023-06',
lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateTo: '2023-06-30' },
displayName: 'EG',
lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateFrom: '2022-10-01' },
},
{ displayName: 'JN.1', lapisFilter: { country: 'USA', pangoLineage: 'JN.1*', dateFrom: '2023-01-01' } },
],
Expand All @@ -137,7 +149,6 @@ export const TwoDatasets: StoryObj<NumberSequencesOverTimeProps> = {
body: {
country: 'USA',
pangoLineage: 'EG*',
dateTo: '2023-06-30',
fields: ['date'],
},
},
Expand Down Expand Up @@ -166,3 +177,56 @@ export const TwoDatasets: StoryObj<NumberSequencesOverTimeProps> = {
},
},
};

export const TwoDatasetsWithNonOverlappingDates: StoryObj<NumberSequencesOverTimeProps> = {
...Template,
args: {
...Template.args,
lapisFilter: [
{
displayName: 'XBB',
lapisFilter: { country: 'USA', pangoLineage: 'XBB*', dateFrom: '2022-01-01', dateTo: '2022-12-31' },
},
{ displayName: 'JN.1', lapisFilter: { country: 'USA', pangoLineage: 'JN.1*', dateFrom: '2023-01-01' } },
],
},
parameters: {
fetchMock: {
mocks: [
{
matcher: {
name: 'aggregatedEG',
url: AGGREGATED_ENDPOINT,
body: {
country: 'USA',
pangoLineage: 'XBB*',
dateFrom: '2022-01-01',
dateTo: '2022-12-31',
fields: ['date'],
},
},
response: {
status: 200,
body: twoVariantsXBB,
},
},
{
matcher: {
name: 'aggregatedJN.1',
url: AGGREGATED_ENDPOINT,
body: {
country: 'USA',
pangoLineage: 'JN.1*',
dateFrom: '2023-01-01',
fields: ['date'],
},
},
response: {
status: 200,
body: twoVariantsJN1,
},
},
],
},
},
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions components/tests/visualizationStories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export const visualizationStories = [
},
{ id: 'visualization-mutation-comparison--venn-diagram', title: 'Mutation comparison' },
{ id: 'visualization-aggregate--table', title: 'Aggregate', testDownloadWithFilename: 'aggregate.csv' },
{ id: 'visualization-number-sequences-over-time--one-dataset-bar-chart', title: 'Number of sequences of time' },
{ id: 'visualization-number-sequences-over-time--one-dataset-table', title: 'Number of sequences of time' },
{ id: 'visualization-number-sequences-over-time--two-datasets', title: 'Number of sequences of time' },
{
id: 'visualization-number-sequences-over-time--two-datasets-with-non-overlapping-dates',
title: 'Number of sequences of time',
},
];

0 comments on commit f7af2c9

Please sign in to comment.