diff --git a/components/src/preact/map/sequences-by-location-map.tsx b/components/src/preact/map/sequences-by-location-map.tsx index 02db2644..99834584 100644 --- a/components/src/preact/map/sequences-by-location-map.tsx +++ b/components/src/preact/map/sequences-by-location-map.tsx @@ -1,10 +1,11 @@ import type { Feature, FeatureCollection, GeometryObject } from 'geojson'; import Leaflet, { type Layer, type LayerGroup } from 'leaflet'; import type { FunctionComponent } from 'preact'; -import { useEffect, useRef } from 'preact/hooks'; +import { useEffect, useMemo, useRef } from 'preact/hooks'; import { type GeoJsonFeatureProperties, type MapSource, useGeoJsonMap } from './useGeoJsonMap'; import { type AggregateData } from '../../query/queryAggregateData'; +import { InfoHeadline1, InfoParagraph } from '../components/info'; import { LoadingDisplay } from '../components/loading-display'; import { formatProportion } from '../shared/table/formatProportion'; @@ -52,18 +53,27 @@ export const SequencesByLocationMapInner: FunctionComponent { const ref = useRef(null); - useEffect(() => { - if (!ref.current || geojsonData === undefined || locationData === undefined) { - return; - } - + const { locations, totalCount, countOfMatchedLocationData, unmatchedLocations } = useMemo(() => { const countAndProportionByCountry = buildLookupByLocationField(locationData, lapisLocationField); - const locations = matchLocationDataAndGeoJsonFeatures( + const { locations, unmatchedLocations } = matchLocationDataAndGeoJsonFeatures( geojsonData, countAndProportionByCountry, lapisLocationField, ); + const totalCount = locationData.map((value) => value.count).reduce((sum, b) => sum + b, 0); + const countOfMatchedLocationData = locations + .map((location) => location.properties.data?.count ?? 0) + .reduce((sum, b) => sum + b, 0); + + return { locations, totalCount, countOfMatchedLocationData, unmatchedLocations }; + }, [geojsonData, locationData, lapisLocationField]); + + useEffect(() => { + if (!ref.current) { + return; + } + const leafletMap = Leaflet.map(ref.current, { scrollWheelZoom: enableMapNavigation, zoomControl: enableMapNavigation, @@ -88,9 +98,82 @@ export const SequencesByLocationMapInner: FunctionComponent { leafletMap.remove(); }; - }, [ref, locationData, geojsonData, enableMapNavigation, lapisLocationField, zoom, offsetX, offsetY]); + }, [ref, locations, enableMapNavigation, lapisLocationField, zoom, offsetX, offsetY]); - return
; + const nullCount = locationData.find((row) => row[lapisLocationField] === null)?.count ?? 0; + + return ( +
+
+
+ +
+
+ ); +}; + +type DataMatchInformationProps = { + totalCount: number; + countOfMatchedLocationData: number; + unmatchedLocations: string[]; + nullCount: number; +}; + +const DataMatchInformation: FunctionComponent = ({ + totalCount, + countOfMatchedLocationData, + unmatchedLocations, + nullCount, +}) => { + const dialogRef = useRef(null); + + const proportion = formatProportion(countOfMatchedLocationData / totalCount); + + return ( + <> + + +
+ Sequences By Location - Map View + + The current filter has matched {totalCount.toLocaleString('en-us')} sequences. We were able to + match {countOfMatchedLocationData.toLocaleString('en-us')} sequences ({proportion}) on locations + on the map. + + {unmatchedLocations.length > 0 && ( + + The following locations from the data could not be matched on the map:{' '} + {unmatchedLocations.map((it) => `"${it}"`).join(', ')} + + )} + {nullCount > 0 && ( + + {nullCount.toLocaleString('en-us')} matching sequences have no location information. + + )} +
+
+ +
+
+
+
+ +
+
+ + ); }; function buildLookupByLocationField(locationData: AggregateData, lapisLocationField: string) { @@ -139,7 +222,7 @@ function matchLocationDataAndGeoJsonFeatures( console.warn(unmatchedLocationsWarning); // eslint-disable-line no-console -- We should give some feedback about unmatched location data. } - return locations; + return { locations, unmatchedLocations }; } function getColor(value: number | undefined): string { diff --git a/components/src/web-components/visualization/gs-sequences-by-location.stories.ts b/components/src/web-components/visualization/gs-sequences-by-location.stories.ts index 31a28116..a9b90020 100644 --- a/components/src/web-components/visualization/gs-sequences-by-location.stories.ts +++ b/components/src/web-components/visualization/gs-sequences-by-location.stories.ts @@ -84,7 +84,7 @@ const Template: StoryObj = { args: { enableMapNavigation: false, width: '1100px', - height: '800px', + height: '700px', views: ['map', 'table'], pageSize: 10, }, @@ -150,7 +150,7 @@ export const Germany: StoryObj = { topologyObjectsKey: 'deu', }, views: ['map', 'table'], - zoom: 6.3, + zoom: 6, offsetX: 10, offsetY: 51.4, }, diff --git a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-chromium-linux.png b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-chromium-linux.png index 4548a76b..2e0b0514 100644 Binary files a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-chromium-linux.png and b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-chromium-linux.png differ diff --git a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-firefox-linux.png b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-firefox-linux.png index 22c727a6..7ddda238 100644 Binary files a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-firefox-linux.png and b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--germany-should-match-screenshot-1-firefox-linux.png differ diff --git a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-chromium-linux.png b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-chromium-linux.png index aa47ab0f..a4ca4688 100644 Binary files a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-chromium-linux.png and b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-chromium-linux.png differ diff --git a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-firefox-linux.png b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-firefox-linux.png index 5b0e8b81..9f665644 100644 Binary files a/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-firefox-linux.png and b/components/tests/snapshots.spec.ts-snapshots/Sequences-by-location-Story-visualization-sequences-by-location--world-map-should-match-screenshot-1-firefox-linux.png differ