@genspectrum/dashboard-components 0.4.4 → 0.5.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/README.md +2 -2
- package/custom-elements.json +279 -108
- package/dist/dashboard-components.js +495 -283
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +115 -55
- package/dist/style.css +34 -7
- package/package.json +5 -5
- package/src/preact/aggregatedData/aggregate-table.tsx +3 -2
- package/src/preact/aggregatedData/aggregate.stories.tsx +2 -0
- package/src/preact/aggregatedData/aggregate.tsx +8 -3
- package/src/preact/components/table.stories.tsx +51 -1
- package/src/preact/components/table.tsx +4 -3
- package/src/preact/locationFilter/location-filter.stories.tsx +12 -1
- package/src/preact/locationFilter/location-filter.tsx +10 -3
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +7 -2
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +1 -1
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +21 -18
- package/src/preact/mutationComparison/mutation-comparison.tsx +30 -8
- package/src/preact/mutationComparison/queryMutationData.ts +4 -4
- package/src/preact/mutations/mutations-grid.tsx +8 -2
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -2
- package/src/preact/mutations/mutations-table.tsx +3 -2
- package/src/preact/mutations/mutations.stories.tsx +6 -3
- package/src/preact/mutations/mutations.tsx +30 -10
- 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-table.tsx +3 -2
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +30 -16
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +46 -12
- 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 +2 -2
- 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.stories.ts +11 -0
- package/src/web-components/input/gs-location-filter.tsx +15 -2
- 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.stories.ts +4 -0
- package/src/web-components/visualization/gs-aggregate.tsx +10 -2
- package/src/web-components/visualization/gs-mutation-comparison.stories.ts +16 -12
- package/src/web-components/visualization/gs-mutation-comparison.tsx +26 -19
- package/src/web-components/visualization/gs-mutations.stories.ts +8 -4
- package/src/web-components/visualization/gs-mutations.tsx +18 -11
- package/src/web-components/visualization/gs-prevalence-over-time.stories.ts +51 -35
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +66 -24
- 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
|
@@ -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,18 +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;
|
|
44
|
+
pageSize: boolean | number;
|
|
45
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
numeratorFilter,
|
|
50
|
+
denominatorFilter,
|
|
48
51
|
granularity,
|
|
49
52
|
smoothingWindow,
|
|
50
53
|
views,
|
|
@@ -53,6 +56,8 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
53
56
|
height,
|
|
54
57
|
headline = 'Prevalence over time',
|
|
55
58
|
lapisDateField,
|
|
59
|
+
pageSize,
|
|
60
|
+
yAxisMaxConfig,
|
|
56
61
|
}) => {
|
|
57
62
|
const size = { height, width };
|
|
58
63
|
|
|
@@ -61,13 +66,15 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
61
66
|
<ResizeContainer size={size}>
|
|
62
67
|
<Headline heading={headline}>
|
|
63
68
|
<PrevalenceOverTimeInner
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
numeratorFilter={numeratorFilter}
|
|
70
|
+
denominatorFilter={denominatorFilter}
|
|
66
71
|
granularity={granularity}
|
|
67
72
|
smoothingWindow={smoothingWindow}
|
|
68
73
|
views={views}
|
|
69
74
|
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
70
75
|
lapisDateField={lapisDateField}
|
|
76
|
+
pageSize={pageSize}
|
|
77
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
71
78
|
/>
|
|
72
79
|
</Headline>
|
|
73
80
|
</ResizeContainer>
|
|
@@ -76,19 +83,29 @@ export const PrevalenceOverTime: FunctionComponent<PrevalenceOverTimeProps> = ({
|
|
|
76
83
|
};
|
|
77
84
|
|
|
78
85
|
export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerProps> = ({
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
numeratorFilter,
|
|
87
|
+
denominatorFilter,
|
|
81
88
|
granularity,
|
|
82
89
|
smoothingWindow,
|
|
83
90
|
views,
|
|
84
91
|
confidenceIntervalMethods,
|
|
85
92
|
lapisDateField,
|
|
93
|
+
pageSize,
|
|
94
|
+
yAxisMaxConfig,
|
|
86
95
|
}) => {
|
|
87
96
|
const lapis = useContext(LapisUrlContext);
|
|
88
97
|
|
|
89
98
|
const { data, error, isLoading } = useQuery(
|
|
90
|
-
() =>
|
|
91
|
-
|
|
99
|
+
() =>
|
|
100
|
+
queryPrevalenceOverTime(
|
|
101
|
+
numeratorFilter,
|
|
102
|
+
denominatorFilter,
|
|
103
|
+
granularity,
|
|
104
|
+
smoothingWindow,
|
|
105
|
+
lapis,
|
|
106
|
+
lapisDateField,
|
|
107
|
+
),
|
|
108
|
+
[lapis, numeratorFilter, denominatorFilter, granularity, smoothingWindow],
|
|
92
109
|
);
|
|
93
110
|
|
|
94
111
|
if (isLoading) {
|
|
@@ -109,6 +126,8 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeInnerP
|
|
|
109
126
|
data={data}
|
|
110
127
|
granularity={granularity}
|
|
111
128
|
confidenceIntervalMethods={confidenceIntervalMethods}
|
|
129
|
+
pageSize={pageSize}
|
|
130
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
112
131
|
/>
|
|
113
132
|
);
|
|
114
133
|
};
|
|
@@ -118,6 +137,8 @@ type PrevalenceOverTimeTabsProps = {
|
|
|
118
137
|
data: PrevalenceOverTimeData;
|
|
119
138
|
granularity: TemporalGranularity;
|
|
120
139
|
confidenceIntervalMethods: ConfidenceIntervalMethod[];
|
|
140
|
+
pageSize: boolean | number;
|
|
141
|
+
yAxisMaxConfig: YAxisMaxConfig;
|
|
121
142
|
};
|
|
122
143
|
|
|
123
144
|
const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = ({
|
|
@@ -125,6 +146,8 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
125
146
|
data,
|
|
126
147
|
granularity,
|
|
127
148
|
confidenceIntervalMethods,
|
|
149
|
+
pageSize,
|
|
150
|
+
yAxisMaxConfig,
|
|
128
151
|
}) => {
|
|
129
152
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
130
153
|
const [confidenceIntervalMethod, setConfidenceIntervalMethod] = useState<ConfidenceIntervalMethod>(
|
|
@@ -141,6 +164,7 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
141
164
|
data={data}
|
|
142
165
|
yAxisScaleType={yAxisScaleType}
|
|
143
166
|
confidenceIntervalMethod={confidenceIntervalMethod}
|
|
167
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
144
168
|
/>
|
|
145
169
|
),
|
|
146
170
|
};
|
|
@@ -152,18 +176,25 @@ const PrevalenceOverTimeTabs: FunctionComponent<PrevalenceOverTimeTabsProps> = (
|
|
|
152
176
|
data={data}
|
|
153
177
|
yAxisScaleType={yAxisScaleType}
|
|
154
178
|
confidenceIntervalMethod={confidenceIntervalMethod}
|
|
179
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
155
180
|
/>
|
|
156
181
|
),
|
|
157
182
|
};
|
|
158
183
|
case 'bubble':
|
|
159
184
|
return {
|
|
160
185
|
title: 'Bubble',
|
|
161
|
-
content:
|
|
186
|
+
content: (
|
|
187
|
+
<PrevalenceOverTimeBubbleChart
|
|
188
|
+
data={data}
|
|
189
|
+
yAxisScaleType={yAxisScaleType}
|
|
190
|
+
yAxisMaxConfig={yAxisMaxConfig}
|
|
191
|
+
/>
|
|
192
|
+
),
|
|
162
193
|
};
|
|
163
194
|
case 'table':
|
|
164
195
|
return {
|
|
165
196
|
title: 'Table',
|
|
166
|
-
content: <PrevalenceOverTimeTable data={data} granularity={granularity} />,
|
|
197
|
+
content: <PrevalenceOverTimeTable data={data} granularity={granularity} pageSize={pageSize} />,
|
|
167
198
|
};
|
|
168
199
|
}
|
|
169
200
|
};
|
|
@@ -238,3 +269,6 @@ const PrevalenceOverTimeInfo: FunctionComponent = () => {
|
|
|
238
269
|
</Info>
|
|
239
270
|
);
|
|
240
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
|
}
|
|
@@ -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%';
|
|
@@ -17,6 +17,7 @@ const codeExample = String.raw`
|
|
|
17
17
|
fields='["region", "country"]'
|
|
18
18
|
initialValue='Europe / Switzerland'
|
|
19
19
|
width="100%"
|
|
20
|
+
placeholderText="Enter a location"
|
|
20
21
|
></gs-location-filter>`;
|
|
21
22
|
|
|
22
23
|
const meta: Meta = {
|
|
@@ -48,6 +49,11 @@ const meta: Meta = {
|
|
|
48
49
|
type: 'text',
|
|
49
50
|
},
|
|
50
51
|
},
|
|
52
|
+
placeholderText: {
|
|
53
|
+
control: {
|
|
54
|
+
type: 'text',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
51
57
|
},
|
|
52
58
|
decorators: [withActions],
|
|
53
59
|
tags: ['autodocs'],
|
|
@@ -63,6 +69,7 @@ const Template: StoryObj<LocationFilterProps> = {
|
|
|
63
69
|
.fields=${args.fields}
|
|
64
70
|
initialValue=${ifDefined(args.initialValue)}
|
|
65
71
|
.width=${args.width}
|
|
72
|
+
placeholderText=${ifDefined(args.placeholderText)}
|
|
66
73
|
></gs-location-filter>
|
|
67
74
|
</div>
|
|
68
75
|
</gs-app>`;
|
|
@@ -71,6 +78,7 @@ const Template: StoryObj<LocationFilterProps> = {
|
|
|
71
78
|
fields: ['region', 'country', 'division', 'location'],
|
|
72
79
|
initialValue: '',
|
|
73
80
|
width: '100%',
|
|
81
|
+
placeholderText: 'Enter a location',
|
|
74
82
|
},
|
|
75
83
|
};
|
|
76
84
|
|
|
@@ -102,6 +110,9 @@ export const LocationFilter: StoryObj<LocationFilterProps> = {
|
|
|
102
110
|
await waitFor(() => {
|
|
103
111
|
return expect(canvas.getByRole('combobox')).toBeEnabled();
|
|
104
112
|
});
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
return expect(canvas.getByPlaceholderText('Enter a location')).toBeInTheDocument();
|
|
115
|
+
});
|
|
105
116
|
},
|
|
106
117
|
};
|
|
107
118
|
|
|
@@ -54,13 +54,26 @@ 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%';
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* The placeholder text to display in the input field, if it is empty.
|
|
64
|
+
*/
|
|
65
|
+
@property()
|
|
66
|
+
placeholderText: string = '';
|
|
67
|
+
|
|
62
68
|
override render() {
|
|
63
|
-
return
|
|
69
|
+
return (
|
|
70
|
+
<LocationFilter
|
|
71
|
+
initialValue={this.initialValue}
|
|
72
|
+
fields={this.fields}
|
|
73
|
+
width={this.width}
|
|
74
|
+
placeholderText={this.placeholderText}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
64
77
|
}
|
|
65
78
|
}
|
|
66
79
|
|
|
@@ -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%';
|
|
@@ -45,7 +45,7 @@ export class TextInputComponent extends PreactLitAdapter {
|
|
|
45
45
|
/**
|
|
46
46
|
* The width of the component.
|
|
47
47
|
*
|
|
48
|
-
* Visit https://genspectrum.github.io/
|
|
48
|
+
* Visit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.
|
|
49
49
|
*/
|
|
50
50
|
@property({ type: String })
|
|
51
51
|
width: string = '100%';
|
|
@@ -19,6 +19,7 @@ const codeExample = `
|
|
|
19
19
|
height='700px'
|
|
20
20
|
initialSortField="count"
|
|
21
21
|
initialSortDirection="descending"
|
|
22
|
+
pageSize="10"
|
|
22
23
|
></gs-aggregate>`;
|
|
23
24
|
|
|
24
25
|
const meta: Meta<Required<AggregateProps>> = {
|
|
@@ -33,6 +34,7 @@ const meta: Meta<Required<AggregateProps>> = {
|
|
|
33
34
|
width: { control: 'text' },
|
|
34
35
|
height: { control: 'text' },
|
|
35
36
|
headline: { control: 'text' },
|
|
37
|
+
pageSize: { control: 'object' },
|
|
36
38
|
initialSortField: { control: 'text' },
|
|
37
39
|
initialSortDirection: {
|
|
38
40
|
options: ['ascending', 'descending'],
|
|
@@ -81,6 +83,7 @@ export const Table: StoryObj<Required<AggregateProps>> = {
|
|
|
81
83
|
.headline=${args.headline}
|
|
82
84
|
.initialSortField=${args.initialSortField}
|
|
83
85
|
.initialSortDirection=${args.initialSortDirection}
|
|
86
|
+
.pageSize=${args.pageSize}
|
|
84
87
|
></gs-aggregate>
|
|
85
88
|
</gs-app>
|
|
86
89
|
`,
|
|
@@ -95,5 +98,6 @@ export const Table: StoryObj<Required<AggregateProps>> = {
|
|
|
95
98
|
headline: 'Aggregate',
|
|
96
99
|
initialSortField: 'count',
|
|
97
100
|
initialSortDirection: 'descending',
|
|
101
|
+
pageSize: 10,
|
|
98
102
|
},
|
|
99
103
|
};
|