diff --git a/app/src/components/ChartHeader.jsx b/app/src/components/ChartHeader.jsx
index 74fa7dcb..dfe788ba 100644
--- a/app/src/components/ChartHeader.jsx
+++ b/app/src/components/ChartHeader.jsx
@@ -58,6 +58,8 @@ const ChartHeader = ({
setShowLegend,
showOtherGroundTruthSeasons,
setShowOtherGroundTruthSeasons,
+ showHistogram,
+ setShowHistogram,
} = useView();
const about = useContext(ChartAboutContext);
@@ -148,6 +150,10 @@ const ChartHeader = ({
setShowOtherGroundTruthSeasons={setShowOtherGroundTruthSeasons}
disableOtherGroundTruthSeasons={isSurveillance}
showIntervals={!isSurveillance}
+ showHistogram={showHistogram}
+ setShowHistogram={
+ viewType === "flu_forecasts" ? setShowHistogram : null
+ }
/>
diff --git a/app/src/components/ViewSelector.jsx b/app/src/components/ViewSelector.jsx
index aa12e721..d67fb510 100644
--- a/app/src/components/ViewSelector.jsx
+++ b/app/src/components/ViewSelector.jsx
@@ -21,10 +21,6 @@ const ViewSelector = ({ showActive = true, onNavigate }) => {
label: "Standard view",
value: DATASETS.flu.defaultView,
},
- {
- label: "Detailed view",
- value: "fludetailed",
- },
{
label: "Peak forecasts",
value: "flu_peak",
@@ -63,7 +59,7 @@ const ViewSelector = ({ showActive = true, onNavigate }) => {
];
const fluViewValues = new Set(fluViews.map((view) => view.value));
- const isFluActive = fluViewValues.has(viewType);
+ const isFluActive = fluViewValues.has(viewType) || viewType === "fludetailed";
useEffect(() => {
if (isFluActive) {
diff --git a/app/src/components/controls/ForecastChartControls.jsx b/app/src/components/controls/ForecastChartControls.jsx
index 2b3297ef..adb2d03f 100644
--- a/app/src/components/controls/ForecastChartControls.jsx
+++ b/app/src/components/controls/ForecastChartControls.jsx
@@ -32,6 +32,8 @@ const ForecastChartControls = ({
disableOtherGroundTruthSeasons = false,
showIntervals = true,
intervalOptions = INTERVAL_OPTIONS,
+ showHistogram = false,
+ setShowHistogram = null,
}) => {
const selectedIntervals = intervalOptions
.filter((option) => intervalVisibility?.[option.value])
@@ -92,6 +94,21 @@ const ForecastChartControls = ({
offLabel="Off"
/>
+ {typeof setShowHistogram === "function" && (
+
+
+ Histogram
+
+ setShowHistogram(event.currentTarget.checked)}
+ size="sm"
+ onLabel="On"
+ offLabel="Off"
+ />
+
+ )}
{typeof setShowOtherGroundTruthSeasons === "function" && (
{
@@ -90,14 +94,14 @@ const FluView = ({
]);
const extraTraces = useMemo(() => {
- if (viewType !== "fludetailed") return [];
+ if (!histogramVisible) return [];
return rateChangeData.map((trace) => ({
...trace,
orientation: "h",
xaxis: "x2",
yaxis: "y2",
}));
- }, [rateChangeData, viewType]);
+ }, [rateChangeData, histogramVisible]);
const activeModels = useMemo(() => {
const activeModelSet = new Set();
@@ -127,7 +131,7 @@ const FluView = ({
}
}
- if (viewType === "fludetailed") {
+ if (histogramVisible) {
const rateChangeSet = forecastsForDate["wk flu hosp rate change"];
if (rateChangeSet) {
Object.keys(rateChangeSet).forEach((model) =>
@@ -138,7 +142,7 @@ const FluView = ({
});
return activeModelSet;
- }, [forecasts, selectedDates, selectedTarget, viewType]);
+ }, [forecasts, selectedDates, selectedTarget, viewType, histogramVisible]);
const forecastTarget =
viewType === "flu" || viewType === "flu_forecasts"
@@ -154,7 +158,7 @@ const FluView = ({
(baseLayout) => {
const baseXAxis = {
...baseLayout.xaxis,
- domain: viewType === "fludetailed" ? [0, 0.8] : baseLayout.xaxis.domain,
+ domain: histogramVisible ? [0, 0.8] : baseLayout.xaxis.domain,
};
const nextLayout = {
@@ -163,7 +167,7 @@ const FluView = ({
xaxis: baseXAxis,
};
- if (viewType !== "fludetailed") {
+ if (!histogramVisible) {
return nextLayout;
}
@@ -207,7 +211,7 @@ const FluView = ({
},
};
},
- [viewType, lastSelectedDate, colorScheme],
+ [histogramVisible, lastSelectedDate, colorScheme],
);
if (viewType === "flu_peak") {
diff --git a/app/src/contexts/ViewContext.jsx b/app/src/contexts/ViewContext.jsx
index 81b976e2..275a272b 100644
--- a/app/src/contexts/ViewContext.jsx
+++ b/app/src/contexts/ViewContext.jsx
@@ -401,6 +401,9 @@ export const ViewProvider = ({ children }) => {
);
const [showOtherGroundTruthSeasons, setShowOtherGroundTruthSeasons] =
useState(() => urlManager.getAdvancedParams().showOtherGroundTruthSeasons);
+ const [showHistogram, setShowHistogram] = useState(
+ () => urlManager.getAdvancedParams().showHistogram,
+ );
const {
data,
@@ -875,6 +878,7 @@ export const ViewProvider = ({ children }) => {
intervalVisibility: urlIntervals,
showLegend: urlLegend,
showOtherGroundTruthSeasons: urlShowOtherGroundTruthSeasons,
+ showHistogram: urlShowHistogram,
} = urlManager.getAdvancedParams();
if (isSurveillanceView && urlShowOtherGroundTruthSeasons) {
@@ -899,6 +903,9 @@ export const ViewProvider = ({ children }) => {
if (urlShowOtherGroundTruthSeasons !== showOtherGroundTruthSeasons) {
setShowOtherGroundTruthSeasons(urlShowOtherGroundTruthSeasons);
}
+ if (urlShowHistogram !== showHistogram) {
+ setShowHistogram(urlShowHistogram);
+ }
}, [
searchParams,
location.pathname,
@@ -909,6 +916,7 @@ export const ViewProvider = ({ children }) => {
intervalVisibility,
showLegend,
showOtherGroundTruthSeasons,
+ showHistogram,
]);
const setChartScaleWithUrl = useCallback(
@@ -956,6 +964,16 @@ export const ViewProvider = ({ children }) => {
[urlManager, isForecastPage],
);
+ const setShowHistogramWithUrl = useCallback(
+ (nextValue) => {
+ setShowHistogram(nextValue);
+ if (isForecastPage) {
+ urlManager.updateAdvancedParams({ showHistogram: nextValue });
+ }
+ },
+ [urlManager, isForecastPage],
+ );
+
const contextValue = {
selectedLocation,
locationMessage,
@@ -1018,6 +1036,8 @@ export const ViewProvider = ({ children }) => {
setShowLegend: setShowLegendWithUrl,
showOtherGroundTruthSeasons,
setShowOtherGroundTruthSeasons: setShowOtherGroundTruthSeasonsWithUrl,
+ showHistogram,
+ setShowHistogram: setShowHistogramWithUrl,
};
return (
diff --git a/app/src/utils/urlManager.js b/app/src/utils/urlManager.js
index 688d16b3..2a21e48a 100644
--- a/app/src/utils/urlManager.js
+++ b/app/src/utils/urlManager.js
@@ -72,6 +72,7 @@ export class URLParameterManager {
const intervalsParam = this.searchParams.get("intervals");
const legendParam = this.searchParams.get("legend");
const otherGtParam = this.searchParams.get("other_gt");
+ const histogramParam = this.searchParams.get("histogram");
const chartScale = normalizeChartScale(scaleParam || DEFAULT_CHART_SCALE);
let intervalVisibility = { ...DEFAULT_INTERVAL_VISIBILITY };
@@ -110,6 +111,7 @@ export class URLParameterManager {
intervalVisibility,
showLegend,
showOtherGroundTruthSeasons,
+ showHistogram: histogramParam === "1" || histogramParam === "true",
};
}
@@ -142,6 +144,7 @@ export class URLParameterManager {
intervalVisibility,
showLegend,
showOtherGroundTruthSeasons,
+ showHistogram,
}) {
const updatedParams = new URLSearchParams(this.searchParams);
@@ -182,6 +185,14 @@ export class URLParameterManager {
}
}
+ if (typeof showHistogram === "boolean") {
+ if (showHistogram) {
+ updatedParams.set("histogram", "1");
+ } else {
+ updatedParams.delete("histogram");
+ }
+ }
+
if (updatedParams.toString() !== this.searchParams.toString()) {
this.setSearchParams(updatedParams, { replace: true });
}