@genspectrum/dashboard-components 0.7.0 → 0.7.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/dist/dashboard-components.js +200 -203
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +14 -14
- package/package.json +1 -1
- package/src/preact/aggregatedData/aggregate.tsx +41 -33
- package/src/preact/mutationComparison/mutation-comparison.tsx +32 -34
- package/src/preact/mutations/mutations.tsx +63 -56
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +33 -25
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +46 -64
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +29 -36
- package/standalone-bundle/dashboard-components.js +9689 -9706
- package/standalone-bundle/dashboard-components.js.map +1 -1
|
@@ -1058,10 +1058,10 @@ declare global {
|
|
|
1058
1058
|
|
|
1059
1059
|
declare global {
|
|
1060
1060
|
interface HTMLElementTagNameMap {
|
|
1061
|
-
'gs-
|
|
1061
|
+
'gs-text-input': TextInputComponent;
|
|
1062
1062
|
}
|
|
1063
1063
|
interface HTMLElementEventMap {
|
|
1064
|
-
'gs-
|
|
1064
|
+
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
@@ -1069,7 +1069,7 @@ declare global {
|
|
|
1069
1069
|
declare global {
|
|
1070
1070
|
namespace JSX {
|
|
1071
1071
|
interface IntrinsicElements {
|
|
1072
|
-
'gs-
|
|
1072
|
+
'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1073
1073
|
}
|
|
1074
1074
|
}
|
|
1075
1075
|
}
|
|
@@ -1077,10 +1077,10 @@ declare global {
|
|
|
1077
1077
|
|
|
1078
1078
|
declare global {
|
|
1079
1079
|
interface HTMLElementTagNameMap {
|
|
1080
|
-
'gs-
|
|
1080
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1081
1081
|
}
|
|
1082
1082
|
interface HTMLElementEventMap {
|
|
1083
|
-
'gs-
|
|
1083
|
+
'gs-location-changed': CustomEvent<Record<string, string>>;
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
1086
1086
|
|
|
@@ -1088,7 +1088,7 @@ declare global {
|
|
|
1088
1088
|
declare global {
|
|
1089
1089
|
namespace JSX {
|
|
1090
1090
|
interface IntrinsicElements {
|
|
1091
|
-
'gs-
|
|
1091
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1092
1092
|
}
|
|
1093
1093
|
}
|
|
1094
1094
|
}
|
|
@@ -1183,7 +1183,7 @@ declare global {
|
|
|
1183
1183
|
|
|
1184
1184
|
declare global {
|
|
1185
1185
|
interface HTMLElementTagNameMap {
|
|
1186
|
-
'gs-
|
|
1186
|
+
'gs-aggregate-component': AggregateComponent;
|
|
1187
1187
|
}
|
|
1188
1188
|
}
|
|
1189
1189
|
|
|
@@ -1191,7 +1191,7 @@ declare global {
|
|
|
1191
1191
|
declare global {
|
|
1192
1192
|
namespace JSX {
|
|
1193
1193
|
interface IntrinsicElements {
|
|
1194
|
-
'gs-
|
|
1194
|
+
'gs-aggregate-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1195
1195
|
}
|
|
1196
1196
|
}
|
|
1197
1197
|
}
|
|
@@ -1199,7 +1199,7 @@ declare global {
|
|
|
1199
1199
|
|
|
1200
1200
|
declare global {
|
|
1201
1201
|
interface HTMLElementTagNameMap {
|
|
1202
|
-
'gs-
|
|
1202
|
+
'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
|
|
1203
1203
|
}
|
|
1204
1204
|
}
|
|
1205
1205
|
|
|
@@ -1207,7 +1207,7 @@ declare global {
|
|
|
1207
1207
|
declare global {
|
|
1208
1208
|
namespace JSX {
|
|
1209
1209
|
interface IntrinsicElements {
|
|
1210
|
-
'gs-
|
|
1210
|
+
'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1211
1211
|
}
|
|
1212
1212
|
}
|
|
1213
1213
|
}
|
|
@@ -1215,7 +1215,7 @@ declare global {
|
|
|
1215
1215
|
|
|
1216
1216
|
declare global {
|
|
1217
1217
|
interface HTMLElementTagNameMap {
|
|
1218
|
-
'gs-
|
|
1218
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
1219
1219
|
}
|
|
1220
1220
|
}
|
|
1221
1221
|
|
|
@@ -1223,7 +1223,7 @@ declare global {
|
|
|
1223
1223
|
declare global {
|
|
1224
1224
|
namespace JSX {
|
|
1225
1225
|
interface IntrinsicElements {
|
|
1226
|
-
'gs-
|
|
1226
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1227
1227
|
}
|
|
1228
1228
|
}
|
|
1229
1229
|
}
|
|
@@ -1231,7 +1231,7 @@ declare global {
|
|
|
1231
1231
|
|
|
1232
1232
|
declare global {
|
|
1233
1233
|
interface HTMLElementTagNameMap {
|
|
1234
|
-
'gs-
|
|
1234
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
1235
1235
|
}
|
|
1236
1236
|
}
|
|
1237
1237
|
|
|
@@ -1239,7 +1239,7 @@ declare global {
|
|
|
1239
1239
|
declare global {
|
|
1240
1240
|
namespace JSX {
|
|
1241
1241
|
interface IntrinsicElements {
|
|
1242
|
-
'gs-
|
|
1242
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1243
1243
|
}
|
|
1244
1244
|
}
|
|
1245
1245
|
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
|
|
|
9
9
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
10
10
|
import { ErrorDisplay } from '../components/error-display';
|
|
11
11
|
import { Fullscreen } from '../components/fullscreen';
|
|
12
|
-
import Info, { InfoHeadline1, InfoParagraph } from '../components/info';
|
|
12
|
+
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
13
13
|
import { LoadingDisplay } from '../components/loading-display';
|
|
14
14
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
15
15
|
import { ResizeContainer } from '../components/resize-container';
|
|
@@ -22,37 +22,29 @@ export type InitialSort = { field: string; direction: 'ascending' | 'descending'
|
|
|
22
22
|
export type AggregateProps = {
|
|
23
23
|
width: string;
|
|
24
24
|
height: string;
|
|
25
|
-
} & AggregateInnerProps;
|
|
26
|
-
|
|
27
|
-
export interface AggregateInnerProps {
|
|
28
25
|
filter: LapisFilter;
|
|
29
26
|
fields: string[];
|
|
30
27
|
views: View[];
|
|
31
28
|
initialSortField: string;
|
|
32
29
|
initialSortDirection: 'ascending' | 'descending';
|
|
33
30
|
pageSize: boolean | number;
|
|
34
|
-
}
|
|
31
|
+
};
|
|
35
32
|
|
|
36
|
-
export const Aggregate: FunctionComponent<AggregateProps> = (
|
|
33
|
+
export const Aggregate: FunctionComponent<AggregateProps> = (componentProps) => {
|
|
34
|
+
const { width, height } = componentProps;
|
|
37
35
|
const size = { height, width };
|
|
38
36
|
|
|
39
37
|
return (
|
|
40
38
|
<ErrorBoundary size={size}>
|
|
41
39
|
<ResizeContainer size={size}>
|
|
42
|
-
<AggregateInner {...
|
|
40
|
+
<AggregateInner {...componentProps} />
|
|
43
41
|
</ResizeContainer>
|
|
44
42
|
</ErrorBoundary>
|
|
45
43
|
);
|
|
46
44
|
};
|
|
47
45
|
|
|
48
|
-
export const AggregateInner: FunctionComponent<
|
|
49
|
-
fields,
|
|
50
|
-
views,
|
|
51
|
-
filter,
|
|
52
|
-
initialSortField,
|
|
53
|
-
initialSortDirection,
|
|
54
|
-
pageSize,
|
|
55
|
-
}) => {
|
|
46
|
+
export const AggregateInner: FunctionComponent<AggregateProps> = (componentProps) => {
|
|
47
|
+
const { fields, filter, initialSortField, initialSortDirection } = componentProps;
|
|
56
48
|
const lapis = useContext(LapisUrlContext);
|
|
57
49
|
|
|
58
50
|
const { data, error, isLoading } = useQuery(async () => {
|
|
@@ -71,50 +63,66 @@ export const AggregateInner: FunctionComponent<AggregateInnerProps> = ({
|
|
|
71
63
|
return <NoDataDisplay />;
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
return <AggregatedDataTabs data={data}
|
|
66
|
+
return <AggregatedDataTabs data={data} originalComponentProps={componentProps} />;
|
|
75
67
|
};
|
|
76
68
|
|
|
77
69
|
type AggregatedDataTabsProps = {
|
|
78
70
|
data: AggregateData;
|
|
79
|
-
|
|
80
|
-
views: View[];
|
|
81
|
-
pageSize: boolean | number;
|
|
71
|
+
originalComponentProps: AggregateProps;
|
|
82
72
|
};
|
|
83
73
|
|
|
84
|
-
const AggregatedDataTabs: FunctionComponent<AggregatedDataTabsProps> = ({ data,
|
|
74
|
+
const AggregatedDataTabs: FunctionComponent<AggregatedDataTabsProps> = ({ data, originalComponentProps }) => {
|
|
85
75
|
const getTab = (view: View) => {
|
|
86
76
|
switch (view) {
|
|
87
77
|
case 'table':
|
|
88
78
|
return {
|
|
89
79
|
title: 'Table',
|
|
90
|
-
content:
|
|
80
|
+
content: (
|
|
81
|
+
<AggregateTable
|
|
82
|
+
data={data}
|
|
83
|
+
fields={originalComponentProps.fields}
|
|
84
|
+
pageSize={originalComponentProps.pageSize}
|
|
85
|
+
/>
|
|
86
|
+
),
|
|
91
87
|
};
|
|
92
88
|
}
|
|
93
89
|
};
|
|
94
90
|
|
|
95
|
-
const tabs = views.map((view) => getTab(view));
|
|
91
|
+
const tabs = originalComponentProps.views.map((view) => getTab(view));
|
|
96
92
|
|
|
97
|
-
return <Tabs tabs={tabs} toolbar={<Toolbar data={data}
|
|
93
|
+
return <Tabs tabs={tabs} toolbar={<Toolbar data={data} originalComponentProps={originalComponentProps} />} />;
|
|
98
94
|
};
|
|
99
95
|
|
|
100
96
|
type ToolbarProps = {
|
|
101
97
|
data: AggregateData;
|
|
102
|
-
|
|
98
|
+
originalComponentProps: AggregateProps;
|
|
103
99
|
};
|
|
104
100
|
|
|
105
|
-
const Toolbar: FunctionComponent<ToolbarProps> = ({ data,
|
|
101
|
+
const Toolbar: FunctionComponent<ToolbarProps> = ({ data, originalComponentProps }) => {
|
|
106
102
|
return (
|
|
107
103
|
<div class='flex flex-row'>
|
|
108
104
|
<CsvDownloadButton className='mx-1 btn btn-xs' getData={() => data} filename='aggregate.csv' />
|
|
109
|
-
<
|
|
110
|
-
<InfoHeadline1>Aggregated data</InfoHeadline1>
|
|
111
|
-
<InfoParagraph>
|
|
112
|
-
This table shows the number and proportion of sequences stratified by the following fields:{' '}
|
|
113
|
-
{fields.join(', ')}. The proportion is calculated with respect to the total count within the
|
|
114
|
-
filtered dataset.
|
|
115
|
-
</InfoParagraph>
|
|
116
|
-
</Info>
|
|
105
|
+
<AggregateInfo originalComponentProps={originalComponentProps} />
|
|
117
106
|
<Fullscreen />
|
|
118
107
|
</div>
|
|
119
108
|
);
|
|
120
109
|
};
|
|
110
|
+
|
|
111
|
+
type AggregateInfoProps = {
|
|
112
|
+
originalComponentProps: AggregateProps;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const AggregateInfo: FunctionComponent<AggregateInfoProps> = ({ originalComponentProps }) => {
|
|
116
|
+
const lapis = useContext(LapisUrlContext);
|
|
117
|
+
return (
|
|
118
|
+
<Info>
|
|
119
|
+
<InfoHeadline1>Aggregated data</InfoHeadline1>
|
|
120
|
+
<InfoParagraph>
|
|
121
|
+
This table shows the number and proportion of sequences stratified by the following fields:{' '}
|
|
122
|
+
{originalComponentProps.fields.join(', ')}. The proportion is calculated with respect to the total count
|
|
123
|
+
within the filtered dataset.
|
|
124
|
+
</InfoParagraph>
|
|
125
|
+
<InfoComponentCode componentName='aggregate' params={originalComponentProps} lapisUrl={lapis} />
|
|
126
|
+
</Info>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
@@ -11,7 +11,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
|
|
|
11
11
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
12
12
|
import { ErrorDisplay } from '../components/error-display';
|
|
13
13
|
import { Fullscreen } from '../components/fullscreen';
|
|
14
|
-
import Info from '../components/info';
|
|
14
|
+
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
15
15
|
import { LoadingDisplay } from '../components/loading-display';
|
|
16
16
|
import { type DisplayedMutationType, MutationTypeSelector } from '../components/mutation-type-selector';
|
|
17
17
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
@@ -24,36 +24,30 @@ import { useQuery } from '../useQuery';
|
|
|
24
24
|
|
|
25
25
|
export type View = 'table' | 'venn';
|
|
26
26
|
|
|
27
|
-
export interface MutationComparisonProps
|
|
27
|
+
export interface MutationComparisonProps {
|
|
28
28
|
width: string;
|
|
29
29
|
height: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface MutationComparisonInnerProps {
|
|
33
30
|
lapisFilters: NamedLapisFilter[];
|
|
34
31
|
sequenceType: SequenceType;
|
|
35
32
|
views: View[];
|
|
36
33
|
pageSize: boolean | number;
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
export const MutationComparison: FunctionComponent<MutationComparisonProps> = (
|
|
36
|
+
export const MutationComparison: FunctionComponent<MutationComparisonProps> = (componentProps) => {
|
|
37
|
+
const { width, height } = componentProps;
|
|
40
38
|
const size = { height, width };
|
|
41
39
|
|
|
42
40
|
return (
|
|
43
41
|
<ErrorBoundary size={size}>
|
|
44
42
|
<ResizeContainer size={size}>
|
|
45
|
-
<MutationComparisonInner {...
|
|
43
|
+
<MutationComparisonInner {...componentProps} />
|
|
46
44
|
</ResizeContainer>
|
|
47
45
|
</ErrorBoundary>
|
|
48
46
|
);
|
|
49
47
|
};
|
|
50
48
|
|
|
51
|
-
export const MutationComparisonInner: FunctionComponent<
|
|
52
|
-
lapisFilters,
|
|
53
|
-
sequenceType,
|
|
54
|
-
views,
|
|
55
|
-
pageSize,
|
|
56
|
-
}) => {
|
|
49
|
+
export const MutationComparisonInner: FunctionComponent<MutationComparisonProps> = (componentProps) => {
|
|
50
|
+
const { lapisFilters, sequenceType } = componentProps;
|
|
57
51
|
const lapis = useContext(LapisUrlContext);
|
|
58
52
|
|
|
59
53
|
const { data, error, isLoading } = useQuery(async () => {
|
|
@@ -72,35 +66,21 @@ export const MutationComparisonInner: FunctionComponent<MutationComparisonInnerP
|
|
|
72
66
|
return <NoDataDisplay />;
|
|
73
67
|
}
|
|
74
68
|
|
|
75
|
-
return
|
|
76
|
-
<MutationComparisonTabs
|
|
77
|
-
data={data.mutationData}
|
|
78
|
-
sequenceType={sequenceType}
|
|
79
|
-
views={views}
|
|
80
|
-
pageSize={pageSize}
|
|
81
|
-
/>
|
|
82
|
-
);
|
|
69
|
+
return <MutationComparisonTabs data={data.mutationData} originalComponentProps={componentProps} />;
|
|
83
70
|
};
|
|
84
71
|
|
|
85
72
|
type MutationComparisonTabsProps = {
|
|
86
73
|
data: MutationData[];
|
|
87
|
-
|
|
88
|
-
sequenceType: SequenceType;
|
|
89
|
-
pageSize: boolean | number;
|
|
74
|
+
originalComponentProps: MutationComparisonProps;
|
|
90
75
|
};
|
|
91
76
|
|
|
92
|
-
const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = ({
|
|
93
|
-
data,
|
|
94
|
-
views,
|
|
95
|
-
sequenceType,
|
|
96
|
-
pageSize,
|
|
97
|
-
}) => {
|
|
77
|
+
const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = ({ data, originalComponentProps }) => {
|
|
98
78
|
const [proportionInterval, setProportionInterval] = useState({ min: 0.5, max: 1 });
|
|
99
79
|
const [displayedMutationTypes, setDisplayedMutationTypes] = useState<DisplayedMutationType[]>([
|
|
100
80
|
{ label: 'Substitutions', checked: true, type: 'substitution' },
|
|
101
81
|
{ label: 'Deletions', checked: true, type: 'deletion' },
|
|
102
82
|
]);
|
|
103
|
-
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(sequenceType);
|
|
83
|
+
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(originalComponentProps.sequenceType);
|
|
104
84
|
|
|
105
85
|
const filteredData = useMemo(
|
|
106
86
|
() => filterMutationData(data, displayedSegments, displayedMutationTypes),
|
|
@@ -116,7 +96,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
116
96
|
<MutationComparisonTable
|
|
117
97
|
data={{ content: filteredData }}
|
|
118
98
|
proportionInterval={proportionInterval}
|
|
119
|
-
pageSize={pageSize}
|
|
99
|
+
pageSize={originalComponentProps.pageSize}
|
|
120
100
|
/>
|
|
121
101
|
),
|
|
122
102
|
};
|
|
@@ -133,7 +113,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
133
113
|
}
|
|
134
114
|
};
|
|
135
115
|
|
|
136
|
-
const tabs = views.map((view) => getTab(view));
|
|
116
|
+
const tabs = originalComponentProps.views.map((view) => getTab(view));
|
|
137
117
|
|
|
138
118
|
return (
|
|
139
119
|
<Tabs
|
|
@@ -147,6 +127,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
147
127
|
filteredData={filteredData}
|
|
148
128
|
proportionInterval={proportionInterval}
|
|
149
129
|
setProportionInterval={setProportionInterval}
|
|
130
|
+
originalComponentProps={originalComponentProps}
|
|
150
131
|
/>
|
|
151
132
|
}
|
|
152
133
|
/>
|
|
@@ -161,6 +142,7 @@ type ToolbarProps = {
|
|
|
161
142
|
filteredData: MutationData[];
|
|
162
143
|
proportionInterval: ProportionInterval;
|
|
163
144
|
setProportionInterval: Dispatch<StateUpdater<ProportionInterval>>;
|
|
145
|
+
originalComponentProps: MutationComparisonProps;
|
|
164
146
|
};
|
|
165
147
|
|
|
166
148
|
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
@@ -171,6 +153,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
171
153
|
filteredData,
|
|
172
154
|
proportionInterval,
|
|
173
155
|
setProportionInterval,
|
|
156
|
+
originalComponentProps,
|
|
174
157
|
}) => {
|
|
175
158
|
return (
|
|
176
159
|
<>
|
|
@@ -189,8 +172,23 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
189
172
|
getData={() => getMutationComparisonTableData({ content: filteredData }, proportionInterval)}
|
|
190
173
|
filename='mutation_comparison.csv'
|
|
191
174
|
/>
|
|
192
|
-
<
|
|
175
|
+
<MutationComparisonInfo originalComponentProps={originalComponentProps} />
|
|
193
176
|
<Fullscreen />
|
|
194
177
|
</>
|
|
195
178
|
);
|
|
196
179
|
};
|
|
180
|
+
|
|
181
|
+
type MutationComparisonInfoProps = {
|
|
182
|
+
originalComponentProps: MutationComparisonProps;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const MutationComparisonInfo: FunctionComponent<MutationComparisonInfoProps> = ({ originalComponentProps }) => {
|
|
186
|
+
const lapis = useContext(LapisUrlContext);
|
|
187
|
+
return (
|
|
188
|
+
<Info>
|
|
189
|
+
<InfoHeadline1>Info for mutation comparison</InfoHeadline1>
|
|
190
|
+
<InfoParagraph>TODO: https://github.com/GenSpectrum/dashboard-components/issues/465</InfoParagraph>
|
|
191
|
+
<InfoComponentCode componentName='mutation-comparison' params={originalComponentProps} lapisUrl={lapis} />
|
|
192
|
+
</Info>
|
|
193
|
+
);
|
|
194
|
+
};
|
|
@@ -18,7 +18,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
|
|
|
18
18
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
19
19
|
import { ErrorDisplay } from '../components/error-display';
|
|
20
20
|
import { Fullscreen } from '../components/fullscreen';
|
|
21
|
-
import Info, { InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
|
|
21
|
+
import Info, { InfoComponentCode, InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
|
|
22
22
|
import { LoadingDisplay } from '../components/loading-display';
|
|
23
23
|
import { type DisplayedMutationType, MutationTypeSelector } from '../components/mutation-type-selector';
|
|
24
24
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
@@ -31,37 +31,32 @@ import { useQuery } from '../useQuery';
|
|
|
31
31
|
|
|
32
32
|
export type View = 'table' | 'grid' | 'insertions';
|
|
33
33
|
|
|
34
|
-
export interface
|
|
34
|
+
export interface MutationsProps {
|
|
35
|
+
width: string;
|
|
36
|
+
height: string;
|
|
35
37
|
lapisFilter: LapisFilter;
|
|
36
38
|
sequenceType: SequenceType;
|
|
37
39
|
views: View[];
|
|
38
40
|
pageSize: boolean | number;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export
|
|
42
|
-
width
|
|
43
|
-
height: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const Mutations: FunctionComponent<MutationsProps> = ({ width, height, ...innerProps }) => {
|
|
43
|
+
export const Mutations: FunctionComponent<MutationsProps> = (componentProps) => {
|
|
44
|
+
const { width, height } = componentProps;
|
|
47
45
|
const size = { height, width };
|
|
48
46
|
|
|
49
47
|
return (
|
|
50
48
|
<ErrorBoundary size={size}>
|
|
51
49
|
<ResizeContainer size={size}>
|
|
52
|
-
<MutationsInner {...
|
|
50
|
+
<MutationsInner {...componentProps} />
|
|
53
51
|
</ResizeContainer>
|
|
54
52
|
</ErrorBoundary>
|
|
55
53
|
);
|
|
56
54
|
};
|
|
57
55
|
|
|
58
|
-
export const MutationsInner: FunctionComponent<
|
|
59
|
-
lapisFilter,
|
|
60
|
-
sequenceType,
|
|
61
|
-
views,
|
|
62
|
-
pageSize,
|
|
63
|
-
}) => {
|
|
56
|
+
export const MutationsInner: FunctionComponent<MutationsProps> = (componentProps) => {
|
|
64
57
|
const lapis = useContext(LapisUrlContext);
|
|
58
|
+
const { lapisFilter, sequenceType } = componentProps;
|
|
59
|
+
|
|
65
60
|
const { data, error, isLoading } = useQuery(async () => {
|
|
66
61
|
return queryMutationsData(lapisFilter, sequenceType, lapis);
|
|
67
62
|
}, [lapisFilter, sequenceType, lapis]);
|
|
@@ -78,20 +73,18 @@ export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({
|
|
|
78
73
|
return <NoDataDisplay />;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
|
-
return <MutationsTabs mutationsData={data}
|
|
76
|
+
return <MutationsTabs mutationsData={data} originalComponentProps={componentProps} />;
|
|
82
77
|
};
|
|
83
78
|
|
|
84
79
|
type MutationTabsProps = {
|
|
85
80
|
mutationsData: { insertions: InsertionEntry[]; substitutionsOrDeletions: SubstitutionOrDeletionEntry[] };
|
|
86
|
-
|
|
87
|
-
views: View[];
|
|
88
|
-
pageSize: boolean | number;
|
|
81
|
+
originalComponentProps: MutationsProps;
|
|
89
82
|
};
|
|
90
83
|
|
|
91
|
-
const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData,
|
|
84
|
+
const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, originalComponentProps }) => {
|
|
92
85
|
const [proportionInterval, setProportionInterval] = useState({ min: 0.05, max: 1 });
|
|
93
86
|
|
|
94
|
-
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(sequenceType);
|
|
87
|
+
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(originalComponentProps.sequenceType);
|
|
95
88
|
const [displayedMutationTypes, setDisplayedMutationTypes] = useState<DisplayedMutationType[]>([
|
|
96
89
|
{ label: 'Substitutions', checked: true, type: 'substitution' },
|
|
97
90
|
{ label: 'Deletions', checked: true, type: 'deletion' },
|
|
@@ -108,7 +101,7 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, se
|
|
|
108
101
|
<MutationsTable
|
|
109
102
|
data={filteredData.tableData}
|
|
110
103
|
proportionInterval={proportionInterval}
|
|
111
|
-
pageSize={pageSize}
|
|
104
|
+
pageSize={originalComponentProps.pageSize}
|
|
112
105
|
/>
|
|
113
106
|
),
|
|
114
107
|
};
|
|
@@ -118,21 +111,23 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, se
|
|
|
118
111
|
content: (
|
|
119
112
|
<MutationsGrid
|
|
120
113
|
data={filteredData.gridData}
|
|
121
|
-
sequenceType={sequenceType}
|
|
114
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
122
115
|
proportionInterval={proportionInterval}
|
|
123
|
-
pageSize={pageSize}
|
|
116
|
+
pageSize={originalComponentProps.pageSize}
|
|
124
117
|
/>
|
|
125
118
|
),
|
|
126
119
|
};
|
|
127
120
|
case 'insertions':
|
|
128
121
|
return {
|
|
129
122
|
title: 'Insertions',
|
|
130
|
-
content:
|
|
123
|
+
content: (
|
|
124
|
+
<InsertionsTable data={filteredData.insertions} pageSize={originalComponentProps.pageSize} />
|
|
125
|
+
),
|
|
131
126
|
};
|
|
132
127
|
}
|
|
133
128
|
};
|
|
134
129
|
|
|
135
|
-
const tabs = views.map((view) => getTab(view));
|
|
130
|
+
const tabs = originalComponentProps.views.map((view) => getTab(view));
|
|
136
131
|
|
|
137
132
|
const toolbar = (activeTab: string) => (
|
|
138
133
|
<Toolbar
|
|
@@ -144,6 +139,7 @@ const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, se
|
|
|
144
139
|
filteredData={filteredData}
|
|
145
140
|
proportionInterval={proportionInterval}
|
|
146
141
|
setProportionInterval={setProportionInterval}
|
|
142
|
+
originalComponentProps={originalComponentProps}
|
|
147
143
|
/>
|
|
148
144
|
);
|
|
149
145
|
|
|
@@ -159,6 +155,7 @@ type ToolbarProps = {
|
|
|
159
155
|
filteredData: { tableData: SubstitutionOrDeletionEntry[]; insertions: InsertionEntry[] };
|
|
160
156
|
proportionInterval: ProportionInterval;
|
|
161
157
|
setProportionInterval: Dispatch<StateUpdater<ProportionInterval>>;
|
|
158
|
+
originalComponentProps: MutationsProps;
|
|
162
159
|
};
|
|
163
160
|
|
|
164
161
|
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
@@ -170,6 +167,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
170
167
|
filteredData,
|
|
171
168
|
proportionInterval,
|
|
172
169
|
setProportionInterval,
|
|
170
|
+
originalComponentProps,
|
|
173
171
|
}) => {
|
|
174
172
|
return (
|
|
175
173
|
<>
|
|
@@ -208,38 +206,47 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
208
206
|
filename='insertions.csv'
|
|
209
207
|
/>
|
|
210
208
|
)}
|
|
211
|
-
<MutationsInfo />
|
|
209
|
+
<MutationsInfo originalComponentProps={originalComponentProps} />
|
|
212
210
|
<Fullscreen />
|
|
213
211
|
</>
|
|
214
212
|
);
|
|
215
213
|
};
|
|
216
214
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
<
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
215
|
+
type MutationsInfoProps = {
|
|
216
|
+
originalComponentProps: MutationsProps;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const MutationsInfo: FunctionComponent<MutationsInfoProps> = ({ originalComponentProps }) => {
|
|
220
|
+
const lapis = useContext(LapisUrlContext);
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<Info>
|
|
224
|
+
<InfoHeadline1>Mutations</InfoHeadline1>
|
|
225
|
+
<InfoParagraph>
|
|
226
|
+
This shows mutations of a variant. There are three types of mutations:{' '}
|
|
227
|
+
<InfoLink href='https://www.genome.gov/genetics-glossary/Substitution'>substitutions</InfoLink>,{' '}
|
|
228
|
+
<InfoLink href='https://www.genome.gov/genetics-glossary/Deletion'>deletions</InfoLink> and{' '}
|
|
229
|
+
<InfoLink href='https://www.genome.gov/genetics-glossary/Insertion'>insertions</InfoLink>.
|
|
230
|
+
</InfoParagraph>
|
|
231
|
+
<InfoHeadline2>Proportion calculation</InfoHeadline2>
|
|
232
|
+
<InfoParagraph>
|
|
233
|
+
The proportion of a mutation is calculated by dividing the number of sequences with the mutation by the
|
|
234
|
+
total number of sequences with a non-ambiguous symbol at the position.
|
|
235
|
+
</InfoParagraph>
|
|
236
|
+
<InfoParagraph>
|
|
237
|
+
<b>Example:</b> Assume we look at nucleotide mutations at position 5 where the reference has a T and
|
|
238
|
+
assume there are 10 sequences in total:
|
|
239
|
+
<ul className='list-disc list-inside ml-2'>
|
|
240
|
+
<li>3 sequences have a C,</li>
|
|
241
|
+
<li>2 sequences have a T,</li>
|
|
242
|
+
<li>1 sequence has a G,</li>
|
|
243
|
+
<li>3 sequences have an N,</li>
|
|
244
|
+
<li>1 sequence has a Y (which means T or C),</li>
|
|
245
|
+
</ul>
|
|
246
|
+
then the proportion of the T5C mutation is 50%. The 4 sequences that have an N or Y are excluded from
|
|
247
|
+
the calculation.
|
|
248
|
+
</InfoParagraph>
|
|
249
|
+
<InfoComponentCode componentName='mutations' params={originalComponentProps} lapisUrl={lapis} />
|
|
250
|
+
</Info>
|
|
251
|
+
);
|
|
252
|
+
};
|