Skip to content

Commit

Permalink
Merge pull request #1013 from PolicyEngine/MaxGhenis/issue997
Browse files Browse the repository at this point in the history
Add a third `% difference` option to household net income chart
  • Loading branch information
MaxGhenis authored Dec 26, 2023
2 parents d396fb1 + dbbf783 commit a2a9050
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 67 deletions.
1 change: 1 addition & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
22 changes: 11 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"fix": "eslint --fix --ext js,jsx . && prettier -w .",
"fix": "prettier -w .",
"lint": "eslint --ext js,jsx . && prettier -c ."
},
"eslintConfig": {
Expand Down Expand Up @@ -87,7 +87,7 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"eslint": "^8.55.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-prettier": "^5.0.0",
Expand All @@ -97,6 +97,6 @@
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.4.3",
"lint-staged": "^15.2.0",
"prettier": "^3.1.0"
"prettier": "^3.1.1"
}
}
4 changes: 2 additions & 2 deletions src/__tests__/BaselineAndReformChart.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ describe("Test Render Output", () => {
});
render(<BaselineAndReformChart metadata={metadata} variable={"abc"} />);

fireEvent.click(screen.getByRole("radio", { name: /difference/i }));
fireEvent.click(screen.getByRole("radio", { name: /Absolute change/i }));

const diffButton = screen.getByRole("radio", { name: /difference/i });
const diffButton = screen.getByRole("radio", { name: /Absolute change/i });

expect(diffButton).toHaveProperty("checked", true);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,58 +70,71 @@ export default function BaselineAndReformChart(props) {
householdBaseline,
metadata,
);

function BaselineAndReformChartWithToggle() {
const [showDelta, setShowDelta] = useState(true);
const [viewMode, setViewMode] = useState("absoluteChange");

const options = [
{
label: "Baseline and reform",
value: false,
value: "baselineAndReform",
},
{
label: "Absolute change",
value: "absoluteChange",
},
{
label: "Difference",
value: true,
label: "Relative change",
value: "relativeChange",
},
];
const onDelta = ({ target: { value } }) => {
setShowDelta(value);

const onViewModeChange = ({ target: { value } }) => {
setViewMode(value);
};

const toggle = (
<div style={{ display: "flex", justifyContent: "center" }}>
<Radio.Group
options={options}
onChange={onDelta}
value={showDelta}
onChange={onViewModeChange}
value={viewMode}
buttonStyle="solid"
/>
</div>
);
const plot = showDelta ? (
<BaselineReformDeltaPlot
earningsArray={earningsArray}
baselineArray={baselineArray}
reformArray={reformArray}
currentEarnings={currentEarnings}
currentValue={currentValue}
baselineValue={baselineValue}
variableLabel={variableLabel}
metadata={metadata}
variable={variable}
/>
) : (
<BaselineAndReformTogetherPlot
earningsArray={earningsArray}
baselineArray={baselineArray}
reformArray={reformArray}
currentEarnings={currentEarnings}
currentValue={currentValue}
baselineValue={baselineValue}
variableLabel={variableLabel}
metadata={metadata}
variable={variable}
policy={policy}
/>
);

const getPlotComponent = (viewMode, sharedProps) => {
switch (viewMode) {
case "baselineAndReform":
return <BaselineAndReformTogetherPlot {...sharedProps} />;
case "absoluteChange":
return (
<BaselineReformDeltaPlot {...sharedProps} showPercentage={false} />
);
case "relativeChange":
return (
<BaselineReformDeltaPlot {...sharedProps} showPercentage={true} />
);
default:
return <div>Unknown view mode</div>;
}
};

let sharedProps = {
earningsArray,
baselineArray,
reformArray,
currentEarnings,
currentValue,
baselineValue,
variableLabel,
metadata,
variable,
policy,
};

let plot = getPlotComponent(viewMode, sharedProps);

return (
<>
{toggle}
Expand Down Expand Up @@ -375,35 +388,54 @@ function BaselineReformDeltaPlot(props) {
metadata,
variable,
useHoverCard = false,
showPercentage,
} = props;
// Calculate delta values
const deltaArray = reformArray.map(
(value, index) => value - baselineArray[index],
);
// Calculate percentage differences, avoiding divide by zero
const percentageDeltaArray = reformArray.map((value, index) => {
const baselineValue = baselineArray[index];
return baselineValue !== 0 ? (value - baselineValue) / baselineValue : null;
});
const currentDelta = currentValue - baselineValue;
const currentPercentageDelta = currentDelta / baselineValue;
let data = [
{
x: earningsArray,
y: deltaArray,
y: showPercentage ? percentageDeltaArray : deltaArray,
type: "line",
name: `Change in ${variableLabel}`,
line: {
color: style.colors.BLUE,
},
...(useHoverCard
? {
hoverinfo: "none",
}
: {
hovertemplate:
`<b>Change in ${variableLabel}</b><br><br>` +
`If you earn %{x}, your change in<br>` +
`${variableLabel} will be %{y}.` +
`<extra></extra>`,
}),
hoverinfo: "text",
text: earningsArray.map((earnings, index) => {
const deltaValue = showPercentage
? percentageDeltaArray[index]
: deltaArray[index];
const formattedEarnings = convertToCurrencyString(
metadata.currency,
earnings,
);

if (deltaValue === 0) {
return `If you earn ${formattedEarnings}, your ${variableLabel} will have no change.`;
} else {
const direction = deltaValue > 0 ? "rise" : "fall";
const absoluteDeltaValue = Math.abs(deltaValue);
const formattedDelta = showPercentage
? `${(absoluteDeltaValue * 100).toFixed(1)}%`
: convertToCurrencyString(metadata.currency, absoluteDeltaValue);
return `If you earn ${formattedEarnings}, your ${variableLabel} will ${direction} by ${formattedDelta}.`;
}
}),
},
{
x: [currentEarnings],
y: [currentDelta],
// Apply delta or % delta based on selection.
y: showPercentage ? [currentPercentageDelta] : [currentDelta],
type: "scatter",
mode: "markers",
name: `Your current change in ${variableLabel}`,
Expand Down Expand Up @@ -440,10 +472,15 @@ function BaselineReformDeltaPlot(props) {
uirevision: metadata.variables.employment_income.unit,
},
yaxis: {
title: `Change in ${variableLabel}`,
title: showPercentage
? `Relative change in ${variableLabel}`
: `Absolute change in ${variableLabel}`,
tickformat: showPercentage ? ".0%" : ".2s",
...getPlotlyAxisFormat(
metadata.variables[variable].unit,
deltaArray.concat(currentDelta),
showPercentage ? "%" : metadata.variables[variable].unit,
showPercentage
? percentageDeltaArray
: deltaArray.concat(currentDelta),
),
uirevision: metadata.variables[variable].unit,
},
Expand Down

0 comments on commit a2a9050

Please sign in to comment.