@genspectrum/dashboard-components 0.1.4 → 0.2.0
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 +1021 -804
- package/dist/dashboard-components.js +647 -218
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +336 -126
- package/dist/style.css +214 -36
- package/package.json +4 -4
- package/src/preact/aggregatedData/aggregate.stories.tsx +2 -0
- package/src/preact/aggregatedData/aggregate.tsx +33 -28
- package/src/preact/components/error-boundary.stories.tsx +62 -0
- package/src/preact/components/error-boundary.tsx +31 -0
- package/src/preact/components/error-display.stories.tsx +24 -3
- package/src/preact/components/error-display.tsx +14 -1
- package/src/preact/components/headline.stories.tsx +19 -1
- package/src/preact/components/headline.tsx +9 -1
- package/src/preact/components/info.stories.tsx +24 -3
- package/src/preact/components/info.tsx +49 -5
- package/src/preact/components/loading-display.stories.tsx +6 -6
- package/src/preact/components/loading-display.tsx +1 -1
- package/src/preact/components/no-data-display.tsx +5 -1
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +17 -0
- package/src/preact/dateRangeSelector/date-range-selector.tsx +43 -15
- package/src/preact/locationFilter/location-filter.stories.tsx +23 -6
- package/src/preact/locationFilter/location-filter.tsx +29 -18
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -0
- package/src/preact/mutationComparison/mutation-comparison.tsx +31 -27
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +17 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +26 -8
- package/src/preact/mutations/mutations.stories.tsx +3 -0
- package/src/preact/mutations/mutations.tsx +32 -26
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +57 -31
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -0
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +89 -32
- package/src/preact/textInput/text-input.tsx +26 -3
- package/src/web-components/app.stories.ts +1 -2
- package/src/web-components/app.ts +4 -2
- package/src/web-components/index.ts +1 -1
- package/src/web-components/input/{date-range-selector-component.stories.ts → gs-date-range-selector.stories.ts} +35 -3
- package/src/web-components/input/gs-date-range-selector.tsx +110 -0
- package/src/web-components/input/{location-filter-component.stories.ts → gs-location-filter.stories.ts} +29 -4
- package/src/web-components/input/{location-filter-component.tsx → gs-location-filter.tsx} +12 -1
- package/src/web-components/input/{mutation-filter-component.stories.ts → gs-mutation-filter.stories.ts} +30 -4
- package/src/web-components/input/gs-mutation-filter.tsx +114 -0
- package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts} +42 -3
- package/src/web-components/input/gs-text-input.tsx +73 -0
- package/src/web-components/input/index.ts +4 -4
- package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +26 -0
- package/src/web-components/{display/aggregate-component.stories.ts → visualization/gs-aggregate.stories.ts} +8 -6
- package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx} +16 -2
- package/src/web-components/{display/mutation-comparison-component.stories.ts → visualization/gs-mutation-comparison.stories.ts} +11 -9
- package/src/web-components/{display/mutation-comparison-component.tsx → visualization/gs-mutation-comparison.tsx} +8 -1
- package/src/web-components/{display/mutations-component.stories.ts → visualization/gs-mutations.stories.ts} +30 -11
- package/src/web-components/visualization/gs-mutations.tsx +94 -0
- package/src/web-components/{display/prevalence-over-time-component.stories.ts → visualization/gs-prevalence-over-time.stories.ts} +24 -1
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +148 -0
- package/src/web-components/{display/relative-growth-advantage-component.stories.ts → visualization/gs-relative-growth-advantage.stories.ts} +21 -1
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +100 -0
- package/src/web-components/visualization/index.ts +5 -0
- package/src/web-components/display/index.ts +0 -5
- package/src/web-components/display/mutations-component.tsx +0 -40
- package/src/web-components/display/prevalence-over-time-component.tsx +0 -58
- package/src/web-components/display/relative-growth-advantage-component.tsx +0 -49
- package/src/web-components/input/date-range-selector-component.tsx +0 -46
- package/src/web-components/input/mutation-filter-component.tsx +0 -35
- package/src/web-components/input/text-input-component.tsx +0 -39
|
@@ -9,6 +9,7 @@ import { type LapisFilter, type SequenceType } from '../../types';
|
|
|
9
9
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
10
10
|
import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '../components/SegmentSelector';
|
|
11
11
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
12
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
12
13
|
import { ErrorDisplay } from '../components/error-display';
|
|
13
14
|
import Headline from '../components/headline';
|
|
14
15
|
import Info from '../components/info';
|
|
@@ -28,11 +29,15 @@ export interface MutationComparisonVariant {
|
|
|
28
29
|
displayName: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export interface MutationComparisonProps {
|
|
32
|
+
export interface MutationComparisonProps extends MutationComparisonInnerProps {
|
|
33
|
+
size?: Size;
|
|
34
|
+
headline?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MutationComparisonInnerProps {
|
|
32
38
|
variants: MutationComparisonVariant[];
|
|
33
39
|
sequenceType: SequenceType;
|
|
34
40
|
views: View[];
|
|
35
|
-
size?: Size;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
@@ -40,6 +45,25 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
40
45
|
sequenceType,
|
|
41
46
|
views,
|
|
42
47
|
size,
|
|
48
|
+
headline = 'Mutation comparison',
|
|
49
|
+
}) => {
|
|
50
|
+
const defaultSize = { height: '600px', width: '100%' };
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
|
|
54
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
55
|
+
<Headline heading={headline}>
|
|
56
|
+
<MutationComparisonInner variants={variants} sequenceType={sequenceType} views={views} />
|
|
57
|
+
</Headline>
|
|
58
|
+
</ResizeContainer>
|
|
59
|
+
</ErrorBoundary>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const MutationComparisonInner: FunctionComponent<MutationComparisonInnerProps> = ({
|
|
64
|
+
variants,
|
|
65
|
+
sequenceType,
|
|
66
|
+
views,
|
|
43
67
|
}) => {
|
|
44
68
|
const lapis = useContext(LapisUrlContext);
|
|
45
69
|
|
|
@@ -47,39 +71,19 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
47
71
|
return queryMutationData(variants, sequenceType, lapis);
|
|
48
72
|
}, [variants, sequenceType, lapis]);
|
|
49
73
|
|
|
50
|
-
const headline = 'Mutation comparison';
|
|
51
|
-
|
|
52
74
|
if (isLoading) {
|
|
53
|
-
return
|
|
54
|
-
<Headline heading={headline}>
|
|
55
|
-
<LoadingDisplay />
|
|
56
|
-
</Headline>
|
|
57
|
-
);
|
|
75
|
+
return <LoadingDisplay />;
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
if (error !== null) {
|
|
61
|
-
return
|
|
62
|
-
<Headline heading={headline}>
|
|
63
|
-
<ErrorDisplay error={error} />
|
|
64
|
-
</Headline>
|
|
65
|
-
);
|
|
79
|
+
return <ErrorDisplay error={error} />;
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
if (data === null) {
|
|
69
|
-
return
|
|
70
|
-
<Headline heading={headline}>
|
|
71
|
-
<NoDataDisplay />
|
|
72
|
-
</Headline>
|
|
73
|
-
);
|
|
83
|
+
return <NoDataDisplay />;
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
return
|
|
77
|
-
<ResizeContainer size={size} defaultSize={{ height: '700px', width: '100%' }}>
|
|
78
|
-
<Headline heading={headline}>
|
|
79
|
-
<MutationComparisonTabs data={data.mutationData} sequenceType={sequenceType} views={views} />
|
|
80
|
-
</Headline>
|
|
81
|
-
</ResizeContainer>
|
|
82
|
-
);
|
|
86
|
+
return <MutationComparisonTabs data={data.mutationData} sequenceType={sequenceType} views={views} />;
|
|
83
87
|
};
|
|
84
88
|
|
|
85
89
|
type MutationComparisonTabsProps = {
|
|
@@ -182,7 +186,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
182
186
|
getData={() => getMutationComparisonTableData({ content: filteredData }, proportionInterval)}
|
|
183
187
|
filename='mutation_comparison.csv'
|
|
184
188
|
/>
|
|
185
|
-
<Info
|
|
189
|
+
<Info>Info for mutation comparison</Info>
|
|
186
190
|
</div>
|
|
187
191
|
);
|
|
188
192
|
};
|
|
@@ -18,19 +18,34 @@ const meta: Meta<MutationFilterProps> = {
|
|
|
18
18
|
},
|
|
19
19
|
fetchMock: {},
|
|
20
20
|
},
|
|
21
|
+
argTypes: {
|
|
22
|
+
size: {
|
|
23
|
+
control: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
initialValue: {
|
|
28
|
+
control: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
21
33
|
decorators: [withActions],
|
|
22
34
|
};
|
|
23
35
|
|
|
24
36
|
export default meta;
|
|
25
37
|
|
|
26
38
|
export const Default: StoryObj<MutationFilterProps> = {
|
|
27
|
-
render: () => (
|
|
39
|
+
render: (args) => (
|
|
28
40
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
29
41
|
<ReferenceGenomeContext.Provider value={referenceGenome}>
|
|
30
|
-
<MutationFilter />
|
|
42
|
+
<MutationFilter size={args.size} initialValue={args.initialValue} />
|
|
31
43
|
</ReferenceGenomeContext.Provider>
|
|
32
44
|
</LapisUrlContext.Provider>
|
|
33
45
|
),
|
|
46
|
+
args: {
|
|
47
|
+
size: { width: '100%' },
|
|
48
|
+
},
|
|
34
49
|
};
|
|
35
50
|
|
|
36
51
|
export const FiresFilterChangedEvents: StoryObj<MutationFilterProps> = {
|
|
@@ -5,13 +5,19 @@ import { parseAndValidateMutation } from './parseAndValidateMutation';
|
|
|
5
5
|
import { type ReferenceGenome } from '../../lapisApi/ReferenceGenome';
|
|
6
6
|
import { type Deletion, type Insertion, type Mutation, type Substitution } from '../../utils/mutations';
|
|
7
7
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
8
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
8
9
|
import Info from '../components/info';
|
|
10
|
+
import { ResizeContainer, type Size } from '../components/resize-container';
|
|
9
11
|
import { singleGraphColorRGBByName } from '../shared/charts/colors';
|
|
10
12
|
import { DeleteIcon } from '../shared/icons/DeleteIcon';
|
|
11
13
|
|
|
12
|
-
export
|
|
14
|
+
export interface MutationFilterInnerProps {
|
|
13
15
|
initialValue?: SelectedMutationFilterStrings | string[] | undefined;
|
|
14
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MutationFilterProps extends MutationFilterInnerProps {
|
|
19
|
+
size?: Size;
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
export type SelectedFilters = {
|
|
17
23
|
nucleotideMutations: (Substitution | Deletion)[];
|
|
@@ -24,7 +30,19 @@ export type SelectedMutationFilterStrings = {
|
|
|
24
30
|
[Key in keyof SelectedFilters]: string[];
|
|
25
31
|
};
|
|
26
32
|
|
|
27
|
-
export const MutationFilter: FunctionComponent<MutationFilterProps> = ({ initialValue }) => {
|
|
33
|
+
export const MutationFilter: FunctionComponent<MutationFilterProps> = ({ initialValue, size }) => {
|
|
34
|
+
const defaultSize = { width: '100%', height: '6.5rem' };
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<ErrorBoundary size={size} defaultSize={defaultSize}>
|
|
38
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
39
|
+
<MutationFilterInner initialValue={initialValue} />
|
|
40
|
+
</ResizeContainer>
|
|
41
|
+
</ErrorBoundary>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const MutationFilterInner: FunctionComponent<MutationFilterInnerProps> = ({ initialValue }) => {
|
|
28
46
|
const referenceGenome = useContext(ReferenceGenomeContext);
|
|
29
47
|
const [selectedFilters, setSelectedFilters] = useState<SelectedFilters>(
|
|
30
48
|
getInitialState(initialValue, referenceGenome),
|
|
@@ -83,14 +101,14 @@ export const MutationFilter: FunctionComponent<MutationFilterProps> = ({ initial
|
|
|
83
101
|
};
|
|
84
102
|
|
|
85
103
|
return (
|
|
86
|
-
<div class={`rounded-lg border border-gray-300 bg-white p-2`}>
|
|
104
|
+
<div class={`h-full w-full rounded-lg border border-gray-300 bg-white p-2 overflow-scroll`}>
|
|
87
105
|
<div class='flex justify-between'>
|
|
88
106
|
<SelectedMutationDisplay
|
|
89
107
|
selectedFilters={selectedFilters}
|
|
90
108
|
setSelectedFilters={setSelectedFilters}
|
|
91
109
|
fireChangeEvent={fireChangeEvent}
|
|
92
110
|
/>
|
|
93
|
-
<Info
|
|
111
|
+
<Info>Info for mutation filter</Info>
|
|
94
112
|
</div>
|
|
95
113
|
|
|
96
114
|
<form className='mt-2 w-full' onSubmit={handleSubmit} ref={formRef}>
|
|
@@ -295,11 +313,11 @@ const SelectedFilter = <MutationType extends Mutation>({
|
|
|
295
313
|
}: SelectedFilterProps<MutationType>) => {
|
|
296
314
|
return (
|
|
297
315
|
<div
|
|
298
|
-
class='flex items-center flex-nowrap gap-1 rounded me-1 px-2.5 py-0.5 font-medium text-xs mb-1'
|
|
316
|
+
class='flex items-center flex-nowrap gap-1 rounded me-1 px-2.5 py-0.5 font-medium text-xs mb-1 min-w-max'
|
|
299
317
|
style={{ backgroundColor, color: textColor }}
|
|
300
318
|
>
|
|
301
|
-
<div>{mutation.toString()}</div>
|
|
302
|
-
<button onClick={() => onDelete(mutation)}>
|
|
319
|
+
<div className='whitespace-nowrap min-w-max'>{mutation.toString()}</div>
|
|
320
|
+
<button type='button' onClick={() => onDelete(mutation)}>
|
|
303
321
|
<DeleteIcon />
|
|
304
322
|
</button>
|
|
305
323
|
</div>
|
|
@@ -23,6 +23,7 @@ const meta: Meta<MutationsProps> = {
|
|
|
23
23
|
control: { type: 'check' },
|
|
24
24
|
},
|
|
25
25
|
size: [{ control: 'object' }],
|
|
26
|
+
headline: { control: 'text' },
|
|
26
27
|
},
|
|
27
28
|
};
|
|
28
29
|
|
|
@@ -37,6 +38,7 @@ const Template = {
|
|
|
37
38
|
sequenceType={args.sequenceType}
|
|
38
39
|
views={args.views}
|
|
39
40
|
size={args.size}
|
|
41
|
+
headline={args.headline}
|
|
40
42
|
/>
|
|
41
43
|
</ReferenceGenomeContext.Provider>
|
|
42
44
|
</LapisUrlContext.Provider>
|
|
@@ -50,6 +52,7 @@ export const Default: StoryObj<MutationsProps> = {
|
|
|
50
52
|
sequenceType: 'nucleotide',
|
|
51
53
|
views: ['grid', 'table', 'insertions'],
|
|
52
54
|
size: { width: '100%', height: '700px' },
|
|
55
|
+
headline: 'Mutations',
|
|
53
56
|
},
|
|
54
57
|
parameters: {
|
|
55
58
|
fetchMock: {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
17
17
|
import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '../components/SegmentSelector';
|
|
18
18
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
19
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
19
20
|
import { ErrorDisplay } from '../components/error-display';
|
|
20
21
|
import Headline from '../components/headline';
|
|
21
22
|
import Info from '../components/info';
|
|
@@ -30,51 +31,56 @@ import { useQuery } from '../useQuery';
|
|
|
30
31
|
|
|
31
32
|
export type View = 'table' | 'grid' | 'insertions';
|
|
32
33
|
|
|
33
|
-
export interface
|
|
34
|
+
export interface MutationsInnerProps {
|
|
34
35
|
variant: LapisFilter;
|
|
35
36
|
sequenceType: SequenceType;
|
|
36
37
|
views: View[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface MutationsProps extends MutationsInnerProps {
|
|
37
41
|
size?: Size;
|
|
42
|
+
headline?: string;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
export const Mutations: FunctionComponent<MutationsProps> = ({
|
|
45
|
+
export const Mutations: FunctionComponent<MutationsProps> = ({
|
|
46
|
+
variant,
|
|
47
|
+
sequenceType,
|
|
48
|
+
views,
|
|
49
|
+
size,
|
|
50
|
+
headline = 'Mutations',
|
|
51
|
+
}) => {
|
|
52
|
+
const defaultSize = { height: '600px', width: '100%' };
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
|
|
56
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
57
|
+
<Headline heading={headline}>
|
|
58
|
+
<MutationsInner variant={variant} sequenceType={sequenceType} views={views} />
|
|
59
|
+
</Headline>
|
|
60
|
+
</ResizeContainer>
|
|
61
|
+
</ErrorBoundary>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({ variant, sequenceType, views }) => {
|
|
41
66
|
const lapis = useContext(LapisUrlContext);
|
|
42
67
|
const { data, error, isLoading } = useQuery(async () => {
|
|
43
68
|
return queryMutationsData(variant, sequenceType, lapis);
|
|
44
69
|
}, [variant, sequenceType, lapis]);
|
|
45
70
|
|
|
46
|
-
const headline = 'Mutations';
|
|
47
71
|
if (isLoading) {
|
|
48
|
-
return
|
|
49
|
-
<Headline heading={headline}>
|
|
50
|
-
<LoadingDisplay />
|
|
51
|
-
</Headline>
|
|
52
|
-
);
|
|
72
|
+
return <LoadingDisplay />;
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
if (error !== null) {
|
|
56
|
-
return
|
|
57
|
-
<Headline heading={headline}>
|
|
58
|
-
<ErrorDisplay error={error} />
|
|
59
|
-
</Headline>
|
|
60
|
-
);
|
|
76
|
+
return <ErrorDisplay error={error} />;
|
|
61
77
|
}
|
|
62
78
|
|
|
63
79
|
if (data === null) {
|
|
64
|
-
return
|
|
65
|
-
<Headline heading={headline}>
|
|
66
|
-
<NoDataDisplay />
|
|
67
|
-
</Headline>
|
|
68
|
-
);
|
|
80
|
+
return <NoDataDisplay />;
|
|
69
81
|
}
|
|
70
82
|
|
|
71
|
-
return
|
|
72
|
-
<ResizeContainer size={size} defaultSize={{ height: '700px', width: '100%' }}>
|
|
73
|
-
<Headline heading={headline}>
|
|
74
|
-
<MutationsTabs mutationsData={data} sequenceType={sequenceType} views={views} />
|
|
75
|
-
</Headline>
|
|
76
|
-
</ResizeContainer>
|
|
77
|
-
);
|
|
83
|
+
return <MutationsTabs mutationsData={data} sequenceType={sequenceType} views={views} />;
|
|
78
84
|
};
|
|
79
85
|
|
|
80
86
|
type MutationTabsProps = {
|
|
@@ -197,7 +203,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
197
203
|
filename='insertions.csv'
|
|
198
204
|
/>
|
|
199
205
|
)}
|
|
200
|
-
<Info
|
|
206
|
+
<Info>Info for mutations</Info>
|
|
201
207
|
</div>
|
|
202
208
|
);
|
|
203
209
|
};
|
|
@@ -30,6 +30,7 @@ export default {
|
|
|
30
30
|
control: { type: 'check' },
|
|
31
31
|
},
|
|
32
32
|
size: [{ control: 'object' }],
|
|
33
|
+
headline: { control: 'text' },
|
|
33
34
|
},
|
|
34
35
|
};
|
|
35
36
|
|
|
@@ -44,6 +45,7 @@ const Template = {
|
|
|
44
45
|
views={args.views}
|
|
45
46
|
confidenceIntervalMethods={args.confidenceIntervalMethods}
|
|
46
47
|
size={args.size}
|
|
48
|
+
headline={args.headline}
|
|
47
49
|
/>
|
|
48
50
|
</LapisUrlContext.Provider>
|
|
49
51
|
),
|
|
@@ -62,6 +64,7 @@ export const TwoVariants = {
|
|
|
62
64
|
views: ['bar', 'line', 'bubble', 'table'],
|
|
63
65
|
confidenceIntervalMethods: ['wilson'],
|
|
64
66
|
size: { width: '100%', height: '700px' },
|
|
67
|
+
headline: 'Prevalence over time',
|
|
65
68
|
},
|
|
66
69
|
parameters: {
|
|
67
70
|
fetchMock: {
|
|
@@ -128,6 +131,7 @@ export const OneVariant = {
|
|
|
128
131
|
views: ['bar', 'line', 'bubble', 'table'],
|
|
129
132
|
confidenceIntervalMethods: ['wilson'],
|
|
130
133
|
size: { width: '100%', height: '700px' },
|
|
134
|
+
headline: 'Prevalence over time',
|
|
131
135
|
},
|
|
132
136
|
parameters: {
|
|
133
137
|
fetchMock: {
|
|
@@ -11,9 +11,10 @@ import { type NamedLapisFilter, type TemporalGranularity } from '../../types';
|
|
|
11
11
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
12
12
|
import { ConfidenceIntervalSelector } from '../components/confidence-interval-selector';
|
|
13
13
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
14
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
14
15
|
import { ErrorDisplay } from '../components/error-display';
|
|
15
16
|
import Headline from '../components/headline';
|
|
16
|
-
import Info from '../components/info';
|
|
17
|
+
import Info, { InfoHeadline1, InfoParagraph } from '../components/info';
|
|
17
18
|
import { LoadingDisplay } from '../components/loading-display';
|
|
18
19
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
19
20
|
import { ResizeContainer, type Size } from '../components/resize-container';
|
|
@@ -25,14 +26,18 @@ import { useQuery } from '../useQuery';
|
|
|
25
26
|
|
|
26
27
|
export type View = 'bar' | 'line' | 'bubble' | 'table';
|
|
27
28
|
|
|
28
|
-
export interface PrevalenceOverTimeProps {
|
|
29
|
+
export interface PrevalenceOverTimeProps extends PrevalenceOverTimeInnerProps {
|
|
30
|
+
size?: Size;
|
|
31
|
+
headline?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PrevalenceOverTimeInnerProps {
|
|
29
35
|
numerator: NamedLapisFilter | NamedLapisFilter[];
|
|
30
36
|
denominator: NamedLapisFilter;
|
|
31
37
|
granularity: TemporalGranularity;
|
|
32
38
|
smoothingWindow: number;
|
|
33
39
|
views: View[];
|
|
34
40
|
confidenceIntervalMethods: ConfidenceIntervalMethod[];
|
|
35
|
-
size?: Size;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
@@ -43,6 +48,35 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
43
48
|
views,
|
|
44
49
|
confidenceIntervalMethods,
|
|
45
50
|
size,
|
|
51
|
+
headline = 'Prevalence over time',
|
|
52
|
+
}) => {
|
|
53
|
+
const defaultSize = { height: '600px', width: '100%' };
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
|
|
57
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
58
|
+
<Headline heading={headline}>
|
|
59
|
+
<PrevalenceOverTimeInner
|
|
60
|
+
numerator={numerator}
|
|
61
|
+
denominator={denominator}
|
|
62
|
+
granularity={granularity}
|
|
63
|
+
smoothingWindow={smoothingWindow}
|
|
64
|
+
views={views}
|
|
65
|
+
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
66
|
+
/>
|
|
67
|
+
</Headline>
|
|
68
|
+
</ResizeContainer>
|
|
69
|
+
</ErrorBoundary>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerProps> = ({
|
|
74
|
+
numerator,
|
|
75
|
+
denominator,
|
|
76
|
+
granularity,
|
|
77
|
+
smoothingWindow,
|
|
78
|
+
views,
|
|
79
|
+
confidenceIntervalMethods,
|
|
46
80
|
}) => {
|
|
47
81
|
const lapis = useContext(LapisUrlContext);
|
|
48
82
|
|
|
@@ -51,43 +85,25 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
51
85
|
[lapis, numerator, denominator, granularity, smoothingWindow],
|
|
52
86
|
);
|
|
53
87
|
|
|
54
|
-
const headline = 'Prevalence over time';
|
|
55
|
-
|
|
56
88
|
if (isLoading) {
|
|
57
|
-
return
|
|
58
|
-
<Headline heading={headline}>
|
|
59
|
-
<LoadingDisplay />
|
|
60
|
-
</Headline>
|
|
61
|
-
);
|
|
89
|
+
return <LoadingDisplay />;
|
|
62
90
|
}
|
|
63
91
|
|
|
64
92
|
if (error !== null) {
|
|
65
|
-
return
|
|
66
|
-
<Headline heading={headline}>
|
|
67
|
-
<ErrorDisplay error={error} />
|
|
68
|
-
</Headline>
|
|
69
|
-
);
|
|
93
|
+
return <ErrorDisplay error={error} />;
|
|
70
94
|
}
|
|
71
95
|
|
|
72
96
|
if (data === null) {
|
|
73
|
-
return
|
|
74
|
-
<Headline heading={headline}>
|
|
75
|
-
<NoDataDisplay />
|
|
76
|
-
</Headline>
|
|
77
|
-
);
|
|
97
|
+
return <NoDataDisplay />;
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
return (
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
88
|
-
/>
|
|
89
|
-
</Headline>
|
|
90
|
-
</ResizeContainer>
|
|
101
|
+
<PrevalenceOverTimeTabs
|
|
102
|
+
views={views}
|
|
103
|
+
data={data}
|
|
104
|
+
granularity={granularity}
|
|
105
|
+
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
106
|
+
/>
|
|
91
107
|
);
|
|
92
108
|
};
|
|
93
109
|
|
|
@@ -202,9 +218,19 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
202
218
|
getData={() => getPrevalenceOverTimeTableData(data, granularity)}
|
|
203
219
|
filename='prevalence-over-time.csv'
|
|
204
220
|
/>
|
|
205
|
-
|
|
221
|
+
|
|
222
|
+
<PrevalenceOverTimeInfo />
|
|
206
223
|
</div>
|
|
207
224
|
);
|
|
208
225
|
};
|
|
209
226
|
|
|
227
|
+
const PrevalenceOverTimeInfo: FunctionComponent = () => {
|
|
228
|
+
return (
|
|
229
|
+
<Info size={{ width: '600px', height: '30vh' }}>
|
|
230
|
+
<InfoHeadline1>Prevalence over time</InfoHeadline1>
|
|
231
|
+
<InfoParagraph>Prevalence over time info.</InfoParagraph>
|
|
232
|
+
</Info>
|
|
233
|
+
);
|
|
234
|
+
};
|
|
235
|
+
|
|
210
236
|
export default PrevalenceOverTime;
|
|
@@ -19,6 +19,7 @@ export default {
|
|
|
19
19
|
control: { type: 'check' },
|
|
20
20
|
},
|
|
21
21
|
size: [{ control: 'object' }],
|
|
22
|
+
headline: { control: 'text' },
|
|
22
23
|
},
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -31,6 +32,7 @@ export const Primary = {
|
|
|
31
32
|
generationTime={args.generationTime}
|
|
32
33
|
views={args.views}
|
|
33
34
|
size={args.size}
|
|
35
|
+
headline={args.headline}
|
|
34
36
|
/>
|
|
35
37
|
</LapisUrlContext.Provider>
|
|
36
38
|
),
|
|
@@ -40,6 +42,7 @@ export const Primary = {
|
|
|
40
42
|
generationTime: 7,
|
|
41
43
|
views: ['line'],
|
|
42
44
|
size: { width: '100%', height: '700px' },
|
|
45
|
+
headline: 'Relative growth advantage',
|
|
43
46
|
},
|
|
44
47
|
parameters: {
|
|
45
48
|
fetchMock: {
|