@genspectrum/dashboard-components 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +16 -0
- package/dist/dashboard-components.js +122 -19
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +2 -2
- package/package.json +1 -1
- package/src/preact/components/scaling-selector.tsx +9 -3
- package/src/preact/mutations/mutations.tsx +1 -1
- package/src/preact/numberSequencesOverTime/number-sequences-over-time-bar-chart.tsx +9 -2
- package/src/preact/numberSequencesOverTime/number-sequences-over-time-line-chart.tsx +66 -0
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +68 -4
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +1 -1
- package/src/web-components/visualization/gs-number-sequences-over-time.stories.ts +11 -0
- package/src/preact/shared/charts/scales.ts +0 -16
|
@@ -876,14 +876,14 @@ declare global {
|
|
|
876
876
|
|
|
877
877
|
declare global {
|
|
878
878
|
interface HTMLElementTagNameMap {
|
|
879
|
-
'gs-
|
|
879
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
880
880
|
}
|
|
881
881
|
}
|
|
882
882
|
|
|
883
883
|
|
|
884
884
|
declare global {
|
|
885
885
|
interface HTMLElementTagNameMap {
|
|
886
|
-
'gs-
|
|
886
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
887
887
|
}
|
|
888
888
|
}
|
|
889
889
|
|
package/package.json
CHANGED
|
@@ -7,18 +7,24 @@ export type ScalingSelectorProps = {
|
|
|
7
7
|
yAxisScaleType: ScaleType;
|
|
8
8
|
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
9
9
|
className?: string;
|
|
10
|
+
enabledTypes?: ScaleType[];
|
|
10
11
|
};
|
|
11
12
|
|
|
13
|
+
const scaleTypeItem: { label: string; value: ScaleType }[] = [
|
|
14
|
+
{ label: 'Linear', value: 'linear' },
|
|
15
|
+
{ label: 'Logarithmic', value: 'logarithmic' },
|
|
16
|
+
{ label: 'Logit', value: 'logit' },
|
|
17
|
+
];
|
|
18
|
+
|
|
12
19
|
export const ScalingSelector: FunctionComponent<ScalingSelectorProps> = ({
|
|
13
20
|
yAxisScaleType,
|
|
14
21
|
setYAxisScaleType,
|
|
15
22
|
className,
|
|
23
|
+
enabledTypes,
|
|
16
24
|
}) => {
|
|
17
25
|
const items = [
|
|
18
26
|
{ label: 'y axis scaling type', value: 'none', disabled: true },
|
|
19
|
-
|
|
20
|
-
{ label: 'Logarithmic', value: 'logarithmic' },
|
|
21
|
-
{ label: 'Logit', value: 'logit' },
|
|
27
|
+
...scaleTypeItem.filter((item) => enabledTypes === undefined || enabledTypes.includes(item.value)),
|
|
22
28
|
];
|
|
23
29
|
|
|
24
30
|
return (
|
|
@@ -198,7 +198,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
198
198
|
<CsvDownloadButton
|
|
199
199
|
className='mx-1 btn btn-xs'
|
|
200
200
|
getData={() => getMutationsTableData(filteredData.tableData, proportionInterval)}
|
|
201
|
-
filename='
|
|
201
|
+
filename='substitutions_and_deletions.csv'
|
|
202
202
|
/>
|
|
203
203
|
</>
|
|
204
204
|
)}
|
|
@@ -5,14 +5,16 @@ import { getNumberOfSequencesOverTimeTableData } from './getNumberOfSequencesOve
|
|
|
5
5
|
import { type NumberOfSequencesDatasets } from '../../query/queryNumberOfSequencesOverTime';
|
|
6
6
|
import GsChart from '../components/chart';
|
|
7
7
|
import { singleGraphColorRGBAById } from '../shared/charts/colors';
|
|
8
|
+
import { getYAxisScale, type ScaleType } from '../shared/charts/getYAxisScale';
|
|
8
9
|
|
|
9
10
|
interface NumberSequencesOverBarChartProps {
|
|
10
11
|
data: NumberOfSequencesDatasets;
|
|
12
|
+
yAxisScaleType: ScaleType;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
Chart.register(...registerables);
|
|
14
16
|
|
|
15
|
-
export const NumberSequencesOverTimeBarChart = ({ data }: NumberSequencesOverBarChartProps) => {
|
|
17
|
+
export const NumberSequencesOverTimeBarChart = ({ data, yAxisScaleType }: NumberSequencesOverBarChartProps) => {
|
|
16
18
|
const config: ChartConfiguration = useMemo(
|
|
17
19
|
() => ({
|
|
18
20
|
type: 'bar',
|
|
@@ -22,6 +24,11 @@ export const NumberSequencesOverTimeBarChart = ({ data }: NumberSequencesOverBar
|
|
|
22
24
|
options: {
|
|
23
25
|
maintainAspectRatio: false,
|
|
24
26
|
animation: false,
|
|
27
|
+
scales: {
|
|
28
|
+
y: {
|
|
29
|
+
type: getYAxisScale(yAxisScaleType).type,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
25
32
|
plugins: {
|
|
26
33
|
legend: {
|
|
27
34
|
display: false,
|
|
@@ -33,7 +40,7 @@ export const NumberSequencesOverTimeBarChart = ({ data }: NumberSequencesOverBar
|
|
|
33
40
|
},
|
|
34
41
|
},
|
|
35
42
|
}),
|
|
36
|
-
[data],
|
|
43
|
+
[data, yAxisScaleType],
|
|
37
44
|
);
|
|
38
45
|
|
|
39
46
|
return <GsChart configuration={config} />;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Chart, type ChartConfiguration, type ChartDataset, registerables } from 'chart.js';
|
|
2
|
+
import { useMemo } from 'preact/hooks';
|
|
3
|
+
|
|
4
|
+
import { getNumberOfSequencesOverTimeTableData } from './getNumberOfSequencesOverTimeTableData';
|
|
5
|
+
import { type NumberOfSequencesDatasets } from '../../query/queryNumberOfSequencesOverTime';
|
|
6
|
+
import GsChart from '../components/chart';
|
|
7
|
+
import { singleGraphColorRGBAById } from '../shared/charts/colors';
|
|
8
|
+
import { getYAxisScale, type ScaleType } from '../shared/charts/getYAxisScale';
|
|
9
|
+
|
|
10
|
+
interface NumberSequencesOverBarChartProps {
|
|
11
|
+
data: NumberOfSequencesDatasets;
|
|
12
|
+
yAxisScaleType: ScaleType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Chart.register(...registerables);
|
|
16
|
+
|
|
17
|
+
export const NumberSequencesOverTimeLineChart = ({ data, yAxisScaleType }: NumberSequencesOverBarChartProps) => {
|
|
18
|
+
const config: ChartConfiguration = useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
type: 'line',
|
|
21
|
+
data: {
|
|
22
|
+
datasets: getDatasets(data),
|
|
23
|
+
},
|
|
24
|
+
options: {
|
|
25
|
+
maintainAspectRatio: false,
|
|
26
|
+
animation: false,
|
|
27
|
+
scales: {
|
|
28
|
+
y: {
|
|
29
|
+
type: getYAxisScale(yAxisScaleType).type,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
plugins: {
|
|
33
|
+
legend: {
|
|
34
|
+
display: false,
|
|
35
|
+
},
|
|
36
|
+
tooltip: {
|
|
37
|
+
mode: 'index',
|
|
38
|
+
intersect: false,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
[data, yAxisScaleType],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return <GsChart configuration={config} />;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getDatasets = (data: NumberOfSequencesDatasets) => {
|
|
50
|
+
const tableData = getNumberOfSequencesOverTimeTableData(data, 'date');
|
|
51
|
+
|
|
52
|
+
return data.map(
|
|
53
|
+
({ displayName }, index) =>
|
|
54
|
+
({
|
|
55
|
+
borderWidth: 1,
|
|
56
|
+
pointRadius: 0,
|
|
57
|
+
label: displayName,
|
|
58
|
+
backgroundColor: singleGraphColorRGBAById(index, 0.3),
|
|
59
|
+
borderColor: singleGraphColorRGBAById(index),
|
|
60
|
+
data: tableData.map((row) => ({
|
|
61
|
+
x: row.date,
|
|
62
|
+
y: row[displayName],
|
|
63
|
+
})),
|
|
64
|
+
}) as ChartDataset<'line', { x: string; y: number }[]>,
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { useContext } from 'preact/hooks';
|
|
1
|
+
import { useContext, useState } from 'preact/hooks';
|
|
2
2
|
|
|
3
|
+
import { getNumberOfSequencesOverTimeTableData } from './getNumberOfSequencesOverTimeTableData';
|
|
3
4
|
import { NumberSequencesOverTimeBarChart } from './number-sequences-over-time-bar-chart';
|
|
5
|
+
import { NumberSequencesOverTimeLineChart } from './number-sequences-over-time-line-chart';
|
|
4
6
|
import { NumberSequencesOverTimeTable } from './number-sequences-over-time-table';
|
|
5
7
|
import {
|
|
6
8
|
type NumberOfSequencesDatasets,
|
|
@@ -8,13 +10,17 @@ import {
|
|
|
8
10
|
} from '../../query/queryNumberOfSequencesOverTime';
|
|
9
11
|
import type { NamedLapisFilter, TemporalGranularity } from '../../types';
|
|
10
12
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
13
|
+
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
11
14
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
12
15
|
import { ErrorDisplay } from '../components/error-display';
|
|
13
16
|
import Headline from '../components/headline';
|
|
17
|
+
import Info, { InfoHeadline1, InfoParagraph } from '../components/info';
|
|
14
18
|
import { LoadingDisplay } from '../components/loading-display';
|
|
15
19
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
16
20
|
import { ResizeContainer } from '../components/resize-container';
|
|
21
|
+
import { ScalingSelector } from '../components/scaling-selector';
|
|
17
22
|
import Tabs from '../components/tabs';
|
|
23
|
+
import type { ScaleType } from '../shared/charts/getYAxisScale';
|
|
18
24
|
import { useQuery } from '../useQuery';
|
|
19
25
|
|
|
20
26
|
type NumberSequencesOverTimeView = 'bar' | 'line' | 'table';
|
|
@@ -85,12 +91,20 @@ interface NumberSequencesOverTimeTabsProps {
|
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }: NumberSequencesOverTimeTabsProps) => {
|
|
94
|
+
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
95
|
+
|
|
88
96
|
const getTab = (view: NumberSequencesOverTimeView) => {
|
|
89
97
|
switch (view) {
|
|
90
98
|
case 'bar':
|
|
91
|
-
return {
|
|
99
|
+
return {
|
|
100
|
+
title: 'Bar',
|
|
101
|
+
content: <NumberSequencesOverTimeBarChart data={data} yAxisScaleType={yAxisScaleType} />,
|
|
102
|
+
};
|
|
92
103
|
case 'line':
|
|
93
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
title: 'Line',
|
|
106
|
+
content: <NumberSequencesOverTimeLineChart data={data} yAxisScaleType={yAxisScaleType} />,
|
|
107
|
+
};
|
|
94
108
|
case 'table':
|
|
95
109
|
return {
|
|
96
110
|
title: 'Table',
|
|
@@ -101,5 +115,55 @@ const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }: Num
|
|
|
101
115
|
}
|
|
102
116
|
};
|
|
103
117
|
|
|
104
|
-
return
|
|
118
|
+
return (
|
|
119
|
+
<Tabs
|
|
120
|
+
tabs={views.map((view) => getTab(view))}
|
|
121
|
+
toolbar={(activeTab) => (
|
|
122
|
+
<Toolbar
|
|
123
|
+
activeTab={activeTab}
|
|
124
|
+
data={data}
|
|
125
|
+
granularity={granularity}
|
|
126
|
+
yAxisScaleType={yAxisScaleType}
|
|
127
|
+
setYAxisScaleType={setYAxisScaleType}
|
|
128
|
+
/>
|
|
129
|
+
)}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
interface ToolbarProps {
|
|
135
|
+
activeTab: string;
|
|
136
|
+
data: NumberOfSequencesDatasets;
|
|
137
|
+
granularity: TemporalGranularity;
|
|
138
|
+
yAxisScaleType: ScaleType;
|
|
139
|
+
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const Toolbar = ({ activeTab, data, granularity, yAxisScaleType, setYAxisScaleType }: ToolbarProps) => {
|
|
143
|
+
return (
|
|
144
|
+
<>
|
|
145
|
+
{activeTab !== 'Table' && (
|
|
146
|
+
<ScalingSelector
|
|
147
|
+
yAxisScaleType={yAxisScaleType}
|
|
148
|
+
setYAxisScaleType={setYAxisScaleType}
|
|
149
|
+
enabledTypes={['linear', 'logarithmic']}
|
|
150
|
+
/>
|
|
151
|
+
)}
|
|
152
|
+
<CsvDownloadButton
|
|
153
|
+
className='mx-1 btn btn-xs'
|
|
154
|
+
getData={() => getNumberOfSequencesOverTimeTableData(data, granularity)}
|
|
155
|
+
filename='number_of_sequences_over_time.csv'
|
|
156
|
+
/>
|
|
157
|
+
<NumberSequencesOverTimeInfo />
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
105
160
|
};
|
|
161
|
+
|
|
162
|
+
const NumberSequencesOverTimeInfo = () => (
|
|
163
|
+
<Info height='100px'>
|
|
164
|
+
<InfoHeadline1>Number of sequences over time</InfoHeadline1>
|
|
165
|
+
<InfoParagraph>
|
|
166
|
+
<a href='https://github.com/GenSpectrum/dashboard-components/issues/315'>TODO</a>
|
|
167
|
+
</InfoParagraph>
|
|
168
|
+
</Info>
|
|
169
|
+
);
|
|
@@ -235,7 +235,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
235
235
|
<CsvDownloadButton
|
|
236
236
|
className='mx-1 btn btn-xs'
|
|
237
237
|
getData={() => getPrevalenceOverTimeTableData(data, granularity)}
|
|
238
|
-
filename='
|
|
238
|
+
filename='prevalence_over_time.csv'
|
|
239
239
|
/>
|
|
240
240
|
|
|
241
241
|
<PrevalenceOverTimeInfo />
|
|
@@ -116,6 +116,17 @@ export const OneDatasetBarChart: StoryObj<NumberSequencesOverTimeProps> = {
|
|
|
116
116
|
},
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
+
export const OneDatasetLineChart: StoryObj<NumberSequencesOverTimeProps> = {
|
|
120
|
+
...Template,
|
|
121
|
+
play: async ({ canvasElement }) => {
|
|
122
|
+
const canvas = await withinShadowRoot(canvasElement, 'gs-number-sequences-over-time');
|
|
123
|
+
|
|
124
|
+
await waitFor(() => expect(canvas.getByRole('button', { name: 'Line' })).toBeVisible());
|
|
125
|
+
|
|
126
|
+
await fireEvent.click(canvas.getByRole('button', { name: 'Line' }));
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
119
130
|
export const OneDatasetTable: StoryObj<NumberSequencesOverTimeProps> = {
|
|
120
131
|
...Template,
|
|
121
132
|
play: async ({ canvasElement }) => {
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export type ScaleType = 'linear' | 'logarithmic' | 'logit';
|
|
2
|
-
|
|
3
|
-
export function getYAxisScale(scaleType: ScaleType) {
|
|
4
|
-
switch (scaleType) {
|
|
5
|
-
case 'linear': {
|
|
6
|
-
return { beginAtZero: true, type: 'linear' as const };
|
|
7
|
-
}
|
|
8
|
-
case 'logarithmic': {
|
|
9
|
-
return { type: 'logarithmic' as const };
|
|
10
|
-
}
|
|
11
|
-
case 'logit':
|
|
12
|
-
return { type: 'logit' as const };
|
|
13
|
-
default:
|
|
14
|
-
return { beginAtZero: true, type: 'linear' as const };
|
|
15
|
-
}
|
|
16
|
-
}
|