@genspectrum/dashboard-components 0.10.4 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +58 -58
- package/dist/components.d.ts +82 -32
- package/dist/components.js +57 -65
- package/dist/components.js.map +1 -1
- package/dist/{dateRangeOption-Doo6WHKu.js → dateRangeOption-Bh2p78z0.js} +9 -4
- package/dist/dateRangeOption-Bh2p78z0.js.map +1 -0
- package/dist/util.d.ts +623 -14
- package/dist/util.js +1 -1
- package/package.json +5 -5
- package/src/preact/aggregatedData/aggregate.stories.tsx +1 -1
- package/src/preact/aggregatedData/aggregate.tsx +11 -8
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +3 -11
- package/src/preact/dateRangeSelector/date-range-selector.tsx +4 -4
- package/src/preact/mutationComparison/mutation-comparison.tsx +4 -6
- package/src/preact/mutationFilter/mutation-filter.tsx +4 -13
- package/src/preact/mutations/mutations.tsx +4 -4
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +4 -4
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.stories.tsx +4 -13
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +4 -4
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +14 -25
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +8 -8
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -14
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +11 -7
- package/src/query/queryNumberOfSequencesOverTime.spec.ts +4 -4
- package/src/query/queryNumberOfSequencesOverTime.ts +1 -4
- package/src/query/queryPrevalenceOverTime.ts +1 -4
- package/src/types.ts +11 -4
- package/src/utilEntrypoint.ts +17 -4
- package/src/utils/utils.ts +0 -29
- package/src/web-components/app.ts +1 -1
- package/src/web-components/input/gs-date-range-selector.stories.ts +4 -4
- package/src/web-components/input/gs-date-range-selector.tsx +5 -5
- package/src/web-components/input/gs-lineage-filter.tsx +1 -1
- package/src/web-components/input/gs-location-filter.tsx +1 -1
- package/src/web-components/input/gs-mutation-filter.tsx +5 -8
- package/src/web-components/input/gs-text-input.tsx +1 -1
- package/src/web-components/visualization/gs-aggregate.stories.ts +3 -3
- package/src/web-components/visualization/gs-aggregate.tsx +10 -6
- package/src/web-components/visualization/gs-mutation-comparison.tsx +7 -2
- package/src/web-components/visualization/gs-mutations-over-time.tsx +7 -2
- package/src/web-components/visualization/gs-mutations.tsx +7 -2
- package/src/web-components/visualization/gs-number-sequences-over-time.stories.ts +5 -5
- package/src/web-components/visualization/gs-number-sequences-over-time.tsx +13 -15
- package/src/web-components/visualization/gs-prevalence-over-time.stories.ts +8 -8
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +17 -14
- package/src/web-components/visualization/gs-relative-growth-advantage.stories.ts +4 -5
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +17 -15
- package/src/web-components/visualization/gs-sequences-by-location.tsx +6 -1
- package/src/web-components/visualization/gs-statistics.tsx +12 -3
- package/standalone-bundle/dashboard-components.js +2520 -2516
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/dateRangeOption-Doo6WHKu.js.map +0 -1
- package/src/utils/utils.spec.ts +0 -16
package/dist/util.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
"./components": {
|
|
31
|
+
"types": "./dist/components.d.ts",
|
|
31
32
|
"import": "./dist/components.js",
|
|
32
|
-
"require": "./dist/components.js"
|
|
33
|
-
"types": "./dist/components.d.ts"
|
|
33
|
+
"require": "./dist/components.js"
|
|
34
34
|
},
|
|
35
35
|
"./util": {
|
|
36
|
+
"types": "./dist/util.d.ts",
|
|
36
37
|
"import": "./dist/util.js",
|
|
37
|
-
"require": "./dist/util.js"
|
|
38
|
-
"types": "./dist/util.d.ts"
|
|
38
|
+
"require": "./dist/util.js"
|
|
39
39
|
},
|
|
40
40
|
"./custom-elements.json": "./custom-elements.json",
|
|
41
41
|
"./package.json": "./package.json",
|
|
@@ -16,13 +16,13 @@ import { ResizeContainer } from '../components/resize-container';
|
|
|
16
16
|
import Tabs from '../components/tabs';
|
|
17
17
|
import { useQuery } from '../useQuery';
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
export type
|
|
19
|
+
const aggregateViewSchema = z.literal(views.table);
|
|
20
|
+
export type AggregateView = z.infer<typeof aggregateViewSchema>;
|
|
21
21
|
|
|
22
22
|
const aggregatePropsSchema = z.object({
|
|
23
|
-
|
|
23
|
+
lapisFilter: lapisFilterSchema,
|
|
24
24
|
fields: z.array(z.string().min(1)),
|
|
25
|
-
views: z.array(
|
|
25
|
+
views: z.array(aggregateViewSchema),
|
|
26
26
|
initialSortField: z.string(),
|
|
27
27
|
initialSortDirection: z.union([z.literal('ascending'), z.literal('descending')]),
|
|
28
28
|
pageSize: z.union([z.boolean(), z.number()]),
|
|
@@ -45,12 +45,15 @@ export const Aggregate: FunctionComponent<AggregateProps> = (componentProps) =>
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
export const AggregateInner: FunctionComponent<AggregateProps> = (componentProps) => {
|
|
48
|
-
const { fields,
|
|
48
|
+
const { fields, lapisFilter, initialSortField, initialSortDirection } = componentProps;
|
|
49
49
|
const lapis = useContext(LapisUrlContext);
|
|
50
50
|
|
|
51
51
|
const { data, error, isLoading } = useQuery(async () => {
|
|
52
|
-
return queryAggregateData(
|
|
53
|
-
|
|
52
|
+
return queryAggregateData(lapisFilter, fields, lapis, {
|
|
53
|
+
field: initialSortField,
|
|
54
|
+
direction: initialSortDirection,
|
|
55
|
+
});
|
|
56
|
+
}, [lapisFilter, fields, lapis]);
|
|
54
57
|
|
|
55
58
|
if (isLoading) {
|
|
56
59
|
return <LoadingDisplay />;
|
|
@@ -73,7 +76,7 @@ type AggregatedDataTabsProps = {
|
|
|
73
76
|
};
|
|
74
77
|
|
|
75
78
|
const AggregatedDataTabs: FunctionComponent<AggregatedDataTabsProps> = ({ data, originalComponentProps }) => {
|
|
76
|
-
const getTab = (view:
|
|
79
|
+
const getTab = (view: AggregateView) => {
|
|
77
80
|
switch (view) {
|
|
78
81
|
case 'table':
|
|
79
82
|
return {
|
|
@@ -54,7 +54,7 @@ const meta: Meta<DateRangeSelectorProps> = {
|
|
|
54
54
|
dateRangeOptions: [dateRangeOptionPresets.lastMonth, dateRangeOptionPresets.allTimes, customDateRange],
|
|
55
55
|
earliestDate,
|
|
56
56
|
initialValue: dateRangeOptionPresets.lastMonth.label,
|
|
57
|
-
|
|
57
|
+
lapisDateField: 'aDateColumn',
|
|
58
58
|
width: '100%',
|
|
59
59
|
initialDateFrom: undefined,
|
|
60
60
|
initialDateTo: undefined,
|
|
@@ -66,15 +66,7 @@ export default meta;
|
|
|
66
66
|
export const Primary: StoryObj<DateRangeSelectorProps> = {
|
|
67
67
|
render: (args) => (
|
|
68
68
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
69
|
-
<DateRangeSelector
|
|
70
|
-
dateRangeOptions={args.dateRangeOptions}
|
|
71
|
-
earliestDate={args.earliestDate}
|
|
72
|
-
initialValue={args.initialValue}
|
|
73
|
-
initialDateFrom={args.initialDateFrom}
|
|
74
|
-
initialDateTo={args.initialDateTo}
|
|
75
|
-
width={args.width}
|
|
76
|
-
dateColumn={args.dateColumn}
|
|
77
|
-
/>
|
|
69
|
+
<DateRangeSelector {...args} />
|
|
78
70
|
</LapisUrlContext.Provider>
|
|
79
71
|
),
|
|
80
72
|
};
|
|
@@ -226,7 +218,7 @@ export const WithNoDateColumn: StoryObj<DateRangeSelectorProps> = {
|
|
|
226
218
|
...Primary,
|
|
227
219
|
args: {
|
|
228
220
|
...Primary.args,
|
|
229
|
-
|
|
221
|
+
lapisDateField: '',
|
|
230
222
|
},
|
|
231
223
|
play: async ({ canvasElement, step }) => {
|
|
232
224
|
step('expect error message', async () => {
|
|
@@ -19,7 +19,7 @@ const dateRangeSelectorInnerPropsSchema = z.object({
|
|
|
19
19
|
initialValue: z.string().optional(),
|
|
20
20
|
initialDateFrom: z.string().date().optional(),
|
|
21
21
|
initialDateTo: z.string().date().optional(),
|
|
22
|
-
|
|
22
|
+
lapisDateField: z.string().min(1),
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
const dateRangeSelectorPropsSchema = dateRangeSelectorInnerPropsSchema.extend({
|
|
@@ -46,7 +46,7 @@ export const DateRangeSelectorInner = ({
|
|
|
46
46
|
dateRangeOptions,
|
|
47
47
|
earliestDate = '1900-01-01',
|
|
48
48
|
initialValue,
|
|
49
|
-
|
|
49
|
+
lapisDateField,
|
|
50
50
|
initialDateFrom,
|
|
51
51
|
initialDateTo,
|
|
52
52
|
}: DateRangeSelectorInnerProps) => {
|
|
@@ -171,8 +171,8 @@ export const DateRangeSelectorInner = ({
|
|
|
171
171
|
const dateTo = dateToPicker?.selectedDates[0];
|
|
172
172
|
|
|
173
173
|
const detail = {
|
|
174
|
-
...(dateFrom !== undefined && { [`${
|
|
175
|
-
...(dateTo !== undefined && { [`${
|
|
174
|
+
...(dateFrom !== undefined && { [`${lapisDateField}From`]: toYYYYMMDD(dateFrom) }),
|
|
175
|
+
...(dateTo !== undefined && { [`${lapisDateField}To`]: toYYYYMMDD(dateTo) }),
|
|
176
176
|
};
|
|
177
177
|
|
|
178
178
|
divRef.current?.dispatchEvent(
|
|
@@ -6,12 +6,7 @@ import { getMutationComparisonTableData } from './getMutationComparisonTableData
|
|
|
6
6
|
import { MutationComparisonTable } from './mutation-comparison-table';
|
|
7
7
|
import { MutationComparisonVenn } from './mutation-comparison-venn';
|
|
8
8
|
import { filterMutationData, type MutationData, queryMutationData } from './queryMutationData';
|
|
9
|
-
import {
|
|
10
|
-
type MutationComparisonView,
|
|
11
|
-
mutationComparisonViewSchema,
|
|
12
|
-
namedLapisFilterSchema,
|
|
13
|
-
sequenceTypeSchema,
|
|
14
|
-
} from '../../types';
|
|
9
|
+
import { namedLapisFilterSchema, sequenceTypeSchema, views } from '../../types';
|
|
15
10
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
16
11
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
17
12
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
@@ -27,6 +22,9 @@ import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '..
|
|
|
27
22
|
import Tabs from '../components/tabs';
|
|
28
23
|
import { useQuery } from '../useQuery';
|
|
29
24
|
|
|
25
|
+
export const mutationComparisonViewSchema = z.union([z.literal(views.table), z.literal(views.venn)]);
|
|
26
|
+
export type MutationComparisonView = z.infer<typeof mutationComparisonViewSchema>;
|
|
27
|
+
|
|
30
28
|
const mutationComparisonPropsSchema = z.object({
|
|
31
29
|
width: z.string(),
|
|
32
30
|
height: z.string(),
|
|
@@ -5,20 +5,14 @@ import z from 'zod';
|
|
|
5
5
|
import { MutationFilterInfo } from './mutation-filter-info';
|
|
6
6
|
import { parseAndValidateMutation, type ParsedMutationFilter } from './parseAndValidateMutation';
|
|
7
7
|
import { type ReferenceGenome } from '../../lapisApi/ReferenceGenome';
|
|
8
|
+
import { type MutationsFilter, mutationsFilterSchema } from '../../types';
|
|
8
9
|
import { type DeletionClass, type InsertionClass, type SubstitutionClass } from '../../utils/mutations';
|
|
9
10
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
10
11
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
11
12
|
import { singleGraphColorRGBByName } from '../shared/charts/colors';
|
|
12
13
|
|
|
13
|
-
const selectedMutationFilterStringsSchema = z.object({
|
|
14
|
-
nucleotideMutations: z.array(z.string()),
|
|
15
|
-
aminoAcidMutations: z.array(z.string()),
|
|
16
|
-
nucleotideInsertions: z.array(z.string()),
|
|
17
|
-
aminoAcidInsertions: z.array(z.string()),
|
|
18
|
-
});
|
|
19
|
-
export type SelectedMutationFilterStrings = z.infer<typeof selectedMutationFilterStringsSchema>;
|
|
20
14
|
const mutationFilterInnerPropsSchema = z.object({
|
|
21
|
-
initialValue: z.union([
|
|
15
|
+
initialValue: z.union([mutationsFilterSchema.optional(), z.array(z.string()), z.undefined()]),
|
|
22
16
|
});
|
|
23
17
|
|
|
24
18
|
const mutationFilterPropsSchema = mutationFilterInnerPropsSchema.extend({
|
|
@@ -73,7 +67,7 @@ export const MutationFilterInner: FunctionComponent<MutationFilterInnerProps> =
|
|
|
73
67
|
const detail = mapToMutationFilterStrings(selectedFilters);
|
|
74
68
|
|
|
75
69
|
filterRef.current?.dispatchEvent(
|
|
76
|
-
new CustomEvent<
|
|
70
|
+
new CustomEvent<MutationsFilter>('gs-mutation-filter-changed', {
|
|
77
71
|
detail,
|
|
78
72
|
bubbles: true,
|
|
79
73
|
composed: true,
|
|
@@ -105,10 +99,7 @@ export const MutationFilterInner: FunctionComponent<MutationFilterInnerProps> =
|
|
|
105
99
|
);
|
|
106
100
|
};
|
|
107
101
|
|
|
108
|
-
function getInitialState(
|
|
109
|
-
initialValue: SelectedMutationFilterStrings | string[] | undefined,
|
|
110
|
-
referenceGenome: ReferenceGenome,
|
|
111
|
-
) {
|
|
102
|
+
function getInitialState(initialValue: MutationsFilter | string[] | undefined, referenceGenome: ReferenceGenome) {
|
|
112
103
|
if (initialValue === undefined) {
|
|
113
104
|
return {
|
|
114
105
|
nucleotideMutations: [],
|
|
@@ -30,13 +30,13 @@ import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '..
|
|
|
30
30
|
import Tabs from '../components/tabs';
|
|
31
31
|
import { useQuery } from '../useQuery';
|
|
32
32
|
|
|
33
|
-
const
|
|
34
|
-
export type
|
|
33
|
+
const mutationsViewSchema = z.union([z.literal(views.table), z.literal(views.grid), z.literal(views.insertions)]);
|
|
34
|
+
export type MutationsView = z.infer<typeof mutationsViewSchema>;
|
|
35
35
|
|
|
36
36
|
const mutationsPropsSchema = z.object({
|
|
37
37
|
lapisFilter: lapisFilterSchema,
|
|
38
38
|
sequenceType: sequenceTypeSchema,
|
|
39
|
-
views:
|
|
39
|
+
views: mutationsViewSchema.array(),
|
|
40
40
|
pageSize: z.union([z.boolean(), z.number()]),
|
|
41
41
|
width: z.string(),
|
|
42
42
|
height: z.string(),
|
|
@@ -95,7 +95,7 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, or
|
|
|
95
95
|
|
|
96
96
|
const filteredData = filterMutationsData(mutationsData, displayedSegments, displayedMutationTypes);
|
|
97
97
|
|
|
98
|
-
const getTab = (view:
|
|
98
|
+
const getTab = (view: MutationsView) => {
|
|
99
99
|
switch (view) {
|
|
100
100
|
case 'table':
|
|
101
101
|
return {
|
|
@@ -35,13 +35,13 @@ import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '..
|
|
|
35
35
|
import Tabs from '../components/tabs';
|
|
36
36
|
import { useWebWorker } from '../webWorkers/useWebWorker';
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
export type
|
|
38
|
+
const mutationsOverTimeViewSchema = z.literal(views.grid);
|
|
39
|
+
export type MutationsOverTimeView = z.infer<typeof mutationsOverTimeViewSchema>;
|
|
40
40
|
|
|
41
41
|
const mutationOverTimeSchema = z.object({
|
|
42
42
|
lapisFilter: lapisFilterSchema,
|
|
43
43
|
sequenceType: sequenceTypeSchema,
|
|
44
|
-
views: z.array(
|
|
44
|
+
views: z.array(mutationsOverTimeViewSchema),
|
|
45
45
|
granularity: temporalGranularitySchema,
|
|
46
46
|
lapisDateField: z.string().min(1),
|
|
47
47
|
width: z.string(),
|
|
@@ -134,7 +134,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
134
134
|
);
|
|
135
135
|
}, [mutationOverTimeData, overallMutationData, displayedSegments, displayedMutationTypes, proportionInterval]);
|
|
136
136
|
|
|
137
|
-
const getTab = (view:
|
|
137
|
+
const getTab = (view: MutationsOverTimeView) => {
|
|
138
138
|
if (filteredData === undefined) {
|
|
139
139
|
return {
|
|
140
140
|
title: 'Calculating',
|
|
@@ -30,21 +30,12 @@ export default {
|
|
|
30
30
|
const Template: StoryObj<NumberSequencesOverTimeProps> = {
|
|
31
31
|
render: (args) => (
|
|
32
32
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
33
|
-
<NumberSequencesOverTime
|
|
34
|
-
lapisFilter={args.lapisFilter}
|
|
35
|
-
lapisDateField={args.lapisDateField}
|
|
36
|
-
views={args.views}
|
|
37
|
-
width={args.width}
|
|
38
|
-
height={args.height}
|
|
39
|
-
granularity={args.granularity}
|
|
40
|
-
smoothingWindow={args.smoothingWindow}
|
|
41
|
-
pageSize={args.pageSize}
|
|
42
|
-
/>
|
|
33
|
+
<NumberSequencesOverTime {...args} />
|
|
43
34
|
</LapisUrlContext.Provider>
|
|
44
35
|
),
|
|
45
36
|
args: {
|
|
46
37
|
views: ['bar', 'line', 'table'],
|
|
47
|
-
|
|
38
|
+
lapisFilters: [
|
|
48
39
|
{ displayName: 'EG', lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateFrom: '2022-12-01' } },
|
|
49
40
|
],
|
|
50
41
|
lapisDateField: 'date',
|
|
@@ -82,11 +73,11 @@ export const Table = {
|
|
|
82
73
|
...Template,
|
|
83
74
|
};
|
|
84
75
|
|
|
85
|
-
export const TwoVariants = {
|
|
76
|
+
export const TwoVariants: StoryObj<NumberSequencesOverTimeProps> = {
|
|
86
77
|
...Template,
|
|
87
78
|
args: {
|
|
88
79
|
...Template.args,
|
|
89
|
-
|
|
80
|
+
lapisFilters: [
|
|
90
81
|
{ displayName: 'EG', lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateTo: '2023-06-30' } },
|
|
91
82
|
{ displayName: 'JN.1', lapisFilter: { country: 'USA', pangoLineage: 'JN.1*', dateFrom: '2023-01-01' } },
|
|
92
83
|
],
|
|
@@ -34,7 +34,7 @@ export type NumberSequencesOverTimeView = z.infer<typeof numberSequencesOverTime
|
|
|
34
34
|
const numberSequencesOverTimePropsSchema = z.object({
|
|
35
35
|
width: z.string(),
|
|
36
36
|
height: z.string(),
|
|
37
|
-
|
|
37
|
+
lapisFilters: z.array(namedLapisFilterSchema).min(1),
|
|
38
38
|
lapisDateField: z.string().min(1),
|
|
39
39
|
views: z.array(numberSequencesOverTimeViewSchema),
|
|
40
40
|
granularity: temporalGranularitySchema,
|
|
@@ -58,12 +58,12 @@ export const NumberSequencesOverTime = (componentProps: NumberSequencesOverTimeP
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const NumberSequencesOverTimeInner = (componentProps: NumberSequencesOverTimeProps) => {
|
|
61
|
-
const {
|
|
61
|
+
const { lapisFilters, lapisDateField, granularity, smoothingWindow } = componentProps;
|
|
62
62
|
const lapis = useContext(LapisUrlContext);
|
|
63
63
|
|
|
64
64
|
const { data, error, isLoading } = useQuery(
|
|
65
|
-
() => queryNumberOfSequencesOverTime(lapis,
|
|
66
|
-
[lapis,
|
|
65
|
+
() => queryNumberOfSequencesOverTime(lapis, lapisFilters, lapisDateField, granularity, smoothingWindow),
|
|
66
|
+
[lapis, lapisFilters, lapisDateField, granularity, smoothingWindow],
|
|
67
67
|
);
|
|
68
68
|
|
|
69
69
|
if (isLoading) {
|
|
@@ -19,8 +19,6 @@ export default {
|
|
|
19
19
|
fetchMock: {},
|
|
20
20
|
},
|
|
21
21
|
argTypes: {
|
|
22
|
-
numerator: { control: 'object' },
|
|
23
|
-
denominator: { control: 'object' },
|
|
24
22
|
granularity: {
|
|
25
23
|
options: ['day', 'week', 'month', 'year'],
|
|
26
24
|
control: { type: 'radio' },
|
|
@@ -45,20 +43,7 @@ export default {
|
|
|
45
43
|
const Template = {
|
|
46
44
|
render: (args: PrevalenceOverTimeProps) => (
|
|
47
45
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
48
|
-
<PrevalenceOverTime
|
|
49
|
-
numeratorFilter={args.numeratorFilter}
|
|
50
|
-
denominatorFilter={args.denominatorFilter}
|
|
51
|
-
granularity={args.granularity}
|
|
52
|
-
smoothingWindow={args.smoothingWindow}
|
|
53
|
-
views={args.views}
|
|
54
|
-
confidenceIntervalMethods={args.confidenceIntervalMethods}
|
|
55
|
-
width={args.width}
|
|
56
|
-
height={args.height}
|
|
57
|
-
lapisDateField={args.lapisDateField}
|
|
58
|
-
pageSize={args.pageSize}
|
|
59
|
-
yAxisMaxLinear={args.yAxisMaxLinear}
|
|
60
|
-
yAxisMaxLogarithmic={args.yAxisMaxLogarithmic}
|
|
61
|
-
/>
|
|
46
|
+
<PrevalenceOverTime {...args} />
|
|
62
47
|
</LapisUrlContext.Provider>
|
|
63
48
|
),
|
|
64
49
|
};
|
|
@@ -66,7 +51,7 @@ const Template = {
|
|
|
66
51
|
export const TwoVariants: StoryObj<PrevalenceOverTimeProps> = {
|
|
67
52
|
...Template,
|
|
68
53
|
args: {
|
|
69
|
-
|
|
54
|
+
numeratorFilters: [
|
|
70
55
|
{ displayName: 'EG', lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateFrom: '2023-01-01' } },
|
|
71
56
|
{ displayName: 'JN.1', lapisFilter: { country: 'USA', pangoLineage: 'JN.1*', dateFrom: '2023-01-01' } },
|
|
72
57
|
],
|
|
@@ -140,10 +125,12 @@ export const TwoVariants: StoryObj<PrevalenceOverTimeProps> = {
|
|
|
140
125
|
export const OneVariant: StoryObj<PrevalenceOverTimeProps> = {
|
|
141
126
|
...Template,
|
|
142
127
|
args: {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
128
|
+
numeratorFilters: [
|
|
129
|
+
{
|
|
130
|
+
displayName: 'EG',
|
|
131
|
+
lapisFilter: { country: 'USA', pangoLineage: 'BA.2.86*', dateFrom: '2023-10-01' },
|
|
132
|
+
},
|
|
133
|
+
],
|
|
147
134
|
denominatorFilter: { country: 'USA', dateFrom: '2023-10-01' },
|
|
148
135
|
granularity: 'day',
|
|
149
136
|
smoothingWindow: 7,
|
|
@@ -198,10 +185,12 @@ export const OneVariant: StoryObj<PrevalenceOverTimeProps> = {
|
|
|
198
185
|
export const ShowsNoDataBanner: StoryObj<PrevalenceOverTimeProps> = {
|
|
199
186
|
...Template,
|
|
200
187
|
args: {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
188
|
+
numeratorFilters: [
|
|
189
|
+
{
|
|
190
|
+
displayName: 'EG',
|
|
191
|
+
lapisFilter: { country: 'USA', pangoLineage: 'BA.2.86*', dateFrom: '2023-10-01' },
|
|
192
|
+
},
|
|
193
|
+
],
|
|
205
194
|
denominatorFilter: { country: 'USA', dateFrom: '2023-10-01' },
|
|
206
195
|
granularity: 'day',
|
|
207
196
|
smoothingWindow: 7,
|
|
@@ -25,22 +25,22 @@ import { axisMaxSchema } from '../shared/charts/getYAxisMax';
|
|
|
25
25
|
import { type ScaleType } from '../shared/charts/getYAxisScale';
|
|
26
26
|
import { useQuery } from '../useQuery';
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const prevalenceOverTimeViewSchema = z.union([
|
|
29
29
|
z.literal(views.table),
|
|
30
30
|
z.literal(views.bar),
|
|
31
31
|
z.literal(views.line),
|
|
32
32
|
z.literal(views.bubble),
|
|
33
33
|
]);
|
|
34
|
-
export type
|
|
34
|
+
export type PrevalenceOverTimeView = z.infer<typeof prevalenceOverTimeViewSchema>;
|
|
35
35
|
|
|
36
36
|
const prevalenceOverTimePropsSchema = z.object({
|
|
37
37
|
width: z.string(),
|
|
38
38
|
height: z.string(),
|
|
39
|
-
|
|
39
|
+
numeratorFilters: z.array(namedLapisFilterSchema).min(1),
|
|
40
40
|
denominatorFilter: lapisFilterSchema,
|
|
41
41
|
granularity: temporalGranularitySchema,
|
|
42
42
|
smoothingWindow: z.number(),
|
|
43
|
-
views: z.array(
|
|
43
|
+
views: z.array(prevalenceOverTimeViewSchema),
|
|
44
44
|
confidenceIntervalMethods: z.array(confidenceIntervalMethodSchema),
|
|
45
45
|
lapisDateField: z.string().min(1),
|
|
46
46
|
pageSize: z.union([z.boolean(), z.number()]),
|
|
@@ -64,20 +64,20 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = (c
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeProps> = (componentProps) => {
|
|
67
|
-
const {
|
|
67
|
+
const { numeratorFilters, denominatorFilter, granularity, smoothingWindow, lapisDateField } = componentProps;
|
|
68
68
|
const lapis = useContext(LapisUrlContext);
|
|
69
69
|
|
|
70
70
|
const { data, error, isLoading } = useQuery(
|
|
71
71
|
() =>
|
|
72
72
|
queryPrevalenceOverTime(
|
|
73
|
-
|
|
73
|
+
numeratorFilters,
|
|
74
74
|
denominatorFilter,
|
|
75
75
|
granularity,
|
|
76
76
|
smoothingWindow,
|
|
77
77
|
lapis,
|
|
78
78
|
lapisDateField,
|
|
79
79
|
),
|
|
80
|
-
[lapis,
|
|
80
|
+
[lapis, numeratorFilters, denominatorFilter, granularity, smoothingWindow, lapisDateField],
|
|
81
81
|
);
|
|
82
82
|
|
|
83
83
|
if (isLoading) {
|
|
@@ -118,7 +118,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
118
118
|
|
|
119
119
|
const yAxisMaxConfig = { linear: yAxisMaxLinear, logarithmic: yAxisMaxLogarithmic };
|
|
120
120
|
|
|
121
|
-
const getTab = (view:
|
|
121
|
+
const getTab = (view: PrevalenceOverTimeView) => {
|
|
122
122
|
switch (view) {
|
|
123
123
|
case 'bar':
|
|
124
124
|
return {
|
|
@@ -31,16 +31,7 @@ export default {
|
|
|
31
31
|
export const Primary: StoryObj<RelativeGrowthAdvantageProps> = {
|
|
32
32
|
render: (args: RelativeGrowthAdvantageProps) => (
|
|
33
33
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
34
|
-
<RelativeGrowthAdvantage
|
|
35
|
-
numeratorFilter={args.numeratorFilter}
|
|
36
|
-
denominatorFilter={args.denominatorFilter}
|
|
37
|
-
generationTime={args.generationTime}
|
|
38
|
-
views={args.views}
|
|
39
|
-
width={args.width}
|
|
40
|
-
height={args.height}
|
|
41
|
-
lapisDateField={args.lapisDateField}
|
|
42
|
-
yAxisMaxConfig={args.yAxisMaxConfig}
|
|
43
|
-
/>
|
|
34
|
+
<RelativeGrowthAdvantage {...args} />
|
|
44
35
|
</LapisUrlContext.Provider>
|
|
45
36
|
),
|
|
46
37
|
args: {
|
|
@@ -56,10 +47,8 @@ export const Primary: StoryObj<RelativeGrowthAdvantageProps> = {
|
|
|
56
47
|
width: '100%',
|
|
57
48
|
height: '700px',
|
|
58
49
|
lapisDateField: 'date',
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
logarithmic: 1,
|
|
62
|
-
},
|
|
50
|
+
yAxisMaxLinear: 1,
|
|
51
|
+
yAxisMaxLogarithmic: 1,
|
|
63
52
|
},
|
|
64
53
|
parameters: {
|
|
65
54
|
fetchMock: {
|
|
@@ -18,12 +18,12 @@ import { NoDataDisplay } from '../components/no-data-display';
|
|
|
18
18
|
import { ResizeContainer } from '../components/resize-container';
|
|
19
19
|
import { ScalingSelector } from '../components/scaling-selector';
|
|
20
20
|
import Tabs from '../components/tabs';
|
|
21
|
-
import {
|
|
21
|
+
import { axisMaxSchema } from '../shared/charts/getYAxisMax';
|
|
22
22
|
import { type ScaleType } from '../shared/charts/getYAxisScale';
|
|
23
23
|
import { useQuery } from '../useQuery';
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
export type
|
|
25
|
+
const relativeGrowthAdvantageViewSchema = z.literal(views.line);
|
|
26
|
+
export type RelativeGrowthAdvantageView = z.infer<typeof relativeGrowthAdvantageViewSchema>;
|
|
27
27
|
|
|
28
28
|
export const relativeGrowthAdvantagePropsSchema = z.object({
|
|
29
29
|
width: z.string(),
|
|
@@ -31,9 +31,10 @@ export const relativeGrowthAdvantagePropsSchema = z.object({
|
|
|
31
31
|
numeratorFilter: lapisFilterSchema,
|
|
32
32
|
denominatorFilter: lapisFilterSchema,
|
|
33
33
|
generationTime: z.number(),
|
|
34
|
-
views: z.array(
|
|
34
|
+
views: z.array(relativeGrowthAdvantageViewSchema),
|
|
35
35
|
lapisDateField: z.string().min(1),
|
|
36
|
-
|
|
36
|
+
yAxisMaxLinear: axisMaxSchema,
|
|
37
|
+
yAxisMaxLogarithmic: axisMaxSchema,
|
|
37
38
|
});
|
|
38
39
|
export type RelativeGrowthAdvantageProps = z.infer<typeof relativeGrowthAdvantagePropsSchema>;
|
|
39
40
|
|
|
@@ -101,7 +102,7 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
101
102
|
setYAxisScaleType,
|
|
102
103
|
originalComponentProps,
|
|
103
104
|
}) => {
|
|
104
|
-
const getTab = (view:
|
|
105
|
+
const getTab = (view: RelativeGrowthAdvantageView) => {
|
|
105
106
|
switch (view) {
|
|
106
107
|
case 'line':
|
|
107
108
|
return {
|
|
@@ -114,7 +115,10 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
114
115
|
params: data.params,
|
|
115
116
|
}}
|
|
116
117
|
yAxisScaleType={yAxisScaleType}
|
|
117
|
-
yAxisMaxConfig={
|
|
118
|
+
yAxisMaxConfig={{
|
|
119
|
+
linear: originalComponentProps.yAxisMaxLinear,
|
|
120
|
+
logarithmic: originalComponentProps.yAxisMaxLogarithmic,
|
|
121
|
+
}}
|
|
118
122
|
/>
|
|
119
123
|
),
|
|
120
124
|
};
|
|
@@ -21,7 +21,7 @@ describe('queryNumberOfSequencesOverTime', () => {
|
|
|
21
21
|
|
|
22
22
|
const result = await queryNumberOfSequencesOverTime(
|
|
23
23
|
DUMMY_LAPIS_URL,
|
|
24
|
-
{ displayName: 'displayName', lapisFilter },
|
|
24
|
+
[{ displayName: 'displayName', lapisFilter }],
|
|
25
25
|
lapisDateField,
|
|
26
26
|
'day',
|
|
27
27
|
0,
|
|
@@ -51,7 +51,7 @@ describe('queryNumberOfSequencesOverTime', () => {
|
|
|
51
51
|
|
|
52
52
|
const result = await queryNumberOfSequencesOverTime(
|
|
53
53
|
DUMMY_LAPIS_URL,
|
|
54
|
-
{ displayName: 'displayName', lapisFilter },
|
|
54
|
+
[{ displayName: 'displayName', lapisFilter }],
|
|
55
55
|
lapisDateField,
|
|
56
56
|
'day',
|
|
57
57
|
0,
|
|
@@ -87,7 +87,7 @@ describe('queryNumberOfSequencesOverTime', () => {
|
|
|
87
87
|
|
|
88
88
|
const result = await queryNumberOfSequencesOverTime(
|
|
89
89
|
DUMMY_LAPIS_URL,
|
|
90
|
-
{ displayName: 'displayName', lapisFilter },
|
|
90
|
+
[{ displayName: 'displayName', lapisFilter }],
|
|
91
91
|
lapisDateField,
|
|
92
92
|
'day',
|
|
93
93
|
3,
|
|
@@ -122,7 +122,7 @@ describe('queryNumberOfSequencesOverTime', () => {
|
|
|
122
122
|
|
|
123
123
|
const result = await queryNumberOfSequencesOverTime(
|
|
124
124
|
DUMMY_LAPIS_URL,
|
|
125
|
-
{ displayName: 'displayName', lapisFilter },
|
|
125
|
+
[{ displayName: 'displayName', lapisFilter }],
|
|
126
126
|
lapisDateField,
|
|
127
127
|
'month',
|
|
128
128
|
0,
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { queryAggregatedDataOverTime } from './queryAggregatedDataOverTime';
|
|
2
2
|
import { type NamedLapisFilter, type TemporalGranularity } from '../types';
|
|
3
3
|
import { sortNullToBeginningThenByDate } from '../utils/sort';
|
|
4
|
-
import { makeArray } from '../utils/utils';
|
|
5
4
|
|
|
6
5
|
export type NumberOfSequencesDatasets = Awaited<ReturnType<typeof queryNumberOfSequencesOverTime>>;
|
|
7
6
|
|
|
8
7
|
export async function queryNumberOfSequencesOverTime(
|
|
9
8
|
lapis: string,
|
|
10
|
-
|
|
9
|
+
lapisFilters: NamedLapisFilter[],
|
|
11
10
|
lapisDateField: string,
|
|
12
11
|
granularity: TemporalGranularity,
|
|
13
12
|
smoothingWindow: number,
|
|
14
13
|
) {
|
|
15
|
-
const lapisFilters = makeArray(lapisFilter);
|
|
16
|
-
|
|
17
14
|
const queries = lapisFilters.map(async ({ displayName, lapisFilter }) => {
|
|
18
15
|
const { content } = await queryAggregatedDataOverTime(
|
|
19
16
|
lapisFilter,
|
|
@@ -2,7 +2,6 @@ import { queryAggregatedDataOverTime } from './queryAggregatedDataOverTime';
|
|
|
2
2
|
import { DivisionOperator } from '../operator/DivisionOperator';
|
|
3
3
|
import { type LapisFilter, type NamedLapisFilter, type TemporalGranularity } from '../types';
|
|
4
4
|
import { type TemporalClass } from '../utils/temporalClass';
|
|
5
|
-
import { makeArray } from '../utils/utils';
|
|
6
5
|
|
|
7
6
|
export type PrevalenceOverTimeData = PrevalenceOverTimeVariantData[];
|
|
8
7
|
|
|
@@ -19,7 +18,7 @@ export type PrevalenceOverTimeVariantDataPoint = {
|
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
export function queryPrevalenceOverTime(
|
|
22
|
-
|
|
21
|
+
numeratorFilters: NamedLapisFilter[],
|
|
23
22
|
denominatorFilter: LapisFilter,
|
|
24
23
|
granularity: TemporalGranularity,
|
|
25
24
|
smoothingWindow: number,
|
|
@@ -27,8 +26,6 @@ export function queryPrevalenceOverTime(
|
|
|
27
26
|
lapisDateField: string,
|
|
28
27
|
signal?: AbortSignal,
|
|
29
28
|
): Promise<PrevalenceOverTimeData> {
|
|
30
|
-
const numeratorFilters = makeArray(numeratorFilter);
|
|
31
|
-
|
|
32
29
|
const denominatorData = queryAggregatedDataOverTime(
|
|
33
30
|
denominatorFilter,
|
|
34
31
|
granularity,
|