Skip to content

Commit

Permalink
Enable state-level enhanced CPS runs (#2226)
Browse files Browse the repository at this point in the history
* feat: Update DatasetSelector, RegionSelector, and PolicyRightSidebar to enable dataset query param

* fix: Remove testing code

* feat: Ensure that sim reruns when dataset changes

* fix: Re-add metadata filter for enhanced_us to PolicyRightSidebar

* fix: Display text on bottom bar based on dataset

* feat: Update Reproduce in Python for datasets

* feat: Update cliff impact display to use dataset

* feat: Integrate dataset into user policy display

* fix: Fix failing tests

* chore: Lint
  • Loading branch information
anth-volk authored Dec 3, 2024
1 parent 59e4c74 commit 32df95a
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 92 deletions.
14 changes: 14 additions & 0 deletions src/__tests__/data/reformDefinitionCode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe("Test getReproducibilityCodeBlock", () => {
reformPolicyUS,
"us",
2024,
null,
householdUS,
);

Expand Down Expand Up @@ -245,6 +246,19 @@ describe("Test getImplementationCode", () => {
expect(output).toBeInstanceOf(Array);
expect(output).toContain("baseline = Microsimulation(reform=baseline)");
});
test("If dataset provided, return lines with dataset", () => {
const output = getImplementationCode(
"policy",
"us",
2024,
baselinePolicyUS,
"enhanced_cps",
);
expect(output).toBeInstanceOf(Array);
expect(output).toContain(
"baseline = Microsimulation(dataset='enhanced_cps_2024')",
);
});
});

describe("Test sanitizeStringToPython", () => {
Expand Down
29 changes: 2 additions & 27 deletions src/__tests__/pages/policy/PolicyRightSidebar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,32 +175,6 @@ describe("Enhanced CPS selector", () => {
"ant-switch-disabled",
);
});
test("Should not be enabled when region is a state", async () => {
const testSearchParams = {
focus: "gov",
region: "ar",
};

useSearchParams.mockImplementation(() => {
return [new URLSearchParams(testSearchParams), jest.fn()];
});

// Declare props
const props = {
metadata: {
...metadataUS,
countryId: "us",
},
policy: standardPolicyUS,
defaultOpen: true,
};

const { getByTestId } = render(<PolicyRightSidebar {...props} />);

expect(getByTestId("enhanced_cps_switch").classList).toContain(
"ant-switch-disabled",
);
});
test("Should change region when selected", () => {
const testSearchParams = {
focus: "gov",
Expand All @@ -209,7 +183,8 @@ describe("Enhanced CPS selector", () => {

const expectedSearchParams = {
focus: "gov",
region: "enhanced_us",
region: "us",
dataset: "enhanced_cps",
};

const mockSetSearchParams = jest.fn();
Expand Down
9 changes: 5 additions & 4 deletions src/data/countries.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ export const STATUS_TEXT_COLORS = {
Pending: colors.BLACK,
};

// Map region entries to default datasets;
// at the moment, this only applies to the
// "enhanced_us" region selection
// Map dataset keywords to their equivalents
// in the actual US package; at the moment,
// this only applies to the "enhanced_cps"
// dataset selection
export const DEFAULT_DATASETS = {
enhanced_us: "enhanced_cps_2024",
enhanced_cps: "enhanced_cps_2024",
};

const DEFAULT_US_HOUSEHOLD = {
Expand Down
33 changes: 24 additions & 9 deletions src/data/reformDefinitionCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function getReproducibilityCodeBlock(
policy,
region,
year,
dataset = null,
householdInput = null,
earningVariation = null,
) {
Expand All @@ -27,7 +28,7 @@ export function getReproducibilityCodeBlock(
householdInput,
earningVariation,
),
...getImplementationCode(type, region, year, policy),
...getImplementationCode(type, region, year, policy, dataset),
];
}

Expand Down Expand Up @@ -156,37 +157,51 @@ export function getSituationCode(
return lines;
}

export function getImplementationCode(type, region, timePeriod, policy) {
export function getImplementationCode(
type,
region,
timePeriod,
policy,
dataset,
) {
if (type !== "policy") {
return [];
}

const hasBaseline = Object.keys(policy?.baseline?.data).length > 0;
const hasReform = Object.keys(policy?.reform?.data).length > 0;

// Check if the region has a dataset specified
const hasDatasetSpecified = Object.keys(DEFAULT_DATASETS).includes(region);
const dataset = hasDatasetSpecified ? DEFAULT_DATASETS[region] : "";
// Check if the region has a dataset specified; enhanced_us is legacy implemntation
// whereby enhanced_us region correlated with enhanced_cps dataset
const hasDatasetSpecified =
Object.keys(DEFAULT_DATASETS).includes(dataset) || region === "enhanced_us";

let formattedDataset = null;
if (region === "enhanced_us") {
formattedDataset = "enhanced_cps_2024";
} else if (hasDatasetSpecified) {
formattedDataset = DEFAULT_DATASETS[dataset];
}

return [
"",
"",
`baseline = Microsimulation(${
hasDatasetSpecified && hasBaseline
? `reform=baseline, dataset='${dataset}'`
? `reform=baseline, dataset='${formattedDataset}'`
: hasBaseline
? `reform=baseline`
: hasDatasetSpecified
? `dataset='${dataset}'`
? `dataset='${formattedDataset}'`
: ""
})`,
`reformed = Microsimulation(${
hasDatasetSpecified && hasReform
? `reform=reform, dataset='${dataset}'`
? `reform=reform, dataset='${formattedDataset}'`
: hasReform
? `reform=reform`
: hasDatasetSpecified
? `dataset='${dataset}'`
? `dataset='${formattedDataset}'`
: ""
})`,
`baseline_income = baseline.calculate("household_net_income", period=${timePeriod || defaultYear})`,
Expand Down
20 changes: 18 additions & 2 deletions src/pages/UserProfilePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,11 +443,17 @@ function UserProfileSection(props) {
function PolicySimulationCard(props) {
const { metadata, userPolicy, keyValue } = props;

console.log(userPolicy);

const CURRENT_API_VERSION = metadata?.version;
const geography =
metadata.economy_options.region.filter(
(region) => region.name === userPolicy.geography,
)[0]?.label || "Unknown";
const datasetName =
metadata.economy_options.datasets.filter(
(dataset) => dataset.name === userPolicy.dataset,
)[0]?.label || "Unknown";

const apiVersion = userPolicy.api_version;
const dateAdded = userPolicy.added_date;
Expand Down Expand Up @@ -480,7 +486,12 @@ function PolicySimulationCard(props) {
return (
<Link
key={keyValue}
to={`/${userPolicy.country_id}/policy?focus=policyOutput.policyBreakdown&reform=${userPolicy.reform_id}&baseline=${userPolicy.baseline_id}&timePeriod=${userPolicy.year}&region=${userPolicy.geography}`}
to={
`/${userPolicy.country_id}/policy?focus=policyOutput.policyBreakdown` +
`&reform=${userPolicy.reform_id}&baseline=${userPolicy.baseline_id}` +
`&timePeriod=${userPolicy.year}&region=${userPolicy.geography}` +
`${userPolicy.dataset ? `&dataset=${userPolicy.dataset}` : ""}`
}
style={{ height: "100%" }}
>
<Card
Expand Down Expand Up @@ -516,7 +527,12 @@ function PolicySimulationCard(props) {
Simulated in{" "}
<span style={{ fontWeight: 500 }}>{userPolicy.year}</span> over{" "}
<span style={{ fontWeight: 500 }}>{geography}</span> against{" "}
<span style={{ fontWeight: 500 }}>{userPolicy.baseline_label}</span>.
<span style={{ fontWeight: 500 }}>{userPolicy.baseline_label}</span>
{userPolicy.dataset ? (
<span style={{ fontWeight: 500 }}> ({datasetName})</span>
) : (
"."
)}
</p>
<p>
<span style={{ fontWeight: 500 }}>
Expand Down
2 changes: 2 additions & 0 deletions src/pages/household/output/HouseholdReproducibility.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function HouseholdReproducibility(props) {
const [earningVariation, setEarningVariation] = useState(false);
const [searchParams] = useSearchParams();
const region = searchParams.get("region");
const dataset = searchParams.get("dataset");
const mobile = useMobile();

let lines = getReproducibilityCodeBlock(
Expand All @@ -20,6 +21,7 @@ export default function HouseholdReproducibility(props) {
policy,
region,
year,
dataset,
householdInput,
earningVariation,
);
Expand Down
93 changes: 48 additions & 45 deletions src/pages/policy/PolicyRightSidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,9 @@ function RegionSelector(props) {
return { value: region.name, label: region.label };
});

// This is a temporary solution that will need to be superseded by
// an improved back end design; removing this value allows
// DatasetSelector to handle choosing between enhanced CPS data and
// standard US data
// The below allows backward compatibility with a past design where enhanced_cps
// was also a region value
options = options.filter((option) => option.value !== "enhanced_us");

// These lines are also a temporary solution; if user accesses the component
// with the enhanced_us region via URL, the component should instead display
// the US
let inputRegion = searchParams.get("region");
if (inputRegion === "enhanced_us") {
inputRegion = "us";
Expand Down Expand Up @@ -415,62 +409,65 @@ function FullLiteToggle() {
}

/**
* A (hopefully temporary) component meant to abstract away the fact
* that the US enhanced CPS data is defined as a region within the US
* country package; this displays the enhanced CPS as a dataset on the
* right-hand policy panel
* This displays the enhanced CPS as a dataset on the right-hand policy panel
* @param {Object} props
* @param {String} presentRegion The region, taken from the searchParams
* @param {String} presentDataset The dataset, taken from the searchParams
* @param {Number|String} timePeriod The year the simulation should run over
* @returns {import("react").ReactElement}
*/
function DatasetSelector(props) {
const { presentRegion, timePeriod } = props;
const { presentDataset, timePeriod } = props;
const [isChecked, setIsChecked] = useState(confirmIsChecked(presentDataset));
const [searchParams, setSearchParams] = useSearchParams();
const displayCategory = useDisplayCategory();

// Determine whether slider should be enabled or disabled
function shouldEnableSlider(presentRegion, timePeriod) {
// Define the regions the slider should be enabled
const showRegions = ["enhanced_us", "us", null];
function confirmIsChecked(presentDataset) {
// Define presentDataset value that activates check
const checkValue = "enhanced_cps";
if (presentDataset === checkValue) {
return true;
}
return false;
}

// Define the times the slider should NOT be enabled
const dontShowTimes = ["2021"];
// Determine whether slider should be enabled or disabled
function shouldEnableSlider(timePeriod) {
// Define earliest year slider should be shown for
const sliderStartYear = 2024;

// Return whether or not slider should be enabled
if (
showRegions.includes(presentRegion) &&
!dontShowTimes.includes(String(timePeriod))
) {
// Null timePeriod reflects no URL param setting yet -
// this is actually default behavior
if (!timePeriod || timePeriod >= sliderStartYear) {
return true;
}

return false;
}

/**
* Switch change handler
* @param {Boolean} isChecked Whether or not the switch is "checked";
* note that the event is not passed to the handler by default
* @returns {undefined|null} Returns null as a safety check in cases where
* switch shouldn't be active in the first place
*/
function handleChange(isChecked) {
// Define our desired states; item 0 corresponds to
// "true" and 1 to "false", since bools can't be used as keys
const outputStates = ["enhanced_us", "us"];

function handleChange() {
// First, safety check - if the button isn't even
// supposed to be shown, do nothing
if (!shouldEnableSlider(presentRegion, timePeriod)) {
if (!shouldEnableSlider(timePeriod)) {
return;
}

// Duplicate the existing search params
let newSearch = copySearchParams(searchParams);

// Set params accordingly
newSearch.set("region", isChecked ? outputStates[0] : outputStates[1]);
if (isChecked) {
newSearch.delete("dataset");
// Allows for backwards compatibility with a past design
// where enhanced_cps was also a region value
if (searchParams.get("region") === "enhanced_us") {
newSearch.set("region", "us");
}
setIsChecked(false);
} else {
newSearch.set("dataset", "enhanced_cps");
setIsChecked(true);
}
setSearchParams(newSearch);
}

Expand All @@ -488,17 +485,15 @@ function DatasetSelector(props) {
data-testid="enhanced_cps_switch"
size={displayCategory !== "mobile" && "small"}
onChange={handleChange}
disabled={!shouldEnableSlider(presentRegion, timePeriod)}
checked={presentRegion === "enhanced_us" ? true : false}
disabled={!shouldEnableSlider(timePeriod)}
checked={presentDataset === "enhanced_cps" ? true : false}
/>
<p
style={{
margin: 0,
fontSize: displayCategory !== "mobile" && "0.95em",
color:
!shouldEnableSlider(presentRegion, timePeriod) && "rgba(0,0,0,0.5)",
cursor:
!shouldEnableSlider(presentRegion, timePeriod) && "not-allowed",
color: !shouldEnableSlider(timePeriod) && "rgba(0,0,0,0.5)",
cursor: !shouldEnableSlider(timePeriod) && "not-allowed",
}}
>
Use Enhanced CPS (beta)
Expand Down Expand Up @@ -804,6 +799,14 @@ export default function PolicyRightSidebar(props) {
const focus = searchParams.get("focus") || "";
const stateAbbreviation = focus.split(".")[2];
const hasHousehold = searchParams.get("household") !== null;

let dataset = searchParams.get("dataset");
// This allows backward compatibility with a past
// design where enhanced_cps was also a region value
if (region === "enhanced_us" && !dataset) {
dataset = "enhanced_cps";
}

const options = metadata.economy_options.region.map((stateAbbreviation) => {
return { value: stateAbbreviation.name, label: stateAbbreviation.label };
});
Expand Down Expand Up @@ -1100,7 +1103,7 @@ export default function PolicyRightSidebar(props) {
</div>
{metadata.countryId === "us" && (
<DatasetSelector
presentRegion={region}
presentDataset={dataset}
timePeriod={timePeriod}
/>
)}
Expand Down
Loading

0 comments on commit 32df95a

Please sign in to comment.