Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/add-statefip-support.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add statefip (FIPS code) input support, matching TAXSIM-35 behavior.
2 changes: 1 addition & 1 deletion dashboard/src/components/CsvRunner.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const SAMPLE_DATASETS = [
const fmt = (n) => Number(n).toLocaleString();

const KNOWN_COLUMNS = new Set([
'taxsimid', 'year', 'state', 'mstat', 'page', 'sage',
'taxsimid', 'year', 'state', 'statefip', 'mstat', 'page', 'sage',
'dependent_exemption', 'depx', 'pwages', 'swages',
'psemp', 'ssemp', 'dividends', 'intrec', 'stcg', 'ltcg',
'otherprop', 'nonprop', 'pensions', 'gssi',
Expand Down
1 change: 1 addition & 0 deletions policyengine_taxsim/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"taxsimid",
"year",
"state",
"statefip",
"mstat",
"page",
"sage",
Expand Down
3 changes: 3 additions & 0 deletions policyengine_taxsim/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,6 @@ def get_ordinal(n):
50: 55, # Wisconsin
51: 56, # Wyoming
}

# Reverse mapping: FIPS → SOI (for statefip input support)
FIPS_TO_SOI_MAP = {fips: soi for soi, fips in SOI_TO_FIPS_MAP.items()}
13 changes: 13 additions & 0 deletions policyengine_taxsim/runners/base_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

try:
from ..core.io import write_output
from ..core.utils import FIPS_TO_SOI_MAP
except ImportError:
from policyengine_taxsim.core.io import write_output
from policyengine_taxsim.core.utils import FIPS_TO_SOI_MAP


class BaseTaxRunner(ABC):
Expand Down Expand Up @@ -39,6 +41,17 @@ def _validate_input(self):
if "year" not in self.input_df.columns:
raise ValueError("Input data must contain a 'year' column")

# Convert statefip (FIPS) to state (SOI) per row.
# Matches TAXSIM-35 behavior: for each record, if state==0
# and statefip is set, convert FIPS→SOI.
if "statefip" in self.input_df.columns:
if "state" not in self.input_df.columns:
self.input_df["state"] = 0
fips_vals = self.input_df["statefip"].astype(int)
soi_from_fips = fips_vals.map(FIPS_TO_SOI_MAP).fillna(0).astype(int)
use_fips = (self.input_df["state"] == 0) & (fips_vals > 0)
self.input_df.loc[use_fips, "state"] = soi_from_fips[use_fips]

# Auto-assign taxsimid if not present
if "taxsimid" not in self.input_df.columns:
# Assign sequential IDs starting from 1
Expand Down
Loading