@genspectrum/dashboard-components 0.4.5 → 0.5.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/README.md +2 -2
- package/custom-elements.json +178 -102
- package/dist/dashboard-components.js +473 -289
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +93 -57
- package/dist/style.css +53 -13
- package/package.json +5 -5
- package/src/preact/aggregatedData/aggregate-table.tsx +4 -2
- package/src/preact/dateRangeSelector/date-range-selector.tsx +3 -5
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +1 -1
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +18 -18
- package/src/preact/mutationComparison/mutation-comparison.tsx +6 -6
- package/src/preact/mutationComparison/queryMutationData.ts +4 -4
- package/src/preact/mutations/mutations.stories.tsx +3 -3
- package/src/preact/mutations/mutations.tsx +16 -6
- package/src/preact/mutations/queryMutations.ts +3 -3
- package/src/preact/prevalenceOverTime/__mockData__/{denominatorOneVariant.json → denominatorFilterOneDataset.json} +1 -1
- package/src/preact/prevalenceOverTime/__mockData__/{numeratorOneVariant.json → numeratorFilterOneDataset.json} +1 -1
- package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +42 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +26 -7
- package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +62 -28
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +26 -16
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +38 -11
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +39 -7
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +10 -4
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +19 -10
- package/src/preact/shared/charts/confideceInterval.ts +7 -2
- package/src/preact/shared/charts/getYAxisMax.ts +24 -0
- package/src/preact/shared/charts/getYAxisScale.ts +1 -3
- package/src/query/queryAggregateData.ts +3 -3
- package/src/query/queryInsertions.ts +7 -2
- package/src/query/querySubstitutionsOrDeletions.ts +2 -2
- package/src/web-components/input/gs-date-range-selector.tsx +1 -1
- package/src/web-components/input/gs-location-filter.tsx +1 -1
- package/src/web-components/input/gs-mutation-filter.tsx +1 -1
- package/src/web-components/input/gs-text-input.tsx +1 -1
- package/src/web-components/visualization/gs-aggregate.tsx +2 -2
- package/src/web-components/visualization/gs-mutation-comparison.stories.ts +12 -12
- package/src/web-components/visualization/gs-mutation-comparison.tsx +18 -19
- package/src/web-components/visualization/gs-mutations.stories.ts +4 -4
- package/src/web-components/visualization/gs-mutations.tsx +10 -11
- package/src/web-components/visualization/gs-prevalence-over-time.stories.ts +46 -35
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +54 -20
- package/src/web-components/visualization/gs-relative-growth-advantage.stories.ts +32 -18
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +51 -13
- /package/src/preact/mutationComparison/__mockData__/{nucleotideMutationsOtherVariant.json → nucleotideMutationsOtherDataset.json} +0 -0
- /package/src/preact/mutationComparison/__mockData__/{nucleotideMutationsSomeVariant.json → nucleotideMutationsSomeDataset.json} +0 -0
- /package/src/preact/prevalenceOverTime/__mockData__/{denominator.json → denominatorFilter.json} +0 -0
- /package/src/preact/prevalenceOverTime/__mockData__/{numeratorEG.json → numeratorFilterEG.json} +0 -0
- /package/src/preact/prevalenceOverTime/__mockData__/{numeratorJN1.json → numeratorFilterJN1.json} +0 -0
- /package/src/preact/relativeGrowthAdvantage/__mockData__/{denominator.json → denominatorFilter.json} +0 -0
- /package/src/preact/relativeGrowthAdvantage/__mockData__/{numerator.json → numeratorFilter.json} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import denominatorFilter from './__mockData__/denominatorFilter.json';
|
|
2
|
+
import denominatorOneDataset from './__mockData__/denominatorFilterOneDataset.json';
|
|
3
|
+
import numeratorFilterEG from './__mockData__/numeratorFilterEG.json';
|
|
4
|
+
import numeratorFilterJN1 from './__mockData__/numeratorFilterJN1.json';
|
|
5
|
+
import numeratorOneDataset from './__mockData__/numeratorFilterOneDataset.json';
|
|
6
6
|
import { PrevalenceOverTime, type PrevalenceOverTimeProps } from './prevalence-over-time';
|
|
7
7
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
8
8
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
@@ -33,6 +33,7 @@ export default {
|
|
|
33
33
|
height: { control: 'text' },
|
|
34
34
|
headline: { control: 'text' },
|
|
35
35
|
pageSize: { control: 'object' },
|
|
36
|
+
yAxisMaxConfig: { control: 'object' },
|
|
36
37
|
},
|
|
37
38
|
};
|
|
38
39
|
|
|
@@ -40,8 +41,8 @@ const Template = {
|
|
|
40
41
|
render: (args: PrevalenceOverTimeProps) => (
|
|
41
42
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
42
43
|
<PrevalenceOverTime
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
numeratorFilter={args.numeratorFilter}
|
|
45
|
+
denominatorFilter={args.denominatorFilter}
|
|
45
46
|
granularity={args.granularity}
|
|
46
47
|
smoothingWindow={args.smoothingWindow}
|
|
47
48
|
views={args.views}
|
|
@@ -51,6 +52,7 @@ const Template = {
|
|
|
51
52
|
headline={args.headline}
|
|
52
53
|
lapisDateField={args.lapisDateField}
|
|
53
54
|
pageSize={args.pageSize}
|
|
55
|
+
yAxisMaxConfig={args.yAxisMaxConfig}
|
|
54
56
|
/>
|
|
55
57
|
</LapisUrlContext.Provider>
|
|
56
58
|
),
|
|
@@ -59,11 +61,11 @@ const Template = {
|
|
|
59
61
|
export const TwoVariants = {
|
|
60
62
|
...Template,
|
|
61
63
|
args: {
|
|
62
|
-
|
|
64
|
+
numeratorFilter: [
|
|
63
65
|
{ displayName: 'EG', lapisFilter: { country: 'USA', pangoLineage: 'EG*', dateFrom: '2023-01-01' } },
|
|
64
66
|
{ displayName: 'JN.1', lapisFilter: { country: 'USA', pangoLineage: 'JN.1*', dateFrom: '2023-01-01' } },
|
|
65
67
|
],
|
|
66
|
-
|
|
68
|
+
denominatorFilter: { country: 'USA', dateFrom: '2023-01-01' },
|
|
67
69
|
granularity: 'month',
|
|
68
70
|
smoothingWindow: 0,
|
|
69
71
|
views: ['bar', 'line', 'bubble', 'table'],
|
|
@@ -73,6 +75,10 @@ export const TwoVariants = {
|
|
|
73
75
|
headline: 'Prevalence over time',
|
|
74
76
|
lapisDateField: 'date',
|
|
75
77
|
pageSize: 10,
|
|
78
|
+
yAxisMaxConfig: {
|
|
79
|
+
linear: 1,
|
|
80
|
+
logarithmic: 1,
|
|
81
|
+
},
|
|
76
82
|
},
|
|
77
83
|
parameters: {
|
|
78
84
|
fetchMock: {
|
|
@@ -90,7 +96,7 @@ export const TwoVariants = {
|
|
|
90
96
|
},
|
|
91
97
|
response: {
|
|
92
98
|
status: 200,
|
|
93
|
-
body:
|
|
99
|
+
body: numeratorFilterEG,
|
|
94
100
|
},
|
|
95
101
|
},
|
|
96
102
|
{
|
|
@@ -106,7 +112,7 @@ export const TwoVariants = {
|
|
|
106
112
|
},
|
|
107
113
|
response: {
|
|
108
114
|
status: 200,
|
|
109
|
-
body:
|
|
115
|
+
body: numeratorFilterJN1,
|
|
110
116
|
},
|
|
111
117
|
},
|
|
112
118
|
{
|
|
@@ -121,7 +127,7 @@ export const TwoVariants = {
|
|
|
121
127
|
},
|
|
122
128
|
response: {
|
|
123
129
|
status: 200,
|
|
124
|
-
body:
|
|
130
|
+
body: denominatorFilter,
|
|
125
131
|
},
|
|
126
132
|
},
|
|
127
133
|
],
|
|
@@ -132,11 +138,11 @@ export const TwoVariants = {
|
|
|
132
138
|
export const OneVariant = {
|
|
133
139
|
...Template,
|
|
134
140
|
args: {
|
|
135
|
-
|
|
141
|
+
numeratorFilter: {
|
|
136
142
|
displayName: 'EG',
|
|
137
143
|
lapisFilter: { country: 'USA', pangoLineage: 'BA.2.86*', dateFrom: '2023-10-01' },
|
|
138
144
|
},
|
|
139
|
-
|
|
145
|
+
denominatorFilter: { country: 'USA', dateFrom: '2023-10-01' },
|
|
140
146
|
granularity: 'day',
|
|
141
147
|
smoothingWindow: 7,
|
|
142
148
|
views: ['bar', 'line', 'bubble', 'table'],
|
|
@@ -146,6 +152,10 @@ export const OneVariant = {
|
|
|
146
152
|
headline: 'Prevalence over time',
|
|
147
153
|
lapisDateField: 'date',
|
|
148
154
|
pageSize: 10,
|
|
155
|
+
yAxisMaxConfig: {
|
|
156
|
+
linear: 1,
|
|
157
|
+
logarithmic: 1,
|
|
158
|
+
},
|
|
149
159
|
},
|
|
150
160
|
parameters: {
|
|
151
161
|
fetchMock: {
|
|
@@ -163,7 +173,7 @@ export const OneVariant = {
|
|
|
163
173
|
},
|
|
164
174
|
response: {
|
|
165
175
|
status: 200,
|
|
166
|
-
body:
|
|
176
|
+
body: numeratorOneDataset,
|
|
167
177
|
},
|
|
168
178
|
},
|
|
169
179
|
{
|
|
@@ -178,7 +188,7 @@ export const OneVariant = {
|
|
|
178
188
|
},
|
|
179
189
|
response: {
|
|
180
190
|
status: 200,
|
|
181
|
-
body:
|
|
191
|
+
body: denominatorOneDataset,
|
|
182
192
|
},
|
|
183
193
|
},
|
|
184
194
|
],
|
|
@@ -21,6 +21,7 @@ import { ResizeContainer } from '../components/resize-container';
|
|
|
21
21
|
import { ScalingSelector } from '../components/scaling-selector';
|
|
22
22
|
import Tabs from '../components/tabs';
|
|
23
23
|
import { type ConfidenceIntervalMethod } from '../shared/charts/confideceInterval';
|
|
24
|
+
import type { YAxisMaxConfig } from '../shared/charts/getYAxisMax';
|
|
24
25
|
import { type ScaleType } from '../shared/charts/getYAxisScale';
|
|
25
26
|
import { useQuery } from '../useQuery';
|
|
26
27
|
|
|
@@ -33,19 +34,20 @@ export interface PrevalenceOverTimeProps extends PrevalenceOverTimeInnerProps {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export interface PrevalenceOverTimeInnerProps {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
numeratorFilter: NamedLapisFilter | NamedLapisFilter[];
|
|
38
|
+
denominatorFilter: LapisFilter;
|
|
38
39
|
granularity: TemporalGranularity;
|
|
39
40
|
smoothingWindow: number;
|
|
40
41
|
views: View[];
|
|
41
42
|
confidenceIntervalMethods: ConfidenceIntervalMethod[];
|
|
42
43
|
lapisDateField: string;
|
|
43
44
|
pageSize: boolean | number;
|
|
45
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
numeratorFilter,
|
|
50
|
+
denominatorFilter,
|
|
49
51
|
granularity,
|
|
50
52
|
smoothingWindow,
|
|
51
53
|
views,
|
|
@@ -55,6 +57,7 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
55
57
|
headline = 'Prevalence over time',
|
|
56
58
|
lapisDateField,
|
|
57
59
|
pageSize,
|
|
60
|
+
yAxisMaxConfig,
|
|
58
61
|
}) => {
|
|
59
62
|
const size = { height, width };
|
|
60
63
|
|
|
@@ -63,14 +66,15 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
63
66
|
<ResizeContainer size={size}>
|
|
64
67
|
<Headline heading={headline}>
|
|
65
68
|
<PrevalenceOverTimeInner
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
numeratorFilter={numeratorFilter}
|
|
70
|
+
denominatorFilter={denominatorFilter}
|
|
68
71
|
granularity={granularity}
|
|
69
72
|
smoothingWindow={smoothingWindow}
|
|
70
73
|
views={views}
|
|
71
74
|
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
72
75
|
lapisDateField={lapisDateField}
|
|
73
76
|
pageSize={pageSize}
|
|
77
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
74
78
|
/>
|
|
75
79
|
</Headline>
|
|
76
80
|
</ResizeContainer>
|
|
@@ -79,20 +83,29 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerProps> = ({
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
numeratorFilter,
|
|
87
|
+
denominatorFilter,
|
|
84
88
|
granularity,
|
|
85
89
|
smoothingWindow,
|
|
86
90
|
views,
|
|
87
91
|
confidenceIntervalMethods,
|
|
88
92
|
lapisDateField,
|
|
89
93
|
pageSize,
|
|
94
|
+
yAxisMaxConfig,
|
|
90
95
|
}) => {
|
|
91
96
|
const lapis = useContext(LapisUrlContext);
|
|
92
97
|
|
|
93
98
|
const { data, error, isLoading } = useQuery(
|
|
94
|
-
() =>
|
|
95
|
-
|
|
99
|
+
() =>
|
|
100
|
+
queryPrevalenceOverTime(
|
|
101
|
+
numeratorFilter,
|
|
102
|
+
denominatorFilter,
|
|
103
|
+
granularity,
|
|
104
|
+
smoothingWindow,
|
|
105
|
+
lapis,
|
|
106
|
+
lapisDateField,
|
|
107
|
+
),
|
|
108
|
+
[lapis, numeratorFilter, denominatorFilter, granularity, smoothingWindow],
|
|
96
109
|
);
|
|
97
110
|
|
|
98
111
|
if (isLoading) {
|
|
@@ -114,6 +127,7 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerP
|
|
|
114
127
|
granularity={granularity}
|
|
115
128
|
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
116
129
|
pageSize={pageSize}
|
|
130
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
117
131
|
/>
|
|
118
132
|
);
|
|
119
133
|
};
|
|
@@ -124,6 +138,7 @@ type PrevalenceOverTimeTabsProps = {
|
|
|
124
138
|
granularity: TemporalGranularity;
|
|
125
139
|
confidenceIntervalMethods: ConfidenceIntervalMethod[];
|
|
126
140
|
pageSize: boolean | number;
|
|
141
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
127
142
|
};
|
|
128
143
|
|
|
129
144
|
const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = ({
|
|
@@ -132,6 +147,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
132
147
|
granularity,
|
|
133
148
|
confidenceIntervalMethods,
|
|
134
149
|
pageSize,
|
|
150
|
+
yAxisMaxConfig,
|
|
135
151
|
}) => {
|
|
136
152
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
137
153
|
const [confidenceIntervalMethod, setConfidenceIntervalMethod] = useState<ConfidenceIntervalMethod>(
|
|
@@ -148,6 +164,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
148
164
|
data={data}
|
|
149
165
|
yAxisScaleType={yAxisScaleType}
|
|
150
166
|
confidenceIntervalMethod={confidenceIntervalMethod}
|
|
167
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
151
168
|
/>
|
|
152
169
|
),
|
|
153
170
|
};
|
|
@@ -159,13 +176,20 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
159
176
|
data={data}
|
|
160
177
|
yAxisScaleType={yAxisScaleType}
|
|
161
178
|
confidenceIntervalMethod={confidenceIntervalMethod}
|
|
179
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
162
180
|
/>
|
|
163
181
|
),
|
|
164
182
|
};
|
|
165
183
|
case 'bubble':
|
|
166
184
|
return {
|
|
167
185
|
title: 'Bubble',
|
|
168
|
-
content:
|
|
186
|
+
content: (
|
|
187
|
+
<PrevalenceOverTimeBubbleChart
|
|
188
|
+
data={data}
|
|
189
|
+
yAxisScaleType={yAxisScaleType}
|
|
190
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
191
|
+
/>
|
|
192
|
+
),
|
|
169
193
|
};
|
|
170
194
|
case 'table':
|
|
171
195
|
return {
|
|
@@ -245,3 +269,6 @@ const PrevalenceOverTimeInfo: FunctionComponent = () => {
|
|
|
245
269
|
</Info>
|
|
246
270
|
);
|
|
247
271
|
};
|
|
272
|
+
|
|
273
|
+
export const maxInData = (data: PrevalenceOverTimeData) =>
|
|
274
|
+
Math.max(...data.flatMap((variant) => variant.content.map((dataPoint) => dataPoint.prevalence)));
|
|
@@ -5,7 +5,9 @@ import GsChart from '../components/chart';
|
|
|
5
5
|
import { LogitScale } from '../shared/charts/LogitScale';
|
|
6
6
|
import { singleGraphColorRGBByName } from '../shared/charts/colors';
|
|
7
7
|
import { confidenceIntervalDataLabel } from '../shared/charts/confideceInterval';
|
|
8
|
+
import { getYAxisMax, type YAxisMaxConfig } from '../shared/charts/getYAxisMax';
|
|
8
9
|
import { getYAxisScale, type ScaleType } from '../shared/charts/getYAxisScale';
|
|
10
|
+
import { formatProportion } from '../shared/table/formatProportion';
|
|
9
11
|
|
|
10
12
|
interface RelativeGrowthAdvantageChartData {
|
|
11
13
|
t: YearMonthDay[];
|
|
@@ -25,11 +27,17 @@ interface RelativeGrowthAdvantageChartData {
|
|
|
25
27
|
interface RelativeGrowthAdvantageChartProps {
|
|
26
28
|
data: RelativeGrowthAdvantageChartData;
|
|
27
29
|
yAxisScaleType: ScaleType;
|
|
30
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
Chart.register(...registerables, LogitScale);
|
|
31
34
|
|
|
32
|
-
const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType }: RelativeGrowthAdvantageChartProps) => {
|
|
35
|
+
const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType, yAxisMaxConfig }: RelativeGrowthAdvantageChartProps) => {
|
|
36
|
+
const maxY =
|
|
37
|
+
yAxisScaleType !== 'logit'
|
|
38
|
+
? getYAxisMax(Math.max(...data.proportion), yAxisMaxConfig?.[yAxisScaleType])
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
33
41
|
const config: ChartConfiguration = {
|
|
34
42
|
type: 'line',
|
|
35
43
|
data: {
|
|
@@ -39,8 +47,9 @@ const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType }: RelativeGrowthAd
|
|
|
39
47
|
options: {
|
|
40
48
|
maintainAspectRatio: false,
|
|
41
49
|
animation: false,
|
|
50
|
+
|
|
42
51
|
scales: {
|
|
43
|
-
y: getYAxisScale(yAxisScaleType),
|
|
52
|
+
y: { ...getYAxisScale(yAxisScaleType), max: maxY },
|
|
44
53
|
},
|
|
45
54
|
plugins: {
|
|
46
55
|
legend: {
|
|
@@ -52,14 +61,37 @@ const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType }: RelativeGrowthAd
|
|
|
52
61
|
};
|
|
53
62
|
|
|
54
63
|
return (
|
|
55
|
-
<div className='flex flex-col
|
|
64
|
+
<div className='flex h-full flex-col'>
|
|
65
|
+
<RelativeGrowthAdvantageDisplay
|
|
66
|
+
relativeAdvantage={data.params.fd.value}
|
|
67
|
+
relativeAdvantageLowerBound={data.params.fd.ciLower}
|
|
68
|
+
relativeAdvantageUpperBound={data.params.fd.ciUpper}
|
|
69
|
+
/>
|
|
56
70
|
<div className='flex-1'>
|
|
57
71
|
<GsChart configuration={config} />
|
|
58
72
|
</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const RelativeGrowthAdvantageDisplay = ({
|
|
78
|
+
relativeAdvantage,
|
|
79
|
+
relativeAdvantageLowerBound,
|
|
80
|
+
relativeAdvantageUpperBound,
|
|
81
|
+
}: {
|
|
82
|
+
relativeAdvantage: number;
|
|
83
|
+
relativeAdvantageLowerBound: number;
|
|
84
|
+
relativeAdvantageUpperBound: number;
|
|
85
|
+
}) => {
|
|
86
|
+
return (
|
|
87
|
+
<div class='mx-auto flex items-end flex-wrap'>
|
|
88
|
+
<span class='text-[#606060]'>Relative advantage:</span>
|
|
89
|
+
<div>
|
|
90
|
+
<span class='text-2xl ml-3'> {formatProportion(relativeAdvantage)} </span>
|
|
91
|
+
<span class='ml-2.5'>
|
|
92
|
+
({formatProportion(relativeAdvantageLowerBound)} - {formatProportion(relativeAdvantageUpperBound)})
|
|
93
|
+
</span>
|
|
94
|
+
</div>
|
|
63
95
|
</div>
|
|
64
96
|
);
|
|
65
97
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import denominator from './__mockData__/
|
|
2
|
-
import numerator from './__mockData__/
|
|
1
|
+
import denominator from './__mockData__/denominatorFilter.json';
|
|
2
|
+
import numerator from './__mockData__/numeratorFilter.json';
|
|
3
3
|
import { RelativeGrowthAdvantage, type RelativeGrowthAdvantageProps } from './relative-growth-advantage';
|
|
4
4
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
5
5
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
@@ -21,6 +21,7 @@ export default {
|
|
|
21
21
|
width: { control: 'text' },
|
|
22
22
|
height: { control: 'text' },
|
|
23
23
|
headline: { control: 'text' },
|
|
24
|
+
yAxisMaxConfig: { control: 'object' },
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
27
|
|
|
@@ -28,14 +29,15 @@ export const Primary = {
|
|
|
28
29
|
render: (args: RelativeGrowthAdvantageProps) => (
|
|
29
30
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
30
31
|
<RelativeGrowthAdvantage
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
numeratorFilter={args.numeratorFilter}
|
|
33
|
+
denominatorFilter={args.denominatorFilter}
|
|
33
34
|
generationTime={args.generationTime}
|
|
34
35
|
views={args.views}
|
|
35
36
|
width={args.width}
|
|
36
37
|
height={args.height}
|
|
37
38
|
headline={args.headline}
|
|
38
39
|
lapisDateField={args.lapisDateField}
|
|
40
|
+
yAxisMaxConfig={args.yAxisMaxConfig}
|
|
39
41
|
/>
|
|
40
42
|
</LapisUrlContext.Provider>
|
|
41
43
|
),
|
|
@@ -48,6 +50,10 @@ export const Primary = {
|
|
|
48
50
|
height: '700px',
|
|
49
51
|
headline: 'Relative growth advantage',
|
|
50
52
|
lapisDateField: 'date',
|
|
53
|
+
yAxisMaxConfig: {
|
|
54
|
+
linear: 1,
|
|
55
|
+
logarithmic: 1,
|
|
56
|
+
},
|
|
51
57
|
},
|
|
52
58
|
parameters: {
|
|
53
59
|
fetchMock: {
|
|
@@ -17,6 +17,7 @@ import { NoDataDisplay } from '../components/no-data-display';
|
|
|
17
17
|
import { ResizeContainer } from '../components/resize-container';
|
|
18
18
|
import { ScalingSelector } from '../components/scaling-selector';
|
|
19
19
|
import Tabs from '../components/tabs';
|
|
20
|
+
import { type YAxisMaxConfig } from '../shared/charts/getYAxisMax';
|
|
20
21
|
import { type ScaleType } from '../shared/charts/getYAxisScale';
|
|
21
22
|
import { useQuery } from '../useQuery';
|
|
22
23
|
|
|
@@ -29,22 +30,24 @@ export interface RelativeGrowthAdvantageProps extends RelativeGrowthAdvantagePro
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export interface RelativeGrowthAdvantagePropsInner {
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
numeratorFilter: LapisFilter;
|
|
34
|
+
denominatorFilter: LapisFilter;
|
|
34
35
|
generationTime: number;
|
|
35
36
|
views: View[];
|
|
36
37
|
lapisDateField: string;
|
|
38
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageProps> = ({
|
|
40
42
|
views,
|
|
41
43
|
width,
|
|
42
44
|
height,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
numeratorFilter,
|
|
46
|
+
denominatorFilter,
|
|
45
47
|
generationTime,
|
|
46
48
|
headline = 'Relative growth advantage',
|
|
47
49
|
lapisDateField,
|
|
50
|
+
yAxisMaxConfig,
|
|
48
51
|
}) => {
|
|
49
52
|
const size = { height, width };
|
|
50
53
|
|
|
@@ -54,10 +57,11 @@ export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageP
|
|
|
54
57
|
<Headline heading={headline}>
|
|
55
58
|
<RelativeGrowthAdvantageInner
|
|
56
59
|
views={views}
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
numeratorFilter={numeratorFilter}
|
|
61
|
+
denominatorFilter={denominatorFilter}
|
|
59
62
|
generationTime={generationTime}
|
|
60
63
|
lapisDateField={lapisDateField}
|
|
64
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
61
65
|
/>
|
|
62
66
|
</Headline>
|
|
63
67
|
</ResizeContainer>
|
|
@@ -66,18 +70,19 @@ export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageP
|
|
|
66
70
|
};
|
|
67
71
|
|
|
68
72
|
export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvantagePropsInner> = ({
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
numeratorFilter,
|
|
74
|
+
denominatorFilter,
|
|
71
75
|
generationTime,
|
|
72
76
|
views,
|
|
73
77
|
lapisDateField,
|
|
78
|
+
yAxisMaxConfig,
|
|
74
79
|
}) => {
|
|
75
80
|
const lapis = useContext(LapisUrlContext);
|
|
76
81
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
77
82
|
|
|
78
83
|
const { data, error, isLoading } = useQuery(
|
|
79
|
-
() => queryRelativeGrowthAdvantage(
|
|
80
|
-
[lapis,
|
|
84
|
+
() => queryRelativeGrowthAdvantage(numeratorFilter, denominatorFilter, generationTime, lapis, lapisDateField),
|
|
85
|
+
[lapis, numeratorFilter, denominatorFilter, generationTime, views],
|
|
81
86
|
);
|
|
82
87
|
|
|
83
88
|
if (isLoading) {
|
|
@@ -99,6 +104,7 @@ export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvan
|
|
|
99
104
|
setYAxisScaleType={setYAxisScaleType}
|
|
100
105
|
views={views}
|
|
101
106
|
generationTime={generationTime}
|
|
107
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
102
108
|
/>
|
|
103
109
|
);
|
|
104
110
|
};
|
|
@@ -109,6 +115,7 @@ type RelativeGrowthAdvantageTabsProps = {
|
|
|
109
115
|
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
110
116
|
views: View[];
|
|
111
117
|
generationTime: number;
|
|
118
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
112
119
|
};
|
|
113
120
|
|
|
114
121
|
const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabsProps> = ({
|
|
@@ -117,6 +124,7 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
117
124
|
setYAxisScaleType,
|
|
118
125
|
views,
|
|
119
126
|
generationTime,
|
|
127
|
+
yAxisMaxConfig,
|
|
120
128
|
}) => {
|
|
121
129
|
const getTab = (view: View) => {
|
|
122
130
|
switch (view) {
|
|
@@ -131,6 +139,7 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
131
139
|
params: data.params,
|
|
132
140
|
}}
|
|
133
141
|
yAxisScaleType={yAxisScaleType}
|
|
142
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
134
143
|
/>
|
|
135
144
|
),
|
|
136
145
|
};
|
|
@@ -20,10 +20,15 @@ export function wilson95PercentConfidenceInterval(observed: number, sample: numb
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export const confidenceIntervalDataLabel = (
|
|
23
|
+
export const confidenceIntervalDataLabel = (
|
|
24
|
+
value: number,
|
|
25
|
+
lowerLimit?: number,
|
|
26
|
+
upperLimit?: number,
|
|
27
|
+
prefix?: string,
|
|
28
|
+
) => {
|
|
24
29
|
const label = prefix ? `${prefix}: ` : '';
|
|
25
30
|
|
|
26
|
-
return `${label}${value.toFixed(3)} (${lowerLimit
|
|
31
|
+
return `${label}${value.toFixed(3)} (${lowerLimit?.toFixed(3)} - ${upperLimit?.toFixed(3)})`;
|
|
27
32
|
};
|
|
28
33
|
|
|
29
34
|
export type ConfidenceIntervalMethod = 'wilson' | 'none';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface YAxisMaxConfig {
|
|
2
|
+
linear?: AxisMax;
|
|
3
|
+
logarithmic?: AxisMax;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type AxisMax = 'maxInData' | 'limitTo1' | number;
|
|
7
|
+
|
|
8
|
+
export const getYAxisMax = (maxInData: number, axisMax?: AxisMax) => {
|
|
9
|
+
if (!axisMax) {
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
switch (axisMax) {
|
|
14
|
+
case 'limitTo1': {
|
|
15
|
+
return maxInData > 1 ? 1 : maxInData;
|
|
16
|
+
}
|
|
17
|
+
case 'maxInData': {
|
|
18
|
+
return maxInData;
|
|
19
|
+
}
|
|
20
|
+
default: {
|
|
21
|
+
return axisMax;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -6,11 +6,9 @@ export function getYAxisScale(scaleType: ScaleType) {
|
|
|
6
6
|
return { beginAtZero: true, type: 'linear' as const, min: 0, max: 1 };
|
|
7
7
|
}
|
|
8
8
|
case 'logarithmic': {
|
|
9
|
-
return { type: 'logarithmic' as const };
|
|
9
|
+
return { type: 'logarithmic' as const, max: 1 };
|
|
10
10
|
}
|
|
11
11
|
case 'logit':
|
|
12
12
|
return { type: 'logit' as const };
|
|
13
|
-
default:
|
|
14
|
-
return { beginAtZero: true, type: 'linear' as const };
|
|
15
13
|
}
|
|
16
14
|
}
|
|
@@ -8,7 +8,7 @@ export type AggregateData = (Record<string, string | null | number | boolean> &
|
|
|
8
8
|
proportion: number;
|
|
9
9
|
})[];
|
|
10
10
|
|
|
11
|
-
const compareAscending = (a: string | null | number, b: string | null | number) => {
|
|
11
|
+
export const compareAscending = (a: string | null | number, b: string | null | number) => {
|
|
12
12
|
if (typeof a === 'number' && typeof b === 'number') {
|
|
13
13
|
return a - b;
|
|
14
14
|
}
|
|
@@ -20,7 +20,7 @@ const compareAscending = (a: string | null | number, b: string | null | number)
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export async function queryAggregateData(
|
|
23
|
-
|
|
23
|
+
lapisFilter: LapisFilter,
|
|
24
24
|
fields: string[],
|
|
25
25
|
lapis: string,
|
|
26
26
|
initialSort: InitialSort = { field: 'count', direction: 'descending' },
|
|
@@ -31,7 +31,7 @@ export async function queryAggregateData(
|
|
|
31
31
|
throw new Error(`InitialSort field not in fields. Valid fields are: ${validSortFields.join(', ')}`);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const fetchData = new FetchAggregatedOperator<Record<string, string | null | number>>(
|
|
34
|
+
const fetchData = new FetchAggregatedOperator<Record<string, string | null | number>>(lapisFilter, fields);
|
|
35
35
|
const sortData = new SortOperator(fetchData, (a, b) => {
|
|
36
36
|
return initialSort.direction === 'ascending'
|
|
37
37
|
? compareAscending(a[initialSort.field], b[initialSort.field])
|
|
@@ -2,8 +2,13 @@ import { FetchInsertionsOperator } from '../operator/FetchInsertionsOperator';
|
|
|
2
2
|
import { SortOperator } from '../operator/SortOperator';
|
|
3
3
|
import { type LapisFilter, type SequenceType } from '../types';
|
|
4
4
|
|
|
5
|
-
export function queryInsertions(
|
|
6
|
-
|
|
5
|
+
export function queryInsertions(
|
|
6
|
+
lapisFilter: LapisFilter,
|
|
7
|
+
sequenceType: SequenceType,
|
|
8
|
+
lapis: string,
|
|
9
|
+
signal?: AbortSignal,
|
|
10
|
+
) {
|
|
11
|
+
const fetchData = new FetchInsertionsOperator(lapisFilter, sequenceType);
|
|
7
12
|
const sortData = new SortOperator(fetchData, (a, b) => {
|
|
8
13
|
if (a.mutation.segment !== b.mutation.segment) {
|
|
9
14
|
return (a.mutation.segment ?? '').localeCompare(b.mutation.segment ?? '');
|
|
@@ -3,12 +3,12 @@ import { SortOperator } from '../operator/SortOperator';
|
|
|
3
3
|
import { type LapisFilter, type SequenceType } from '../types';
|
|
4
4
|
|
|
5
5
|
export function querySubstitutionsOrDeletions(
|
|
6
|
-
|
|
6
|
+
lapisFilter: LapisFilter,
|
|
7
7
|
sequenceType: SequenceType,
|
|
8
8
|
lapis: string,
|
|
9
9
|
signal?: AbortSignal,
|
|
10
10
|
) {
|
|
11
|
-
const fetchData = new FetchSubstitutionsOrDeletionsOperator(
|
|
11
|
+
const fetchData = new FetchSubstitutionsOrDeletionsOperator(lapisFilter, sequenceType, 0);
|
|
12
12
|
const sortData = new SortOperator(fetchData, (a, b) => {
|
|
13
13
|
if (a.mutation.segment !== b.mutation.segment) {
|
|
14
14
|
return (a.mutation.segment ?? '').localeCompare(b.mutation.segment ?? '');
|
|
@@ -91,7 +91,7 @@ export class DateRangeSelectorComponent extends PreactLitAdapter {
|
|
|
91
91
|
/**
|
|
92
92
|
* The width of the component.
|
|
93
93
|
*
|
|
94
|
-
* Visit https://genspectrum.github.io/
|
|
94
|
+
* Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
|
|
95
95
|
*/
|
|
96
96
|
@property({ type: String })
|
|
97
97
|
width: string = '100%';
|
|
@@ -54,7 +54,7 @@ export class LocationFilterComponent extends PreactLitAdapter {
|
|
|
54
54
|
/**
|
|
55
55
|
* The width of the component.
|
|
56
56
|
*
|
|
57
|
-
* Visit https://genspectrum.github.io/
|
|
57
|
+
* Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
|
|
58
58
|
*/
|
|
59
59
|
@property({ type: String })
|
|
60
60
|
width: string = '100%';
|
|
@@ -86,7 +86,7 @@ export class MutationFilterComponent extends PreactLitAdapter {
|
|
|
86
86
|
/**
|
|
87
87
|
* The width of the component.
|
|
88
88
|
*
|
|
89
|
-
* Visit https://genspectrum.github.io/
|
|
89
|
+
* Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
|
|
90
90
|
*/
|
|
91
91
|
@property({ type: String })
|
|
92
92
|
width: string = '100%';
|