@genspectrum/dashboard-components 0.10.2 → 0.10.4

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.
Files changed (76) hide show
  1. package/README.md +19 -19
  2. package/custom-elements.json +377 -33
  3. package/dist/assets/mutationOverTimeWorker-BjjkMGzd.js.map +1 -0
  4. package/dist/components.d.ts +217 -59
  5. package/dist/components.js +1365 -177
  6. package/dist/components.js.map +1 -1
  7. package/dist/{dateRangeOption-du8H7LWu.js → dateRangeOption-Doo6WHKu.js} +17 -3
  8. package/dist/dateRangeOption-Doo6WHKu.js.map +1 -0
  9. package/dist/style.css +16 -6
  10. package/dist/util.d.ts +107 -41
  11. package/dist/util.js +1 -1
  12. package/package.json +10 -4
  13. package/src/preact/aggregatedData/aggregate.stories.tsx +14 -0
  14. package/src/preact/aggregatedData/aggregate.tsx +17 -15
  15. package/src/preact/components/error-boundary.stories.tsx +24 -3
  16. package/src/preact/components/error-boundary.tsx +3 -4
  17. package/src/preact/components/error-display.tsx +38 -17
  18. package/src/preact/components/tabs.tsx +2 -2
  19. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +1 -1
  20. package/src/preact/lineageFilter/lineage-filter.stories.tsx +1 -1
  21. package/src/preact/locationFilter/location-filter.stories.tsx +1 -1
  22. package/src/preact/map/__mockData__/aggregatedGermany.json +83 -0
  23. package/src/preact/map/__mockData__/aggregatedWorld.json +259 -0
  24. package/src/preact/map/__mockData__/germanyMap.json +9083 -0
  25. package/src/preact/map/__mockData__/howToGenerateWorldMap.md +9 -0
  26. package/src/preact/map/__mockData__/worldAtlas.json +497127 -0
  27. package/src/preact/map/leafletStyleModifications.css +3 -0
  28. package/src/preact/map/sequences-by-location-map.tsx +202 -0
  29. package/src/preact/map/sequences-by-location-table.tsx +18 -0
  30. package/src/preact/map/sequences-by-location.stories.tsx +144 -0
  31. package/src/preact/map/sequences-by-location.tsx +151 -0
  32. package/src/preact/map/useGeoJsonMap.tsx +62 -0
  33. package/src/preact/mutationComparison/mutation-comparison.tsx +1 -1
  34. package/src/preact/mutationFilter/mutation-filter.tsx +26 -13
  35. package/src/preact/mutations/mutations.tsx +16 -12
  36. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +14 -0
  37. package/src/preact/mutationsOverTime/mutations-over-time.tsx +18 -14
  38. package/src/preact/numberSequencesOverTime/number-sequences-over-time.stories.tsx +14 -0
  39. package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +22 -14
  40. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +14 -0
  41. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +28 -19
  42. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +14 -0
  43. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +18 -15
  44. package/src/preact/shared/charts/confideceInterval.ts +10 -8
  45. package/src/preact/shared/charts/getYAxisMax.ts +10 -5
  46. package/src/preact/shared/stories/expectErrorMessage.ts +21 -0
  47. package/src/preact/statistic/statistics.tsx +10 -8
  48. package/src/preact/textInput/text-input.stories.tsx +14 -0
  49. package/src/preact/textInput/text-input.tsx +16 -11
  50. package/src/preact/useQuery.ts +9 -1
  51. package/src/query/queryAggregateData.ts +2 -1
  52. package/src/styles/tailwind.css +1 -1
  53. package/src/types.ts +13 -1
  54. package/src/utilEntrypoint.ts +7 -0
  55. package/src/web-components/app.stories.ts +17 -2
  56. package/src/web-components/app.ts +17 -5
  57. package/src/web-components/input/gs-mutation-filter.stories.ts +2 -0
  58. package/src/web-components/input/gs-text-input.tsx +2 -2
  59. package/src/web-components/introduction.mdx +4 -4
  60. package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +3 -3
  61. package/src/web-components/visualization/gs-mutations-over-time.tsx +1 -3
  62. package/src/web-components/visualization/gs-mutations.tsx +1 -3
  63. package/src/web-components/visualization/gs-number-sequences-over-time.tsx +1 -3
  64. package/src/web-components/visualization/gs-prevalence-over-time.tsx +3 -6
  65. package/src/web-components/visualization/gs-relative-growth-advantage.tsx +1 -5
  66. package/src/web-components/visualization/gs-sequences-by-location.stories.ts +234 -0
  67. package/src/web-components/visualization/gs-sequences-by-location.tsx +253 -0
  68. package/src/web-components/visualization/index.ts +1 -0
  69. package/standalone-bundle/assets/mutationOverTimeWorker-DoUBht2e.js.map +1 -0
  70. package/standalone-bundle/dashboard-components.js +16223 -9292
  71. package/standalone-bundle/dashboard-components.js.map +1 -1
  72. package/standalone-bundle/style.css +1 -1
  73. package/dist/assets/mutationOverTimeWorker-Di6yP1e6.js.map +0 -1
  74. package/dist/dateRangeOption-du8H7LWu.js.map +0 -1
  75. package/src/preact/shared/stories/expectInvalidAttributesErrorMessage.ts +0 -13
  76. package/standalone-bundle/assets/mutationOverTimeWorker-cIyshfj_.js.map +0 -1
@@ -80,6 +80,14 @@
80
80
  },
81
81
  "default": "{ ...Template, play: async ({ canvasElement }) => { const canvas = within(canvasElement); await waitFor(() => { expect(canvas.getByText(LAPIS_URL)).toBeVisible(); expect(canvas.getByText('\"name\": \"ORF1a\",', { exact: false })).toBeVisible(); }); }, }"
82
82
  },
83
+ {
84
+ "kind": "variable",
85
+ "name": "WithNoLapisUrl",
86
+ "type": {
87
+ "text": "StoryObj<{ lapis: string }>"
88
+ },
89
+ "default": "{ ...Default, args: { ...Default.args, lapis: 'notAValidUrl', }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); await waitFor(() => { expect(canvas.getByText(\"Error: Invalid LAPIS URL: 'notAValidUrl'\", { exact: false })).toBeVisible(); }); }, }"
90
+ },
83
91
  {
84
92
  "kind": "variable",
85
93
  "name": "DelayFetchingReferenceGenome",
@@ -94,7 +102,7 @@
94
102
  "type": {
95
103
  "text": "StoryObj<{ lapis: string }>"
96
104
  },
97
- "default": "{ ...Template, args: { lapis: 'definitely-not-a-valid-url', }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); await waitFor(() => { expect(canvas.getByText('Error', { exact: false })).toBeVisible(); }); }, }"
105
+ "default": "{ ...Template, args: { lapis: 'https://url.to.lapis-definitely-not-a-valid-url', }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); await waitFor(() => { expect(canvas.getByText('Error: Cannot fetch reference genome.', { exact: false })).toBeVisible(); }); }, }"
98
106
  },
99
107
  {
100
108
  "kind": "class",
@@ -143,6 +151,14 @@
143
151
  "module": "src/web-components/app.stories.ts"
144
152
  }
145
153
  },
154
+ {
155
+ "kind": "js",
156
+ "name": "WithNoLapisUrl",
157
+ "declaration": {
158
+ "name": "WithNoLapisUrl",
159
+ "module": "src/web-components/app.stories.ts"
160
+ }
161
+ },
146
162
  {
147
163
  "kind": "js",
148
164
  "name": "DelayFetchingReferenceGenome",
@@ -918,7 +934,7 @@
918
934
  "type": {
919
935
  "text": "StoryObj<MutationFilterProps>"
920
936
  },
921
- "default": "{ ...Template, args: { initialValue: ['A123T'], }, }"
937
+ "default": "{ ...Template, args: { ...Template.args, initialValue: ['A123T'], }, }"
922
938
  },
923
939
  {
924
940
  "kind": "variable",
@@ -934,7 +950,7 @@
934
950
  "type": {
935
951
  "text": "StoryObj<MutationFilterProps>"
936
952
  },
937
- "default": "{ ...Template, args: { initialValue: ['seg1:123T', 'gene2:56', 'ins_seg2:78:AAA'], }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'referenceGenome', url: REFERENCE_GENOME_ENDPOINT, }, response: { status: 200, body: { nucleotideSequences: [ { name: 'seg1', sequence: 'dummy', }, { name: 'seg2', sequence: 'dummy', }, ], genes: [ { name: 'gene1', sequence: 'dummy', }, { name: 'gene2', sequence: 'dummy', }, ], }, }, options: { overwriteRoutes: false, }, }, ], }, }, play: async ({ canvasElement }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-filter'); const inputField = () => canvas.getByPlaceholderText('Enter a mutation', { exact: false }); await waitFor(() => { const placeholderText = inputField().getAttribute('placeholder'); expect(placeholderText).toEqual( 'Enter a mutation (e.g. seg1:A123T, ins_seg1:123:AT, gene1:M123E, ins_gene1:123:ME)', ); }); await waitFor(() => { expect(canvas.getByText('seg1:123T')).toBeVisible(); expect(canvas.getByText('gene2:56')).toBeVisible(); return expect(canvas.getByText('ins_seg2:78:AAA')).toBeVisible(); }); }, }"
953
+ "default": "{ ...Template, args: { ...Template.args, initialValue: ['seg1:123T', 'gene2:56', 'ins_seg2:78:AAA'], }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'referenceGenome', url: REFERENCE_GENOME_ENDPOINT, }, response: { status: 200, body: { nucleotideSequences: [ { name: 'seg1', sequence: 'dummy', }, { name: 'seg2', sequence: 'dummy', }, ], genes: [ { name: 'gene1', sequence: 'dummy', }, { name: 'gene2', sequence: 'dummy', }, ], }, }, options: { overwriteRoutes: false, }, }, ], }, }, play: async ({ canvasElement }) => { const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-filter'); const inputField = () => canvas.getByPlaceholderText('Enter a mutation', { exact: false }); await waitFor(() => { const placeholderText = inputField().getAttribute('placeholder'); expect(placeholderText).toEqual( 'Enter a mutation (e.g. seg1:A123T, ins_seg1:123:AT, gene1:M123E, ins_gene1:123:ME)', ); }); await waitFor(() => { expect(canvas.getByText('seg1:123T')).toBeVisible(); expect(canvas.getByText('gene2:56')).toBeVisible(); return expect(canvas.getByText('ins_seg2:78:AAA')).toBeVisible(); }); }, }"
938
954
  }
939
955
  ],
940
956
  "exports": [
@@ -1127,9 +1143,9 @@
1127
1143
  "kind": "field",
1128
1144
  "name": "initialValue",
1129
1145
  "type": {
1130
- "text": "string"
1146
+ "text": "string | undefined"
1131
1147
  },
1132
- "default": "''",
1148
+ "default": "undefined",
1133
1149
  "description": "The initial value to use for this text input.",
1134
1150
  "attribute": "initialValue"
1135
1151
  },
@@ -1147,9 +1163,9 @@
1147
1163
  "kind": "field",
1148
1164
  "name": "placeholderText",
1149
1165
  "type": {
1150
- "text": "string"
1166
+ "text": "string | undefined"
1151
1167
  },
1152
- "default": "''",
1168
+ "default": "undefined",
1153
1169
  "description": "The placeholder text to display in the input field.",
1154
1170
  "attribute": "placeholderText"
1155
1171
  },
@@ -1177,9 +1193,9 @@
1177
1193
  {
1178
1194
  "name": "initialValue",
1179
1195
  "type": {
1180
- "text": "string"
1196
+ "text": "string | undefined"
1181
1197
  },
1182
- "default": "''",
1198
+ "default": "undefined",
1183
1199
  "description": "The initial value to use for this text input.",
1184
1200
  "fieldName": "initialValue"
1185
1201
  },
@@ -1195,9 +1211,9 @@
1195
1211
  {
1196
1212
  "name": "placeholderText",
1197
1213
  "type": {
1198
- "text": "string"
1214
+ "text": "string | undefined"
1199
1215
  },
1200
- "default": "''",
1216
+ "default": "undefined",
1201
1217
  "description": "The placeholder text to display in the input field.",
1202
1218
  "fieldName": "placeholderText"
1203
1219
  },
@@ -1887,7 +1903,7 @@
1887
1903
  "text": "Record<string, string | number | null | boolean>"
1888
1904
  },
1889
1905
  "default": "{}",
1890
- "description": "Required.\n\nLAPIS filter to select the displayed data.",
1906
+ "description": "LAPIS filter to select the displayed data. If not provided, all data is displayed.",
1891
1907
  "attribute": "lapisFilter"
1892
1908
  },
1893
1909
  {
@@ -1958,7 +1974,7 @@
1958
1974
  "text": "Record<string, string | number | null | boolean>"
1959
1975
  },
1960
1976
  "default": "{}",
1961
- "description": "Required.\n\nLAPIS filter to select the displayed data.",
1977
+ "description": "LAPIS filter to select the displayed data. If not provided, all data is displayed.",
1962
1978
  "fieldName": "lapisFilter"
1963
1979
  },
1964
1980
  {
@@ -2131,7 +2147,7 @@
2131
2147
  "text": "Record<string, string | number | null | boolean>"
2132
2148
  },
2133
2149
  "default": "{}",
2134
- "description": "Required.\n\nLAPIS filter to select the displayed data.",
2150
+ "description": "LAPIS filter to select the displayed data. If not provided, all data is displayed.",
2135
2151
  "attribute": "lapisFilter"
2136
2152
  },
2137
2153
  {
@@ -2192,7 +2208,7 @@
2192
2208
  "text": "Record<string, string | number | null | boolean>"
2193
2209
  },
2194
2210
  "default": "{}",
2195
- "description": "Required.\n\nLAPIS filter to select the displayed data.",
2211
+ "description": "LAPIS filter to select the displayed data. If not provided, all data is displayed.",
2196
2212
  "fieldName": "lapisFilter"
2197
2213
  },
2198
2214
  {
@@ -2388,7 +2404,7 @@
2388
2404
  "text": "{\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }\n | {\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }[]"
2389
2405
  },
2390
2406
  "default": "{ displayName: '', lapisFilter: {} }",
2391
- "description": "Required.\n\nEither a LAPIS filter or an array of LAPIS filters to fetch the number of sequences for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used to label the component views.\nIt should be human-readable.",
2407
+ "description": "Either a LAPIS filter or an array of LAPIS filters to fetch the number of sequences for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used to label the component views.\nIt should be human-readable.",
2392
2408
  "attribute": "lapisFilter"
2393
2409
  },
2394
2410
  {
@@ -2397,7 +2413,7 @@
2397
2413
  "type": {
2398
2414
  "text": "string"
2399
2415
  },
2400
- "default": "'date'",
2416
+ "default": "''",
2401
2417
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
2402
2418
  "attribute": "lapisDateField"
2403
2419
  },
@@ -2469,7 +2485,7 @@
2469
2485
  "text": "{\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }\n | {\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }[]"
2470
2486
  },
2471
2487
  "default": "{ displayName: '', lapisFilter: {} }",
2472
- "description": "Required.\n\nEither a LAPIS filter or an array of LAPIS filters to fetch the number of sequences for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used to label the component views.\nIt should be human-readable.",
2488
+ "description": "Either a LAPIS filter or an array of LAPIS filters to fetch the number of sequences for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used to label the component views.\nIt should be human-readable.",
2473
2489
  "fieldName": "lapisFilter"
2474
2490
  },
2475
2491
  {
@@ -2477,7 +2493,7 @@
2477
2493
  "type": {
2478
2494
  "text": "string"
2479
2495
  },
2480
- "default": "'date'",
2496
+ "default": "''",
2481
2497
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
2482
2498
  "fieldName": "lapisDateField"
2483
2499
  },
@@ -2682,8 +2698,8 @@
2682
2698
  "type": {
2683
2699
  "text": "{\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }\n | {\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }[]"
2684
2700
  },
2685
- "default": "{displayName: '', lapisFilter: {}}",
2686
- "description": "Required.\nEither a LAPIS filter or an array of LAPIS filters to calculate the prevalence for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used as the label the prevalence in the views.\nIt should be human-readable.",
2701
+ "default": "{ displayName: '', lapisFilter: {} }",
2702
+ "description": "Either a LAPIS filter or an array of LAPIS filters to calculate the prevalence for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used as the label the prevalence in the views.\nIt should be human-readable.",
2687
2703
  "attribute": "numeratorFilter"
2688
2704
  },
2689
2705
  {
@@ -2693,7 +2709,7 @@
2693
2709
  "text": "Record<string, string | number | null | boolean>"
2694
2710
  },
2695
2711
  "default": "{}",
2696
- "description": "Required.\n\nThe LAPIS filter, to select the data of the reference.\nIt must be a valid LAPIS filter object.",
2712
+ "description": "The LAPIS filter, to select the data of the reference.\nIt must be a valid LAPIS filter object.",
2697
2713
  "attribute": "denominatorFilter"
2698
2714
  },
2699
2715
  {
@@ -2762,7 +2778,7 @@
2762
2778
  "type": {
2763
2779
  "text": "string"
2764
2780
  },
2765
- "default": "'date'",
2781
+ "default": "''",
2766
2782
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
2767
2783
  "attribute": "lapisDateField"
2768
2784
  },
@@ -2803,8 +2819,8 @@
2803
2819
  "type": {
2804
2820
  "text": "{\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }\n | {\n lapisFilter: Record<string, string | number | null | boolean>;\n displayName: string;\n }[]"
2805
2821
  },
2806
- "default": "{displayName: '', lapisFilter: {}}",
2807
- "description": "Required.\nEither a LAPIS filter or an array of LAPIS filters to calculate the prevalence for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used as the label the prevalence in the views.\nIt should be human-readable.",
2822
+ "default": "{ displayName: '', lapisFilter: {} }",
2823
+ "description": "Either a LAPIS filter or an array of LAPIS filters to calculate the prevalence for.\n\nThe `lapisFilter` will be sent as is to LAPIS to select the data.\nIt must be a valid LAPIS filter object.\n\nThe `displayName` will be used as the label the prevalence in the views.\nIt should be human-readable.",
2808
2824
  "fieldName": "numeratorFilter"
2809
2825
  },
2810
2826
  {
@@ -2813,7 +2829,7 @@
2813
2829
  "text": "Record<string, string | number | null | boolean>"
2814
2830
  },
2815
2831
  "default": "{}",
2816
- "description": "Required.\n\nThe LAPIS filter, to select the data of the reference.\nIt must be a valid LAPIS filter object.",
2832
+ "description": "The LAPIS filter, to select the data of the reference.\nIt must be a valid LAPIS filter object.",
2817
2833
  "fieldName": "denominatorFilter"
2818
2834
  },
2819
2835
  {
@@ -2875,7 +2891,7 @@
2875
2891
  "type": {
2876
2892
  "text": "string"
2877
2893
  },
2878
- "default": "'date'",
2894
+ "default": "''",
2879
2895
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
2880
2896
  "fieldName": "lapisDateField"
2881
2897
  },
@@ -2990,7 +3006,7 @@
2990
3006
  "text": "Record<string, string | number | null | boolean>"
2991
3007
  },
2992
3008
  "default": "{}",
2993
- "description": "Required.\n\nLAPIS filter to select the data of the focal variant.\nIt must be a valid LAPIS filter object.",
3009
+ "description": "LAPIS filter to select the data of the focal variant.\nIt must be a valid LAPIS filter object.",
2994
3010
  "attribute": "numeratorFilter"
2995
3011
  },
2996
3012
  {
@@ -3000,7 +3016,7 @@
3000
3016
  "text": "Record<string, string | number | null | boolean>"
3001
3017
  },
3002
3018
  "default": "{}",
3003
- "description": "Required.\n\nLAPIS filter to select the data of the baseline variant.\nIt must be a valid LAPIS filter object.",
3019
+ "description": "LAPIS filter to select the data of the baseline variant.\nIt must be a valid LAPIS filter object.",
3004
3020
  "attribute": "denominatorFilter"
3005
3021
  },
3006
3022
  {
@@ -3049,7 +3065,7 @@
3049
3065
  "type": {
3050
3066
  "text": "string"
3051
3067
  },
3052
- "default": "'date'",
3068
+ "default": "''",
3053
3069
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
3054
3070
  "attribute": "lapisDateField"
3055
3071
  },
@@ -3081,7 +3097,7 @@
3081
3097
  "text": "Record<string, string | number | null | boolean>"
3082
3098
  },
3083
3099
  "default": "{}",
3084
- "description": "Required.\n\nLAPIS filter to select the data of the focal variant.\nIt must be a valid LAPIS filter object.",
3100
+ "description": "LAPIS filter to select the data of the focal variant.\nIt must be a valid LAPIS filter object.",
3085
3101
  "fieldName": "numeratorFilter"
3086
3102
  },
3087
3103
  {
@@ -3090,7 +3106,7 @@
3090
3106
  "text": "Record<string, string | number | null | boolean>"
3091
3107
  },
3092
3108
  "default": "{}",
3093
- "description": "Required.\n\nLAPIS filter to select the data of the baseline variant.\nIt must be a valid LAPIS filter object.",
3109
+ "description": "LAPIS filter to select the data of the baseline variant.\nIt must be a valid LAPIS filter object.",
3094
3110
  "fieldName": "denominatorFilter"
3095
3111
  },
3096
3112
  {
@@ -3134,7 +3150,7 @@
3134
3150
  "type": {
3135
3151
  "text": "string"
3136
3152
  },
3137
- "default": "'date'",
3153
+ "default": "''",
3138
3154
  "description": "Required.\n\nThe LAPIS field that the data should be aggregated by.\nThe values will be used on the x-axis of the diagram.\nMust be a field of type `date` in LAPIS.",
3139
3155
  "fieldName": "lapisDateField"
3140
3156
  },
@@ -3184,6 +3200,326 @@
3184
3200
  }
3185
3201
  ]
3186
3202
  },
3203
+ {
3204
+ "kind": "javascript-module",
3205
+ "path": "src/web-components/visualization/gs-sequences-by-location.stories.ts",
3206
+ "declarations": [
3207
+ {
3208
+ "kind": "variable",
3209
+ "name": "meta",
3210
+ "type": {
3211
+ "text": "Meta<Required<SequencesByLocationProps>>"
3212
+ },
3213
+ "default": "{ title: 'Visualization/Sequences by location', component: 'gs-sequences-by-location', argTypes: {}, parameters: withComponentDocs({ fetchMock: { mocks: [ { matcher: { name: 'aggregatedData', url: AGGREGATED_ENDPOINT, body: { fields: ['division', 'host'], country: 'USA', }, }, response: { status: 200, body: aggregatedData, }, }, ], }, componentDocs: { opensShadowDom: true, expectsChildren: false, codeExample, }, }), tags: ['autodocs'], }"
3214
+ },
3215
+ {
3216
+ "kind": "variable",
3217
+ "name": "WorldMap",
3218
+ "type": {
3219
+ "text": "StoryObj<SequencesByLocationProps>"
3220
+ },
3221
+ "default": "{ ...Template, args: { ...Template.args, lapisFilter: { dateFrom: '2022-01-01', dateTo: '2022-04-01' }, lapisLocationField: 'country', mapSource: { type: 'topojson', url: mockMapUrl, topologyObjectsKey: 'countries', }, zoom: 2, offsetX: 0, offsetY: 10, }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'worldMap', url: mockMapUrl, }, response: { status: 200, body: worldAtlas, }, }, { matcher: { name: 'aggregatedData', url: AGGREGATED_ENDPOINT, body: { fields: ['country'], dateFrom: '2022-01-01', dateTo: '2022-04-01', }, }, response: { status: 200, body: aggregatedWorld, }, }, ], }, }, }"
3222
+ },
3223
+ {
3224
+ "kind": "variable",
3225
+ "name": "Germany",
3226
+ "type": {
3227
+ "text": "StoryObj<SequencesByLocationProps>"
3228
+ },
3229
+ "default": "{ ...Template, args: { ...Template.args, lapisFilter: { dateFrom: '2022-01-01', dateTo: '2022-04-01', country: 'Germany' }, lapisLocationField: 'division', mapSource: { type: 'topojson', url: mockMapUrl, topologyObjectsKey: 'deu', }, views: ['map', 'table'], zoom: 6.3, offsetX: 10, offsetY: 51.4, }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'worldMap', url: mockMapUrl, }, response: { status: 200, body: mapOfGermany, }, }, { matcher: { name: 'aggregatedData', url: AGGREGATED_ENDPOINT, body: { fields: ['division'], dateFrom: '2022-01-01', dateTo: '2022-04-01', country: 'Germany', }, }, response: { status: 200, body: aggregatedGermany, }, }, ], }, }, }"
3230
+ },
3231
+ {
3232
+ "kind": "variable",
3233
+ "name": "GermanyTableOnly",
3234
+ "type": {
3235
+ "text": "StoryObj<SequencesByLocationProps>"
3236
+ },
3237
+ "default": "{ render: (args) => html` <gs-app lapis=\"${LAPIS_URL}\"> <gs-sequences-by-location .lapisFilter=${args.lapisFilter} .lapisLocationField=${args.lapisLocationField} .width=${args.width} .height=${args.height} .views=${args.views} .pageSize=${args.pageSize} ></gs-sequences-by-location> </gs-app> `, args: { lapisFilter: { dateFrom: '2022-01-01', dateTo: '2022-04-01', country: 'Germany' }, lapisLocationField: 'division', width: '100%', height: '700px', views: ['table'], pageSize: 10, }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'aggregatedData', url: AGGREGATED_ENDPOINT, body: { fields: ['division'], dateFrom: '2022-01-01', dateTo: '2022-04-01', country: 'Germany', }, }, response: { status: 200, body: aggregatedGermany, }, }, ], }, }, }"
3238
+ }
3239
+ ],
3240
+ "exports": [
3241
+ {
3242
+ "kind": "js",
3243
+ "name": "default",
3244
+ "declaration": {
3245
+ "name": "meta",
3246
+ "module": "src/web-components/visualization/gs-sequences-by-location.stories.ts"
3247
+ }
3248
+ },
3249
+ {
3250
+ "kind": "js",
3251
+ "name": "WorldMap",
3252
+ "declaration": {
3253
+ "name": "WorldMap",
3254
+ "module": "src/web-components/visualization/gs-sequences-by-location.stories.ts"
3255
+ }
3256
+ },
3257
+ {
3258
+ "kind": "js",
3259
+ "name": "Germany",
3260
+ "declaration": {
3261
+ "name": "Germany",
3262
+ "module": "src/web-components/visualization/gs-sequences-by-location.stories.ts"
3263
+ }
3264
+ },
3265
+ {
3266
+ "kind": "js",
3267
+ "name": "GermanyTableOnly",
3268
+ "declaration": {
3269
+ "name": "GermanyTableOnly",
3270
+ "module": "src/web-components/visualization/gs-sequences-by-location.stories.ts"
3271
+ }
3272
+ }
3273
+ ]
3274
+ },
3275
+ {
3276
+ "kind": "javascript-module",
3277
+ "path": "src/web-components/visualization/gs-sequences-by-location.tsx",
3278
+ "declarations": [
3279
+ {
3280
+ "kind": "class",
3281
+ "description": "## Context\n\nThis component shows the geographic distribution of sequence data from LAPIS.\nIt displays the count and proportion (number of sample per `lapisLocationField` / number of samples matching the `lapisFilter`)\nof the data by location.\n\n## Views\n\n### Map View\n\nThis view displays a chloropleth map based on [Leaflet](https://leafletjs.com/).\nThe component expects a `mapSource` object that specifies where the map data can be downloaded from.\nWe can imagine that we add other map source types later (for example, GeoJSON).\n\n#### TopoJSON\n\nSuppose you provide this example object as `mapSource`:\n\n```json\n{\n \"type\": \"topojson\",\n \"url\": \"https://example.com/map.topojson\",\n \"topologyObjectsKey\": \"myObjectKey\"\n}\n```\n\nThe URL must point to a [TopoJSON file](https://github.com/topojson/topojson) that contains the map data.\nThe TopoJSON file must schematically look like this,\nwhere `objects[topologyObjectsKey]` must be a valid GeometryCollection (`objects.myObjectKey` in this example):\n\n```json\n{\n \"type\": \"Topology\",\n \"objects\": {\n \"myObjectKey\": {\n \"type\": \"GeometryCollection\",\n \"geometries\": [\n {\n \"type\": \"Polygon\",\n \"properties\": {\n \"name\": \"North Rhine Westphalia\"\n },\n \"id\": \"DE.NW\",\n \"arcs\": [...]\n },\n ...\n ]\n }\n },\n \"arcs\": [...],\n \"transform\": {...}\n}\n```\n\nYou can use any valid TopoJSON file.\nhttps://github.com/markmarkoh/datamaps/tree/master/src/js/data contains TopoJSON files for many countries.\n\nThe `lapisFilter` is used to select the data to display, and it is aggregated by the `lapisLocationField`.\nThis component assumes that every geometry object in the TopoJSON file has a `properties.name` field.\n\nThe values that LAPIS returns for `lapisLocationField` must match the `properties.name` in the map data.\nLAPIS entries where `lapisLocationField` is `null` are ignored on the map.\n\nThe names of the locations in the TopoJSON map and in LAPIS should match.\nHowever, there are two cases of misalignment:\n- If there is a LAPIS location that does not match any location in the TopoJSON map,\n the component will log a console warning to assist in creating map data that aligns with the LAPIS data.\n- If a TopoJSON location does not match any LAPIS location for the given filter,\n no data will be displayed for this location.\n This is expected, as LAPIS will only return locations where sequences have been collected for that filter.\n\n### Table View\n\nThis view displays the data in a table format.\nIt is similar to the table view of the `gs-aggregate` component.\nThe table has three columns:\n- `lapisLocationField`,\n- `count` (the number of samples in this location matching the `lapisFilter`),\n- `proportion` (`count` / sum of the `count` of all locations).",
3282
+ "name": "SequencesByLocationComponent",
3283
+ "members": [
3284
+ {
3285
+ "kind": "field",
3286
+ "name": "lapisFilter",
3287
+ "type": {
3288
+ "text": "Record<string, string | number | null | boolean>"
3289
+ },
3290
+ "default": "{}",
3291
+ "description": "LAPIS filter to select the displayed data.\nIf you want to display the distribution over the states of a certain country,\nyou should usually filter by that country here (e.g. { country: 'USA' }).",
3292
+ "attribute": "lapisFilter"
3293
+ },
3294
+ {
3295
+ "kind": "field",
3296
+ "name": "lapisLocationField",
3297
+ "type": {
3298
+ "text": "string"
3299
+ },
3300
+ "default": "''",
3301
+ "description": "Required.\n\nThe location field to aggregate the data by.\nThis should match the selected map location granularity.",
3302
+ "attribute": "lapisLocationField"
3303
+ },
3304
+ {
3305
+ "kind": "field",
3306
+ "name": "mapSource",
3307
+ "type": {
3308
+ "text": "{ type: 'topojson'; url: string; topologyObjectsKey: string } | undefined"
3309
+ },
3310
+ "default": "undefined",
3311
+ "description": "Required when using the map view.\n\nThe source of the map data. See component level docs for more information.",
3312
+ "attribute": "mapSource"
3313
+ },
3314
+ {
3315
+ "kind": "field",
3316
+ "name": "enableMapNavigation",
3317
+ "type": {
3318
+ "text": "boolean"
3319
+ },
3320
+ "default": "true",
3321
+ "description": "Enable map navigation (dragging, keyboard navigation, zooming).",
3322
+ "attribute": "enableMapNavigation"
3323
+ },
3324
+ {
3325
+ "kind": "field",
3326
+ "name": "width",
3327
+ "type": {
3328
+ "text": "string"
3329
+ },
3330
+ "default": "'100%'",
3331
+ "description": "The width of the component.\nNot that the map in the map view is not responsive\n(i.e. does not adjust its size when the component is resized).\n\nVisit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.",
3332
+ "attribute": "width"
3333
+ },
3334
+ {
3335
+ "kind": "field",
3336
+ "name": "height",
3337
+ "type": {
3338
+ "text": "string"
3339
+ },
3340
+ "default": "'700px'",
3341
+ "description": "The height of the component.\n\nVisit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.",
3342
+ "attribute": "height"
3343
+ },
3344
+ {
3345
+ "kind": "field",
3346
+ "name": "views",
3347
+ "type": {
3348
+ "text": "('map' | 'table')[]"
3349
+ },
3350
+ "default": "['map', 'table']",
3351
+ "description": "A list of tabs with views that this component should provide.",
3352
+ "attribute": "views"
3353
+ },
3354
+ {
3355
+ "kind": "field",
3356
+ "name": "zoom",
3357
+ "type": {
3358
+ "text": "number"
3359
+ },
3360
+ "default": "1",
3361
+ "description": "The initial zoom level of the map.",
3362
+ "attribute": "zoom"
3363
+ },
3364
+ {
3365
+ "kind": "field",
3366
+ "name": "offsetX",
3367
+ "type": {
3368
+ "text": "number"
3369
+ },
3370
+ "default": "0",
3371
+ "description": "Initially shift the center of the map in x direction (longitude).\n\n`-180` is the International Date Line with the map shifted to the right, `0` is the prime meridian,\n`180` is the International Date Line with the map shifted to the left.",
3372
+ "attribute": "offsetX"
3373
+ },
3374
+ {
3375
+ "kind": "field",
3376
+ "name": "offsetY",
3377
+ "type": {
3378
+ "text": "number"
3379
+ },
3380
+ "default": "0",
3381
+ "description": "Initially shift the center of the map in y direction (latitude).\n\n`-90` is the South Pole, `0` is the equator, `90` is the North Pole.",
3382
+ "attribute": "offsetY"
3383
+ },
3384
+ {
3385
+ "kind": "field",
3386
+ "name": "pageSize",
3387
+ "type": {
3388
+ "text": "boolean | number"
3389
+ },
3390
+ "default": "false",
3391
+ "description": "The maximum number of rows to display in the table view.\nSet to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).",
3392
+ "attribute": "pageSize"
3393
+ }
3394
+ ],
3395
+ "attributes": [
3396
+ {
3397
+ "name": "lapisFilter",
3398
+ "type": {
3399
+ "text": "Record<string, string | number | null | boolean>"
3400
+ },
3401
+ "default": "{}",
3402
+ "description": "LAPIS filter to select the displayed data.\nIf you want to display the distribution over the states of a certain country,\nyou should usually filter by that country here (e.g. { country: 'USA' }).",
3403
+ "fieldName": "lapisFilter"
3404
+ },
3405
+ {
3406
+ "name": "lapisLocationField",
3407
+ "type": {
3408
+ "text": "string"
3409
+ },
3410
+ "default": "''",
3411
+ "description": "Required.\n\nThe location field to aggregate the data by.\nThis should match the selected map location granularity.",
3412
+ "fieldName": "lapisLocationField"
3413
+ },
3414
+ {
3415
+ "name": "mapSource",
3416
+ "type": {
3417
+ "text": "{ type: 'topojson'; url: string; topologyObjectsKey: string } | undefined"
3418
+ },
3419
+ "default": "undefined",
3420
+ "description": "Required when using the map view.\n\nThe source of the map data. See component level docs for more information.",
3421
+ "fieldName": "mapSource"
3422
+ },
3423
+ {
3424
+ "name": "enableMapNavigation",
3425
+ "type": {
3426
+ "text": "boolean"
3427
+ },
3428
+ "default": "true",
3429
+ "description": "Enable map navigation (dragging, keyboard navigation, zooming).",
3430
+ "fieldName": "enableMapNavigation"
3431
+ },
3432
+ {
3433
+ "name": "width",
3434
+ "type": {
3435
+ "text": "string"
3436
+ },
3437
+ "default": "'100%'",
3438
+ "description": "The width of the component.\nNot that the map in the map view is not responsive\n(i.e. does not adjust its size when the component is resized).\n\nVisit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.",
3439
+ "fieldName": "width"
3440
+ },
3441
+ {
3442
+ "name": "height",
3443
+ "type": {
3444
+ "text": "string"
3445
+ },
3446
+ "default": "'700px'",
3447
+ "description": "The height of the component.\n\nVisit https://genspectrum.github.io/dashboard-components/?path=/docs/components-size-of-components--docs for more information.",
3448
+ "fieldName": "height"
3449
+ },
3450
+ {
3451
+ "name": "views",
3452
+ "type": {
3453
+ "text": "('map' | 'table')[]"
3454
+ },
3455
+ "default": "['map', 'table']",
3456
+ "description": "A list of tabs with views that this component should provide.",
3457
+ "fieldName": "views"
3458
+ },
3459
+ {
3460
+ "name": "zoom",
3461
+ "type": {
3462
+ "text": "number"
3463
+ },
3464
+ "default": "1",
3465
+ "description": "The initial zoom level of the map.",
3466
+ "fieldName": "zoom"
3467
+ },
3468
+ {
3469
+ "name": "offsetX",
3470
+ "type": {
3471
+ "text": "number"
3472
+ },
3473
+ "default": "0",
3474
+ "description": "Initially shift the center of the map in x direction (longitude).\n\n`-180` is the International Date Line with the map shifted to the right, `0` is the prime meridian,\n`180` is the International Date Line with the map shifted to the left.",
3475
+ "fieldName": "offsetX"
3476
+ },
3477
+ {
3478
+ "name": "offsetY",
3479
+ "type": {
3480
+ "text": "number"
3481
+ },
3482
+ "default": "0",
3483
+ "description": "Initially shift the center of the map in y direction (latitude).\n\n`-90` is the South Pole, `0` is the equator, `90` is the North Pole.",
3484
+ "fieldName": "offsetY"
3485
+ },
3486
+ {
3487
+ "name": "pageSize",
3488
+ "type": {
3489
+ "text": "boolean | number"
3490
+ },
3491
+ "default": "false",
3492
+ "description": "The maximum number of rows to display in the table view.\nSet to `false` to disable pagination. Set to `true` to enable pagination with a default limit (10).",
3493
+ "fieldName": "pageSize"
3494
+ }
3495
+ ],
3496
+ "superclass": {
3497
+ "name": "PreactLitAdapterWithGridJsStyles",
3498
+ "module": "/src/web-components/PreactLitAdapterWithGridJsStyles"
3499
+ },
3500
+ "tagName": "gs-sequences-by-location",
3501
+ "customElement": true
3502
+ }
3503
+ ],
3504
+ "exports": [
3505
+ {
3506
+ "kind": "js",
3507
+ "name": "SequencesByLocationComponent",
3508
+ "declaration": {
3509
+ "name": "SequencesByLocationComponent",
3510
+ "module": "src/web-components/visualization/gs-sequences-by-location.tsx"
3511
+ }
3512
+ },
3513
+ {
3514
+ "kind": "custom-element-definition",
3515
+ "name": "gs-sequences-by-location",
3516
+ "declaration": {
3517
+ "name": "SequencesByLocationComponent",
3518
+ "module": "src/web-components/visualization/gs-sequences-by-location.tsx"
3519
+ }
3520
+ }
3521
+ ]
3522
+ },
3187
3523
  {
3188
3524
  "kind": "javascript-module",
3189
3525
  "path": "src/web-components/visualization/gs-statistics.stories.ts",
@@ -3400,6 +3736,14 @@
3400
3736
  "module": "./gs-mutations-over-time"
3401
3737
  }
3402
3738
  },
3739
+ {
3740
+ "kind": "js",
3741
+ "name": "SequencesByLocationComponent",
3742
+ "declaration": {
3743
+ "name": "SequencesByLocationComponent",
3744
+ "module": "./gs-sequences-by-location"
3745
+ }
3746
+ },
3403
3747
  {
3404
3748
  "kind": "js",
3405
3749
  "name": "StatisticsComponent",