@genspectrum/dashboard-components 0.7.0 → 0.7.2

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.
@@ -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 MutationsInnerProps {
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 interface MutationsProps extends MutationsInnerProps {
42
- width: string;
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 {...innerProps} />
50
+ <MutationsInner {...componentProps} />
53
51
  </ResizeContainer>
54
52
  </ErrorBoundary>
55
53
  );
56
54
  };
57
55
 
58
- export const MutationsInner: FunctionComponent<MutationsInnerProps> = ({
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} sequenceType={sequenceType} views={views} pageSize={pageSize} />;
76
+ return <MutationsTabs mutationsData={data} originalComponentProps={componentProps} />;
82
77
  };
83
78
 
84
79
  type MutationTabsProps = {
85
80
  mutationsData: { insertions: InsertionEntry[]; substitutionsOrDeletions: SubstitutionOrDeletionEntry[] };
86
- sequenceType: SequenceType;
87
- views: View[];
88
- pageSize: boolean | number;
81
+ originalComponentProps: MutationsProps;
89
82
  };
90
83
 
91
- const MutationsTabs: FunctionComponent<MutationTabsProps> = ({ mutationsData, sequenceType, views, pageSize }) => {
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: <InsertionsTable data={filteredData.insertions} pageSize={pageSize} />,
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
- const MutationsInfo = () => (
218
- <Info>
219
- <InfoHeadline1>Mutations</InfoHeadline1>
220
- <InfoParagraph>
221
- This shows mutations of a variant. There are three types of mutations:{' '}
222
- <InfoLink href='https://www.genome.gov/genetics-glossary/Substitution'>substitutions</InfoLink>,{' '}
223
- <InfoLink href='https://www.genome.gov/genetics-glossary/Deletion'>deletions</InfoLink> and{' '}
224
- <InfoLink href='https://www.genome.gov/genetics-glossary/Insertion'>insertions</InfoLink>.
225
- </InfoParagraph>
226
- <InfoHeadline2>Proportion calculation</InfoHeadline2>
227
- <InfoParagraph>
228
- The proportion of a mutation is calculated by dividing the number of sequences with the mutation by the
229
- total number of sequences with a non-ambiguous symbol at the position.
230
- </InfoParagraph>
231
- <InfoParagraph>
232
- <b>Example:</b> Assume we look at nucleotide mutations at position 5 where the reference has a T and assume
233
- there are 10 sequences in total:
234
- <ul className='list-disc list-inside ml-2'>
235
- <li>3 sequences have a C,</li>
236
- <li>2 sequences have a T,</li>
237
- <li>1 sequence has a G,</li>
238
- <li>3 sequences have an N,</li>
239
- <li>1 sequence has a Y (which means T or C),</li>
240
- </ul>
241
- then the proportion of the T5C mutation is 50%. The 4 sequences that have an N or Y are excluded from the
242
- calculation.
243
- </InfoParagraph>
244
- </Info>
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
+ };
@@ -23,7 +23,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
23
23
  import { ErrorBoundary } from '../components/error-boundary';
24
24
  import { ErrorDisplay } from '../components/error-display';
25
25
  import { Fullscreen } from '../components/fullscreen';
26
- import Info from '../components/info';
26
+ import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
27
27
  import { LoadingDisplay } from '../components/loading-display';
28
28
  import { type DisplayedMutationType, MutationTypeSelector } from '../components/mutation-type-selector';
29
29
  import { NoDataDisplay } from '../components/no-data-display';
@@ -36,7 +36,9 @@ import { useWebWorker } from '../webWorkers/useWebWorker';
36
36
 
37
37
  export type View = 'grid';
38
38
 
39
- export interface MutationsOverTimeInnerProps {
39
+ export interface MutationsOverTimeProps {
40
+ width: string;
41
+ height: string;
40
42
  lapisFilter: LapisFilter;
41
43
  sequenceType: SequenceType;
42
44
  views: View[];
@@ -44,31 +46,22 @@ export interface MutationsOverTimeInnerProps {
44
46
  lapisDateField: string;
45
47
  }
46
48
 
47
- export interface MutationsOverTimeProps extends MutationsOverTimeInnerProps {
48
- width: string;
49
- height: string;
50
- }
51
-
52
- export const MutationsOverTime: FunctionComponent<MutationsOverTimeProps> = ({ width, height, ...innerProps }) => {
49
+ export const MutationsOverTime: FunctionComponent<MutationsOverTimeProps> = (componentProps) => {
50
+ const { width, height } = componentProps;
53
51
  const size = { height, width };
54
52
 
55
53
  return (
56
54
  <ErrorBoundary size={size}>
57
55
  <ResizeContainer size={size}>
58
- <MutationsOverTimeInner {...innerProps} />
56
+ <MutationsOverTimeInner {...componentProps} />
59
57
  </ResizeContainer>
60
58
  </ErrorBoundary>
61
59
  );
62
60
  };
63
61
 
64
- export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeInnerProps> = ({
65
- lapisFilter,
66
- sequenceType,
67
- views,
68
- granularity,
69
- lapisDateField,
70
- }) => {
62
+ export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = (componentProps) => {
71
63
  const lapis = useContext(LapisUrlContext);
64
+ const { lapisFilter, sequenceType, granularity, lapisDateField } = componentProps;
72
65
 
73
66
  const { data, error, isLoading } = useWebWorker<MutationOverTimeQuery, MutationOverTimeWorkerResponse>(
74
67
  {
@@ -99,29 +92,26 @@ export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeInnerPro
99
92
  <MutationsOverTimeTabs
100
93
  overallMutationData={overallMutationData}
101
94
  mutationOverTimeData={mutationOverTimeData}
102
- sequenceType={sequenceType}
103
- views={views}
95
+ originalComponentProps={componentProps}
104
96
  />
105
97
  );
106
98
  };
107
99
 
108
100
  type MutationOverTimeTabsProps = {
109
101
  mutationOverTimeData: BaseMutationOverTimeDataMap;
110
- sequenceType: SequenceType;
111
- views: View[];
102
+ originalComponentProps: MutationsOverTimeProps;
112
103
  overallMutationData: SubstitutionOrDeletionEntry<Substitution, Deletion>[];
113
104
  };
114
105
 
115
106
  const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
116
107
  mutationOverTimeData,
117
- sequenceType,
118
- views,
108
+ originalComponentProps,
119
109
  overallMutationData,
120
110
  }) => {
121
111
  const [proportionInterval, setProportionInterval] = useState({ min: 0.05, max: 0.9 });
122
112
  const [colorScale, setColorScale] = useState<ColorScale>({ min: 0, max: 1, color: 'indigo' });
123
113
 
124
- const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(sequenceType);
114
+ const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(originalComponentProps.sequenceType);
125
115
  const [displayedMutationTypes, setDisplayedMutationTypes] = useState<DisplayedMutationType[]>([
126
116
  { label: 'Substitutions', checked: true, type: 'substitution' },
127
117
  { label: 'Deletions', checked: true, type: 'deletion' },
@@ -153,7 +143,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
153
143
  }
154
144
  };
155
145
 
156
- const tabs = views.map((view) => getTab(view));
146
+ const tabs = originalComponentProps.views.map((view) => getTab(view));
157
147
 
158
148
  const toolbar = (activeTab: string) => (
159
149
  <Toolbar
@@ -167,6 +157,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
167
157
  filteredData={filteredData}
168
158
  colorScale={colorScale}
169
159
  setColorScale={setColorScale}
160
+ originalComponentProps={originalComponentProps}
170
161
  />
171
162
  );
172
163
 
@@ -184,6 +175,7 @@ type ToolbarProps = {
184
175
  filteredData: MutationOverTimeDataMap;
185
176
  colorScale: ColorScale;
186
177
  setColorScale: Dispatch<StateUpdater<ColorScale>>;
178
+ originalComponentProps: MutationsOverTimeProps;
187
179
  };
188
180
 
189
181
  const Toolbar: FunctionComponent<ToolbarProps> = ({
@@ -197,6 +189,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
197
189
  filteredData,
198
190
  colorScale,
199
191
  setColorScale,
192
+ originalComponentProps,
200
193
  }) => {
201
194
  return (
202
195
  <>
@@ -219,12 +212,27 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
219
212
  getData={() => getDownloadData(filteredData)}
220
213
  filename='mutations_over_time.csv'
221
214
  />
222
- <Info>Info for mutations over time</Info>
215
+ <MutationsOverTimeInfo originalComponentProps={originalComponentProps} />
223
216
  <Fullscreen />
224
217
  </>
225
218
  );
226
219
  };
227
220
 
221
+ type MutationsOverTimeInfoProps = {
222
+ originalComponentProps: MutationsOverTimeProps;
223
+ };
224
+
225
+ const MutationsOverTimeInfo: FunctionComponent<MutationsOverTimeInfoProps> = ({ originalComponentProps }) => {
226
+ const lapis = useContext(LapisUrlContext);
227
+ return (
228
+ <Info>
229
+ <InfoHeadline1>Info for mutations over time</InfoHeadline1>
230
+ <InfoParagraph>TODO: https://github.com/GenSpectrum/dashboard-components/issues/441</InfoParagraph>
231
+ <InfoComponentCode componentName='mutations-over-time' params={originalComponentProps} lapisUrl={lapis} />
232
+ </Info>
233
+ );
234
+ };
235
+
228
236
  function getDownloadData(filteredData: MutationOverTimeDataMap) {
229
237
  const dates = filteredData.getSecondAxisKeys().map((date) => toTemporalClass(date));
230
238
 
@@ -15,7 +15,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
15
15
  import { ErrorBoundary } from '../components/error-boundary';
16
16
  import { ErrorDisplay } from '../components/error-display';
17
17
  import { Fullscreen } from '../components/fullscreen';
18
- import Info, { InfoHeadline1, InfoParagraph } from '../components/info';
18
+ import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
19
19
  import { LoadingDisplay } from '../components/loading-display';
20
20
  import { NoDataDisplay } from '../components/no-data-display';
21
21
  import { ResizeContainer } from '../components/resize-container';
@@ -26,12 +26,9 @@ import { useQuery } from '../useQuery';
26
26
 
27
27
  type NumberSequencesOverTimeView = 'bar' | 'line' | 'table';
28
28
 
29
- export interface NumberSequencesOverTimeProps extends NumberSequencesOverTimeInnerProps {
29
+ export interface NumberSequencesOverTimeProps {
30
30
  width: string;
31
31
  height: string;
32
- }
33
-
34
- interface NumberSequencesOverTimeInnerProps {
35
32
  lapisFilter: NamedLapisFilter | NamedLapisFilter[];
36
33
  lapisDateField: string;
37
34
  views: NumberSequencesOverTimeView[];
@@ -40,26 +37,21 @@ interface NumberSequencesOverTimeInnerProps {
40
37
  pageSize: boolean | number;
41
38
  }
42
39
 
43
- export const NumberSequencesOverTime = ({ width, height, ...innerProps }: NumberSequencesOverTimeProps) => {
40
+ export const NumberSequencesOverTime = (componentProps: NumberSequencesOverTimeProps) => {
41
+ const { width, height } = componentProps;
44
42
  const size = { height, width };
45
43
 
46
44
  return (
47
45
  <ErrorBoundary size={size}>
48
46
  <ResizeContainer size={size}>
49
- <NumberSequencesOverTimeInner {...innerProps} />
47
+ <NumberSequencesOverTimeInner {...componentProps} />
50
48
  </ResizeContainer>
51
49
  </ErrorBoundary>
52
50
  );
53
51
  };
54
52
 
55
- const NumberSequencesOverTimeInner = ({
56
- lapisFilter,
57
- granularity,
58
- smoothingWindow,
59
- lapisDateField,
60
- views,
61
- pageSize,
62
- }: NumberSequencesOverTimeInnerProps) => {
53
+ const NumberSequencesOverTimeInner = (componentProps: NumberSequencesOverTimeProps) => {
54
+ const { lapisFilter, lapisDateField, granularity, smoothingWindow } = componentProps;
63
55
  const lapis = useContext(LapisUrlContext);
64
56
 
65
57
  const { data, error, isLoading } = useQuery(
@@ -79,32 +71,15 @@ const NumberSequencesOverTimeInner = ({
79
71
  return <NoDataDisplay />;
80
72
  }
81
73
 
82
- return (
83
- <NumberSequencesOverTimeTabs
84
- views={views}
85
- data={data}
86
- granularity={granularity}
87
- smoothingWindow={smoothingWindow}
88
- pageSize={pageSize}
89
- />
90
- );
74
+ return <NumberSequencesOverTimeTabs data={data} originalComponentProps={componentProps} />;
91
75
  };
92
76
 
93
77
  interface NumberSequencesOverTimeTabsProps {
94
- views: NumberSequencesOverTimeView[];
95
78
  data: NumberOfSequencesDatasets;
96
- granularity: TemporalGranularity;
97
- smoothingWindow: number;
98
- pageSize: boolean | number;
79
+ originalComponentProps: NumberSequencesOverTimeProps;
99
80
  }
100
81
 
101
- const NumberSequencesOverTimeTabs = ({
102
- views,
103
- data,
104
- granularity,
105
- smoothingWindow,
106
- pageSize,
107
- }: NumberSequencesOverTimeTabsProps) => {
82
+ const NumberSequencesOverTimeTabs = ({ data, originalComponentProps }: NumberSequencesOverTimeTabsProps) => {
108
83
  const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
109
84
 
110
85
  const getTab = (view: NumberSequencesOverTimeView) => {
@@ -122,7 +97,13 @@ const NumberSequencesOverTimeTabs = ({
122
97
  case 'table':
123
98
  return {
124
99
  title: 'Table',
125
- content: <NumberSequencesOverTimeTable data={data} granularity={granularity} pageSize={pageSize} />,
100
+ content: (
101
+ <NumberSequencesOverTimeTable
102
+ data={data}
103
+ granularity={originalComponentProps.granularity}
104
+ pageSize={originalComponentProps.pageSize}
105
+ />
106
+ ),
126
107
  };
127
108
  default:
128
109
  throw new Error(`Unknown view: ${view}`);
@@ -131,15 +112,14 @@ const NumberSequencesOverTimeTabs = ({
131
112
 
132
113
  return (
133
114
  <Tabs
134
- tabs={views.map((view) => getTab(view))}
115
+ tabs={originalComponentProps.views.map((view) => getTab(view))}
135
116
  toolbar={(activeTab) => (
136
117
  <Toolbar
137
118
  activeTab={activeTab}
138
119
  data={data}
139
- granularity={granularity}
140
- smoothingWindow={smoothingWindow}
141
120
  yAxisScaleType={yAxisScaleType}
142
121
  setYAxisScaleType={setYAxisScaleType}
122
+ originalComponentProps={originalComponentProps}
143
123
  />
144
124
  )}
145
125
  />
@@ -149,20 +129,12 @@ const NumberSequencesOverTimeTabs = ({
149
129
  interface ToolbarProps {
150
130
  activeTab: string;
151
131
  data: NumberOfSequencesDatasets;
152
- granularity: TemporalGranularity;
153
132
  yAxisScaleType: ScaleType;
154
133
  setYAxisScaleType: (scaleType: ScaleType) => void;
155
- smoothingWindow: number;
134
+ originalComponentProps: NumberSequencesOverTimeProps;
156
135
  }
157
136
 
158
- const Toolbar = ({
159
- activeTab,
160
- data,
161
- granularity,
162
- yAxisScaleType,
163
- setYAxisScaleType,
164
- smoothingWindow,
165
- }: ToolbarProps) => {
137
+ const Toolbar = ({ activeTab, data, yAxisScaleType, setYAxisScaleType, originalComponentProps }: ToolbarProps) => {
166
138
  return (
167
139
  <>
168
140
  {activeTab !== 'Table' && (
@@ -174,29 +146,39 @@ const Toolbar = ({
174
146
  )}
175
147
  <CsvDownloadButton
176
148
  className='mx-1 btn btn-xs'
177
- getData={() => getNumberOfSequencesOverTimeTableData(data, granularity)}
149
+ getData={() => getNumberOfSequencesOverTimeTableData(data, originalComponentProps.granularity)}
178
150
  filename='number_of_sequences_over_time.csv'
179
151
  />
180
- <NumberSequencesOverTimeInfo granularity={granularity} smoothingWindow={smoothingWindow} />
152
+ <NumberSequencesOverTimeInfo originalComponentProps={originalComponentProps} />
181
153
  <Fullscreen />
182
154
  </>
183
155
  );
184
156
  };
185
157
 
186
158
  type NumberSequencesOverTimeInfoProps = {
187
- granularity: TemporalGranularity;
188
- smoothingWindow: number;
159
+ originalComponentProps: NumberSequencesOverTimeProps;
189
160
  };
190
161
 
191
162
  const NumberSequencesOverTimeInfo: FunctionComponent<NumberSequencesOverTimeInfoProps> = ({
192
- granularity,
193
- smoothingWindow,
194
- }) => (
195
- <Info>
196
- <InfoHeadline1>Number of sequences over time</InfoHeadline1>
197
- <InfoParagraph>
198
- This presents the number of available sequences of a variant per <b>{granularity}</b>
199
- {smoothingWindow > 0 && `, smoothed using a ${smoothingWindow}-${granularity} sliding window`}.
200
- </InfoParagraph>
201
- </Info>
202
- );
163
+ originalComponentProps,
164
+ }) => {
165
+ const lapis = useContext(LapisUrlContext);
166
+
167
+ return (
168
+ <Info>
169
+ <InfoHeadline1>Number of sequences over time</InfoHeadline1>
170
+ <InfoParagraph>
171
+ This presents the number of available sequences of a variant per{' '}
172
+ <b>{originalComponentProps.granularity}</b>
173
+ {originalComponentProps.smoothingWindow > 0 &&
174
+ `, smoothed using a ${originalComponentProps.smoothingWindow}-${originalComponentProps.granularity} sliding window`}
175
+ .
176
+ </InfoParagraph>
177
+ <InfoComponentCode
178
+ componentName='number-sequences-over-time'
179
+ params={originalComponentProps}
180
+ lapisUrl={lapis}
181
+ />
182
+ </Info>
183
+ );
184
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "errors": [],
3
+ "info": {
4
+ "apiVersion": 1,
5
+ "dataVersion": 1709685650,
6
+ "deprecationDate": null,
7
+ "deprecationInfo": null,
8
+ "acknowledgement": null
9
+ },
10
+ "data": []
11
+ }
@@ -9,6 +9,7 @@ import {
9
9
  } from '../../query/queryPrevalenceOverTime';
10
10
  import { sortNullToBeginningThenByDate } from '../../utils/sort';
11
11
  import GsChart from '../components/chart';
12
+ import { NoDataDisplay } from '../components/no-data-display';
12
13
  import { LogitScale } from '../shared/charts/LogitScale';
13
14
  import { singleGraphColorRGBAById } from '../shared/charts/colors';
14
15
  import { type ConfidenceIntervalMethod, wilson95PercentConfidenceInterval } from '../shared/charts/confideceInterval';
@@ -30,12 +31,18 @@ const PrevalenceOverTimeBarChart = ({
30
31
  confidenceIntervalMethod,
31
32
  yAxisMaxConfig,
32
33
  }: PrevalenceOverTimeBarChartProps) => {
33
- const nullFirstData = data.map((variantData) => {
34
- return {
35
- content: variantData.content.sort(sortNullToBeginningThenByDate),
36
- displayName: variantData.displayName,
37
- };
38
- });
34
+ const nullFirstData = data
35
+ .filter((prevalenceOverTimeData) => prevalenceOverTimeData.content.length > 0)
36
+ .map((variantData) => {
37
+ return {
38
+ content: variantData.content.sort(sortNullToBeginningThenByDate),
39
+ displayName: variantData.displayName,
40
+ };
41
+ });
42
+
43
+ if (nullFirstData.length === 0) {
44
+ return <NoDataDisplay />;
45
+ }
39
46
 
40
47
  const datasets = nullFirstData.map((graphData, index) => getDataset(graphData, index, confidenceIntervalMethod));
41
48
 
@@ -5,6 +5,7 @@ import { type PrevalenceOverTimeData } from '../../query/queryPrevalenceOverTime
5
5
  import { addUnit, minusTemporal } from '../../utils/temporalClass';
6
6
  import { getMinMaxNumber } from '../../utils/utils';
7
7
  import GsChart from '../components/chart';
8
+ import { NoDataDisplay } from '../components/no-data-display';
8
9
  import { LogitScale } from '../shared/charts/LogitScale';
9
10
  import { singleGraphColorRGBAById } from '../shared/charts/colors';
10
11
  import { getYAxisMax, type YAxisMaxConfig } from '../shared/charts/getYAxisMax';
@@ -23,12 +24,18 @@ const PrevalenceOverTimeBubbleChart = ({
23
24
  yAxisScaleType,
24
25
  yAxisMaxConfig,
25
26
  }: PrevalenceOverTimeBubbleChartProps) => {
26
- const nonNullDateRangeData = data.map((variantData) => {
27
- return {
28
- content: variantData.content.filter((dataPoint) => dataPoint.dateRange !== null),
29
- displayName: variantData.displayName,
30
- };
31
- });
27
+ const nonNullDateRangeData = data
28
+ .filter((prevalenceOverTimeData) => prevalenceOverTimeData.content.length > 0)
29
+ .map((variantData) => {
30
+ return {
31
+ content: variantData.content.filter((dataPoint) => dataPoint.dateRange !== null),
32
+ displayName: variantData.displayName,
33
+ };
34
+ });
35
+
36
+ if (nonNullDateRangeData.length === 0) {
37
+ return <NoDataDisplay />;
38
+ }
32
39
 
33
40
  const firstDate = nonNullDateRangeData[0].content[0].dateRange!;
34
41
  const total = nonNullDateRangeData.map((graphData) => graphData.content.map((dataPoint) => dataPoint.total)).flat();