Skip to content
Merged
16 changes: 16 additions & 0 deletions static/js/tools/map/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import React, {
RefObject,
useContext,
useEffect,
useMemo,
} from "react";
import { Card, Container, FormGroup, Input, Label } from "reactstrap";

Expand Down Expand Up @@ -125,6 +126,20 @@ export function Chart(props: ChartProps): ReactElement {
statVarDateRanges[statVar.value.dcid] = { minDate, maxDate };
}

// Compile a deduplicated list of all entity DCIDs currently displayed
// across the map regions, map points, and breadcrumbs.
const entities = useMemo(
() =>
Array.from(
new Set([
...Object.keys(props.mapDataValues || {}),
...Object.keys(props.mapPointValues || {}),
...Object.keys(props.breadcrumbDataValues || {}),
])
),
[props.mapDataValues, props.mapPointValues, props.breadcrumbDataValues]
);

return (
<div className="chart-section-container">
<ToolChartHeader
Expand Down Expand Up @@ -200,6 +215,7 @@ export function Chart(props: ChartProps): ReactElement {
</Card>
<ToolChartFooter
chartId="map"
entities={entities}
sources={props.sources}
mMethods={null}
hidePerCapitaOption={!mainSvInfo.pcAllowed}
Expand Down
61 changes: 53 additions & 8 deletions static/js/tools/map/chart_loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,21 @@ export function ChartLoader(): ReactElement {
statVarToFacets[svDcid] = new Set();
}

// We check if there is a specific facet selected for this variable
const selectedFacetId =
svDcid === statVar.value.dcid ? statVar.value.metahash : null;
// Compile facets that are used in the actual map
const selectedFacetIds = new Set<string>();

if (
svDcid === statVar.value.dcid &&
chartStore.mapValuesDates.data?.numerFacets
) {
chartStore.mapValuesDates.data.numerFacets.forEach((f) => {
if (facetInfo.metadataMap[f]) {
selectedFacetIds.add(f);
}
});
}

const facetIdsToAdd =
selectedFacetId && facetInfo.metadataMap[selectedFacetId]
? [selectedFacetId]
: Object.keys(facetInfo.metadataMap);
const facetIdsToAdd = Array.from(selectedFacetIds);

for (const facetId of facetIdsToAdd) {
statVarToFacets[svDcid].add(facetId);
Expand All @@ -211,8 +218,36 @@ export function ChartLoader(): ReactElement {
}
}

// If per capita, explicitly include the denominator facets
// that were tracked during data processing.
const denom = statVar.value.denom;
const denomFacets = chartStore.mapValuesDates.data?.denomFacets;

if (statVar.value.perCapita && denom && denomFacets?.size > 0) {
if (!statVarToFacets[denom]) {
statVarToFacets[denom] = new Set();
}

const denomMetadataMap = chartStore.denomStat.data?.facets || {};

for (const facetId of Array.from(denomFacets)) {
statVarToFacets[denom].add(facetId);
if (denomMetadataMap[facetId]) {
facets[facetId] = denomMetadataMap[facetId];
}
}
}

return { facets, statVarToFacets };
}, [facetList, statVar.value.dcid, statVar.value.metahash]);
}, [
chartStore.denomStat.data?.facets,
chartStore.mapValuesDates.data?.denomFacets,
chartStore.mapValuesDates.data?.numerFacets,
facetList,
statVar.value.dcid,
statVar.value.denom,
statVar.value.perCapita,
]);

/**
* Callback function for building observation specifications.
Expand Down Expand Up @@ -348,6 +383,15 @@ export function ChartLoader(): ReactElement {
);

const footer = document.getElementById("metadata").dataset.footer || "";

const entities = Array.from(
new Set([
...Object.keys(chartStore.mapValuesDates.data?.mapValues || {}),
...Object.keys(chartStore.mapPointValues.data || {}),
...Object.keys(chartStore.breadcrumbValues.data || {}),
])
);

return (
<div className="chart-region" ref={containerRef}>
<Chart
Expand Down Expand Up @@ -409,6 +453,7 @@ export function ChartLoader(): ReactElement {
{footer && <div className="footer">* {footer}</div>}
<ChartEmbed
ref={embedModalElement}
entities={entities}
facets={facets}
statVarSpecs={currentStatVarSpec ? [currentStatVarSpec] : []}
statVarToFacets={statVarToFacets}
Expand Down
2 changes: 2 additions & 0 deletions static/js/tools/map/chart_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export interface ChartStore {
mapValues: { [dcid: string]: number };
mapDates: Set<string>;
unit?: string;
denomFacets?: Set<string>;
numerFacets?: Set<string>;
};
context?: DataContext;
};
Expand Down
13 changes: 12 additions & 1 deletion static/js/tools/map/compute/map_value_dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export function useComputeMapValueAndDate(
const mapValues = {};
const sources = new Set<string>();
const mapDates = new Set<string>();
const denomFacets = new Set<string>();
const numerFacets = new Set<string>();
const metadata = {};
const facets = Object.assign(
{},
Expand Down Expand Up @@ -98,6 +100,15 @@ export function useComputeMapValueAndDate(
}
mapValues[placeDcid] = placeChartData.value;
mapDates.add(placeChartData.date);

if (placeChartData.denomFacet) {
denomFacets.add(placeChartData.denomFacet);
}

if (wantedFacetData[placeDcid] && wantedFacetData[placeDcid].facet) {
numerFacets.add(wantedFacetData[placeDcid].facet);
}

if (!_.isEmpty(placeChartData.metadata)) {
metadata[placeDcid] = placeChartData.metadata;
}
Expand All @@ -117,7 +128,7 @@ export function useComputeMapValueAndDate(
statVar: _.cloneDeep(statVar.value),
placeInfo: _.cloneDeep(placeInfo.value),
},
payload: { mapValues, mapDates, unit },
payload: { mapValues, mapDates, unit, denomFacets, numerFacets },
});
}, [
dateCtx.value,
Expand Down
5 changes: 4 additions & 1 deletion static/js/tools/map/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ interface PlaceChartData {
date: string;
value: number;
unit?: string;
denomFacet?: string;
}

/**
Expand All @@ -574,6 +575,7 @@ export function getPlaceChartData(
const facetId = stat.facet;
const statVarSource = metadataMap[facetId].provenanceUrl;
let value = stat.value === undefined ? 0 : stat.value;
let denomFacet = null;
const metadata: DataPointMetadata = {
popDate: "",
popSource: "",
Expand All @@ -588,6 +590,7 @@ export function getPlaceChartData(
return { metadata, sources, date: placeStatDate, value };
}
const popFacetId = placePopData.facet;
denomFacet = popFacetId;
const popSeries = placePopData.series;
const popSource = metadataMap[popFacetId].provenanceUrl;
metadata.popSource = popSource;
Expand All @@ -606,7 +609,7 @@ export function getPlaceChartData(
}
sources.push(statVarSource);
const unit = getUnit(metadataMap[facetId]);
return { metadata, sources, date: placeStatDate, value, unit };
return { metadata, sources, date: placeStatDate, value, unit, denomFacet };
}

/**
Expand Down
6 changes: 6 additions & 0 deletions static/js/tools/scatter/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import React, {
ReactElement,
RefObject,
useEffect,
useMemo,
useRef,
useState,
} from "react";
Expand Down Expand Up @@ -113,6 +114,10 @@ export function Chart(props: ChartPropsType): ReactElement {
xDates.add(point.xDate);
yDates.add(point.yDate);
});
const entities = useMemo(
() => Array.from(new Set(Object.keys(props.points || {}))),
[props.points]
);
const xTitle = getTitle(Array.from(xDates), props.xLabel);
const yTitle = getTitle(Array.from(yDates), props.yLabel);
// Tooltip needs to start off hidden
Expand Down Expand Up @@ -239,6 +244,7 @@ export function Chart(props: ChartPropsType): ReactElement {
</Card>
<ToolChartFooter
chartId="scatter"
entities={entities}
sources={props.sources}
mMethods={null}
hidePerCapitaOption={true}
Expand Down
99 changes: 76 additions & 23 deletions static/js/tools/scatter/chart_loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ type ChartData = {
sources: Set<string>;
xUnit: string;
yUnit: string;
xDenomFacets: Set<string>;
yDenomFacets: Set<string>;
xNumerFacets: Set<string>;
yNumerFacets: Set<string>;
};

export function ChartLoader(): ReactElement {
Expand Down Expand Up @@ -143,43 +147,52 @@ export function ChartLoader(): ReactElement {
const facets: Record<string, StatMetadata> = {};
const statVarToFacets: StatVarFacetMap = {};

if (!cache || !cache.baseFacets || !cache.metadataMap) {
if (!cache || !cache.metadataMap || !chartData) {
return { facets, statVarToFacets };
}

// We build the statVar to facet mapping and the metadata map
for (const statVarDcid in cache.baseFacets) {
// Helper to map plotted facets to their variable and populate metadata
const processFacets = (
statVarDcid: string,
plottedFacets: Set<string>
): void => {
if (!statVarDcid || !plottedFacets || plottedFacets.size === 0) return;

if (!statVarToFacets[statVarDcid]) {
statVarToFacets[statVarDcid] = new Set();
}

// Check if there is a specific facet selected for this variable
const selectedFacetIds = new Set<string>();

if (xVal.statVarDcid === statVarDcid && xVal.metahash) {
selectedFacetIds.add(xVal.metahash);
}
if (yVal.statVarDcid === statVarDcid && yVal.metahash) {
selectedFacetIds.add(yVal.metahash);
}

// If facets have been selected, we add only those to `facets`.
// If none are selected, we add all facets associated with the variable.
const facetIdsToConsider =
selectedFacetIds.size > 0
? Array.from(selectedFacetIds)
: Object.keys(cache.baseFacets[statVarDcid]);

for (const facetId of facetIdsToConsider) {
for (const facetId of Array.from(plottedFacets)) {
statVarToFacets[statVarDcid].add(facetId);
if (cache.metadataMap[facetId]) {
facets[facetId] = cache.metadataMap[facetId];
}
}
};

//Add in numerators that appear in the chart
processFacets(xVal.statVarDcid, chartData.xNumerFacets);
processFacets(yVal.statVarDcid, chartData.yNumerFacets);

//Add in denominators that appear in the chart
if (xVal.perCapita && xVal.denom) {
processFacets(xVal.denom, chartData.xDenomFacets);
}
if (yVal.perCapita && yVal.denom) {
processFacets(yVal.denom, chartData.yDenomFacets);
}

return { facets, statVarToFacets };
}, [cache, xVal.statVarDcid, xVal.metahash, yVal.statVarDcid, yVal.metahash]);
}, [
cache,
chartData,
xVal.statVarDcid,
xVal.perCapita,
xVal.denom,
yVal.statVarDcid,
yVal.perCapita,
yVal.denom,
]);

/**
* Callback function for building observation specifications.
Expand Down Expand Up @@ -337,6 +350,7 @@ export function ChartLoader(): ReactElement {
/>
<ChartEmbed
ref={embedModalElement}
entities={Object.keys(chartData.points)}
facets={facets}
statVarSpecs={currentStatVarSpecs}
statVarToFacets={statVarToFacets}
Expand Down Expand Up @@ -431,6 +445,7 @@ async function loadData(
const metadataMap = {
...(statResponse.facets || {}),
...(statAllResponse.facets || {}),
...(populationData.facets || {}),
};

const baseFacets: FacetResponse = {};
Expand Down Expand Up @@ -579,6 +594,11 @@ function getChartData(
const sources: Set<string> = new Set();
let xUnit = "";
let yUnit = "";
const xDenomFacets: Set<string> = new Set();
const yDenomFacets: Set<string> = new Set();
const xNumerFacets: Set<string> = new Set();
const yNumerFacets: Set<string> = new Set();

for (const namedPlace of place.enclosedPlaces) {
const xDenom = x.perCapita ? x.denom : null;
const yDenom = y.perCapita ? y.denom : null;
Expand All @@ -600,11 +620,44 @@ function getChartData(
sources.add(source);
}
});

// Compile the used numerator and denominator facets
if (placeChartData.xDenomFacet) {
xDenomFacets.add(placeChartData.xDenomFacet);
}
if (placeChartData.yDenomFacet) {
yDenomFacets.add(placeChartData.yDenomFacet);
}

if (
xStatData &&
xStatData[namedPlace.dcid] &&
xStatData[namedPlace.dcid].facet
) {
xNumerFacets.add(xStatData[namedPlace.dcid].facet);
}
if (
yStatData &&
yStatData[namedPlace.dcid] &&
yStatData[namedPlace.dcid].facet
) {
yNumerFacets.add(yStatData[namedPlace.dcid].facet);
}

points[namedPlace.dcid] = placeChartData.point;
xUnit = xUnit || placeChartData.xUnit;
yUnit = yUnit || placeChartData.yUnit;
}
return { points, sources, xUnit, yUnit };
return {
points,
sources,
xUnit,
yUnit,
xDenomFacets,
yDenomFacets,
xNumerFacets,
yNumerFacets,
};
}

function getFacetInfo(
Expand Down
Loading
Loading