Commit
·
64cb2a0
1
Parent(s):
761e2b2
Add CRA filter
Browse files- app.py +27 -13
- modules/get_resolutions.py +53 -16
app.py
CHANGED
|
@@ -15,7 +15,8 @@ from modules import (
|
|
| 15 |
WINDOW_OPEN_DATE,
|
| 16 |
GET_SIGNIFICANT,
|
| 17 |
METADATA,
|
| 18 |
-
AGENCIES,
|
|
|
|
| 19 |
groupby_agency,
|
| 20 |
groupby_date,
|
| 21 |
add_week_info_to_data,
|
|
@@ -24,7 +25,7 @@ from modules import (
|
|
| 24 |
plot_tf,
|
| 25 |
plot_NA,
|
| 26 |
plot_NA,
|
| 27 |
-
|
| 28 |
)
|
| 29 |
|
| 30 |
from shiny import reactive
|
|
@@ -65,7 +66,7 @@ sidebar_logo = ui.HTML(
|
|
| 65 |
FOOTER = f"""
|
| 66 |
-----
|
| 67 |
|
| 68 |
-
©
|
| 69 |
"""
|
| 70 |
|
| 71 |
|
|
@@ -94,6 +95,10 @@ with ui.sidebar(open={"desktop": "open", "mobile": "closed"}, fg="#033C5A"):
|
|
| 94 |
ui.input_select("menu_significant", "Select rule significance", choices=["all", "3f1-significant", "other-significant"], selected="all", multiple=True, size=3)
|
| 95 |
"Rule significance as defined in Executive Order 12866, as amended by Executive Order 14094."
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
with ui.tooltip(placement="right", id="agency_tooltip"):
|
| 98 |
ui.input_select("menu_agency", "Select agencies", choices=["all"] + AGENCIES, selected=["all"], multiple=True, size=6)
|
| 99 |
"Select one or more parent-level agencies."
|
|
@@ -150,7 +155,7 @@ with ui.navset_card_underline(title=""):
|
|
| 150 |
"other_significant",
|
| 151 |
"CRA Target",
|
| 152 |
"CRA Stage",
|
| 153 |
-
"RD
|
| 154 |
]
|
| 155 |
return render.DataGrid(df.loc[:, [c for c in cols if c in df.columns]], width="100%")
|
| 156 |
|
|
@@ -199,7 +204,7 @@ with ui.navset_card_underline(title=""):
|
|
| 199 |
"other_significant",
|
| 200 |
"CRA Target",
|
| 201 |
"CRA Stage",
|
| 202 |
-
"RD
|
| 203 |
]
|
| 204 |
return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
|
| 205 |
|
|
@@ -232,7 +237,7 @@ with ui.navset_card_underline(title=""):
|
|
| 232 |
"other_significant",
|
| 233 |
"CRA Target",
|
| 234 |
"CRA Stage",
|
| 235 |
-
"RD
|
| 236 |
]
|
| 237 |
return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
|
| 238 |
|
|
@@ -265,11 +270,11 @@ with ui.accordion(open=False):
|
|
| 265 |
"other_significant",
|
| 266 |
"CRA Target",
|
| 267 |
"CRA Stage",
|
| 268 |
-
"RD
|
| 269 |
"RD Link"
|
| 270 |
)
|
| 271 |
):
|
| 272 |
-
filt_df =
|
| 273 |
filt_df.loc[:, "agencies"] = filt_df.loc[:, "agency_slugs"].apply(lambda x: "; ".join(x))
|
| 274 |
filt_df.loc[:, "parent_agencies"] = filt_df.loc[:, "parent_slug"].apply(lambda x: "; ".join(x))
|
| 275 |
filt_df.loc[:, "subagencies"] = filt_df.loc[:, "subagency_slug"].apply(lambda x: "; ".join(x))
|
|
@@ -283,10 +288,10 @@ with ui.accordion(open=False):
|
|
| 283 |
|
| 284 |
ui.markdown(
|
| 285 |
f"""
|
| 286 |
-
|
|
|
|
| 287 |
Rules that are published in the Federal Register and submitted to Congress after the lookback day are made available for review in the subsequent session of Congress.
|
| 288 |
The current lookback date is [August 16, 2024](https://www.congress.gov/congressional-record/volume-171/issue-18/house-section/article/H398-8).
|
| 289 |
-
This dashboard allows users to explore how different lookback window dates would affect the set of rules available for congressional review.
|
| 290 |
|
| 291 |
"Section 3(f)(1) significant" rules are regulations that meet the criteria in Section 3(f)(1) of [Executive Order 12866](https://www.archives.gov/files/federal-register/executive-orders/pdf/12866.pdf), as amended by [Executive Order 14094](https://www.govinfo.gov/content/pkg/FR-2023-04-11/pdf/2023-07760.pdf), referring to those with an estimated annual effect on the economy of $200 million or more.
|
| 292 |
"Other significant" rules are regulations that meet the other criteria in Section 3(f) of Executive Order 12866, as amended by Executive Order 14094, such as those creating inconsistency with other agencies' actions, altering certain budgetary impacts, or raising legal or policy issues pertaining to the president's priorities.
|
|
@@ -309,7 +314,7 @@ def filtered_df(agency_column: str = "parent_slug"):
|
|
| 309 |
filt_df = DF
|
| 310 |
|
| 311 |
# merge with RD data
|
| 312 |
-
filt_df=
|
| 313 |
|
| 314 |
# filter dates
|
| 315 |
try:
|
|
@@ -322,7 +327,16 @@ def filtered_df(agency_column: str = "parent_slug"):
|
|
| 322 |
if (input.menu_agency() is not None) and ("all" not in input.menu_agency()):
|
| 323 |
bool_agency = [True if sum(selected in agency for selected in input.menu_agency()) > 0 else False for agency in filt_df[agency_column]]
|
| 324 |
filt_df = filt_df.loc[bool_agency]
|
| 325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
# return filtered dataframe
|
| 327 |
return filt_df
|
| 328 |
|
|
@@ -392,7 +406,7 @@ def grouped_df_week():
|
|
| 392 |
|
| 393 |
@reactive.calc
|
| 394 |
def grouped_df_agency():
|
| 395 |
-
filt_df
|
| 396 |
grouped = groupby_agency(filt_df, metadata=METADATA, significant=GET_SIGNIFICANT)
|
| 397 |
return grouped
|
| 398 |
|
|
|
|
| 15 |
WINDOW_OPEN_DATE,
|
| 16 |
GET_SIGNIFICANT,
|
| 17 |
METADATA,
|
| 18 |
+
AGENCIES,
|
| 19 |
+
CRA_LAST_UPDATED,
|
| 20 |
groupby_agency,
|
| 21 |
groupby_date,
|
| 22 |
add_week_info_to_data,
|
|
|
|
| 25 |
plot_tf,
|
| 26 |
plot_NA,
|
| 27 |
plot_NA,
|
| 28 |
+
get_rd
|
| 29 |
)
|
| 30 |
|
| 31 |
from shiny import reactive
|
|
|
|
| 66 |
FOOTER = f"""
|
| 67 |
-----
|
| 68 |
|
| 69 |
+
© {date.today().year} [GW Regulatory Studies Center](https://go.gwu.edu/regstudies). See our page on the [Congressional Review Act](https://regulatorystudies.columbian.gwu.edu/congressional-review-act) for more information.
|
| 70 |
"""
|
| 71 |
|
| 72 |
|
|
|
|
| 95 |
ui.input_select("menu_significant", "Select rule significance", choices=["all", "3f1-significant", "other-significant"], selected="all", multiple=True, size=3)
|
| 96 |
"Rule significance as defined in Executive Order 12866, as amended by Executive Order 14094."
|
| 97 |
|
| 98 |
+
with ui.tooltip(placement="right", id="cra_tooltip"):
|
| 99 |
+
ui.input_select("menu_cra_target", "Select CRA target status", choices=["all", "CRA targeted", "Not CRA targeted"], selected="all", multiple=True, size=3)
|
| 100 |
+
f"Whether a rule has been targeted in a joint resolution (RD) for congressional disapproval (data last updated {CRA_LAST_UPDATED})."
|
| 101 |
+
|
| 102 |
with ui.tooltip(placement="right", id="agency_tooltip"):
|
| 103 |
ui.input_select("menu_agency", "Select agencies", choices=["all"] + AGENCIES, selected=["all"], multiple=True, size=6)
|
| 104 |
"Select one or more parent-level agencies."
|
|
|
|
| 155 |
"other_significant",
|
| 156 |
"CRA Target",
|
| 157 |
"CRA Stage",
|
| 158 |
+
"RD No. & Date",
|
| 159 |
]
|
| 160 |
return render.DataGrid(df.loc[:, [c for c in cols if c in df.columns]], width="100%")
|
| 161 |
|
|
|
|
| 204 |
"other_significant",
|
| 205 |
"CRA Target",
|
| 206 |
"CRA Stage",
|
| 207 |
+
"RD No. & Date",
|
| 208 |
]
|
| 209 |
return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
|
| 210 |
|
|
|
|
| 237 |
"other_significant",
|
| 238 |
"CRA Target",
|
| 239 |
"CRA Stage",
|
| 240 |
+
"RD No. & Date",
|
| 241 |
]
|
| 242 |
return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
|
| 243 |
|
|
|
|
| 270 |
"other_significant",
|
| 271 |
"CRA Target",
|
| 272 |
"CRA Stage",
|
| 273 |
+
"RD No. & Date",
|
| 274 |
"RD Link"
|
| 275 |
)
|
| 276 |
):
|
| 277 |
+
filt_df = filter_significance().copy()
|
| 278 |
filt_df.loc[:, "agencies"] = filt_df.loc[:, "agency_slugs"].apply(lambda x: "; ".join(x))
|
| 279 |
filt_df.loc[:, "parent_agencies"] = filt_df.loc[:, "parent_slug"].apply(lambda x: "; ".join(x))
|
| 280 |
filt_df.loc[:, "subagencies"] = filt_df.loc[:, "subagency_slug"].apply(lambda x: "; ".join(x))
|
|
|
|
| 288 |
|
| 289 |
ui.markdown(
|
| 290 |
f"""
|
| 291 |
+
This dashboard allows users to explore how different [Congressional Review Act](https://uscode.house.gov/view.xhtml?req=granuleid%3AUSC-prelim-title5-chapter8&saved=%7CKHRpdGxlOjUgc2VjdGlvbjo4MDEgZWRpdGlvbjpwcmVsaW0pIE9SIChncmFudWxlaWQ6VVNDLXByZWxpbS10aXRsZTUtc2VjdGlvbjgwMSk%3D%7CdHJlZXNvcnQ%3D%7C%7C0%7Cfalse%7Cprelim&edition=prelim) (CRA) lookback window dates would affect the set of rules available for congressional review and tracks resolutions for disapproval targeting the rules published within this window.
|
| 292 |
+
The “lookback window” refers to the period starting [60 working days](https://crsreports.congress.gov/product/pdf/R/R46690#page=8) (either session days in the Senate or legislative days in the House of Representatives) before the current session of Congress adjourns and ending the day the subsequent session of Congress first convenes.
|
| 293 |
Rules that are published in the Federal Register and submitted to Congress after the lookback day are made available for review in the subsequent session of Congress.
|
| 294 |
The current lookback date is [August 16, 2024](https://www.congress.gov/congressional-record/volume-171/issue-18/house-section/article/H398-8).
|
|
|
|
| 295 |
|
| 296 |
"Section 3(f)(1) significant" rules are regulations that meet the criteria in Section 3(f)(1) of [Executive Order 12866](https://www.archives.gov/files/federal-register/executive-orders/pdf/12866.pdf), as amended by [Executive Order 14094](https://www.govinfo.gov/content/pkg/FR-2023-04-11/pdf/2023-07760.pdf), referring to those with an estimated annual effect on the economy of $200 million or more.
|
| 297 |
"Other significant" rules are regulations that meet the other criteria in Section 3(f) of Executive Order 12866, as amended by Executive Order 14094, such as those creating inconsistency with other agencies' actions, altering certain budgetary impacts, or raising legal or policy issues pertaining to the president's priorities.
|
|
|
|
| 314 |
filt_df = DF
|
| 315 |
|
| 316 |
# merge with RD data
|
| 317 |
+
filt_df = get_rd(filt_df)
|
| 318 |
|
| 319 |
# filter dates
|
| 320 |
try:
|
|
|
|
| 327 |
if (input.menu_agency() is not None) and ("all" not in input.menu_agency()):
|
| 328 |
bool_agency = [True if sum(selected in agency for selected in input.menu_agency()) > 0 else False for agency in filt_df[agency_column]]
|
| 329 |
filt_df = filt_df.loc[bool_agency]
|
| 330 |
+
|
| 331 |
+
# filter CRA target status
|
| 332 |
+
bool_cra = []
|
| 333 |
+
if (input.menu_cra_target() is not None) and ("all" not in input.menu_cra_target()):
|
| 334 |
+
if "CRA targeted" in input.menu_cra_target():
|
| 335 |
+
bool_cra.append((filt_df["CRA Target"] == 1).to_numpy())
|
| 336 |
+
if "Not CRA targeted" in input.menu_cra_target():
|
| 337 |
+
bool_cra.append((filt_df["CRA Target"] == 0).to_numpy())
|
| 338 |
+
filt_df = filt_df.loc[array(bool_cra).any(axis=0)]
|
| 339 |
+
|
| 340 |
# return filtered dataframe
|
| 341 |
return filt_df
|
| 342 |
|
|
|
|
| 406 |
|
| 407 |
@reactive.calc
|
| 408 |
def grouped_df_agency():
|
| 409 |
+
filt_df=filter_significance()
|
| 410 |
grouped = groupby_agency(filt_df, metadata=METADATA, significant=GET_SIGNIFICANT)
|
| 411 |
return grouped
|
| 412 |
|
modules/get_resolutions.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
| 1 |
import pandas as pd
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
rd_stages={0:'Introduced',
|
| 5 |
-
1:'Passed
|
| 6 |
-
2:'Passed
|
| 7 |
-
3:'Became
|
| 8 |
-
4:'Vetoed by
|
| 9 |
|
| 10 |
-
|
| 11 |
def read_cra_data(file_path):
|
| 12 |
|
| 13 |
# Import CRA data set
|
|
@@ -16,6 +18,9 @@ def read_cra_data(file_path):
|
|
| 16 |
# Refine dataframe
|
| 17 |
df_rd=df_rd[['rd','introdate','rd_link','ridentifier','rin','introducedbin','chamberpass_atleast1','chamberpass_2','becamelawbin','vetobin']]
|
| 18 |
|
|
|
|
|
|
|
|
|
|
| 19 |
# Define RD status variable
|
| 20 |
df_rd['rd_status']=df_rd[['chamberpass_atleast1','chamberpass_2','becamelawbin','vetobin']].sum(axis=1)
|
| 21 |
|
|
@@ -30,27 +35,59 @@ def read_cra_data(file_path):
|
|
| 30 |
|
| 31 |
# Rename columns
|
| 32 |
df_rd.rename(columns={'ridentifier':'citation','introducedbin':'CRA Target',
|
| 33 |
-
'rd_status':'CRA Stage','rd_date': 'RD
|
| 34 |
|
| 35 |
# Replace RD stage values
|
| 36 |
df_rd['CRA Stage'] = df_rd['CRA Stage'].replace(rd_stages)
|
| 37 |
|
| 38 |
-
return df_rd
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
# Read CRA data set
|
| 43 |
cra_file_path='congress_data\cra_data.csv'
|
| 44 |
-
df_rd=read_cra_data(cra_file_path)
|
| 45 |
-
# print(df_rd.head())
|
| 46 |
|
| 47 |
# Merge
|
| 48 |
df_merged=df_fr.merge(df_rd,on='citation',how='left')
|
| 49 |
|
| 50 |
-
# Fill
|
| 51 |
df_merged['CRA Target']=df_merged['CRA Target'].fillna(0)
|
| 52 |
|
| 53 |
return df_merged
|
| 54 |
|
| 55 |
-
#%%
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import pandas as pd
|
| 2 |
+
import subprocess
|
| 3 |
+
import datetime
|
| 4 |
|
| 5 |
+
#%% Define RD stages
|
| 6 |
+
rd_stages={0:'RD Introduced',
|
| 7 |
+
1:'RD Passed One Chamber',
|
| 8 |
+
2:'RD Passed Two Chambers',
|
| 9 |
+
3:'RD Became Law',
|
| 10 |
+
4:'RD Vetoed by President'}
|
| 11 |
|
| 12 |
+
#%% Function to read and clean CRA RD dataset
|
| 13 |
def read_cra_data(file_path):
|
| 14 |
|
| 15 |
# Import CRA data set
|
|
|
|
| 18 |
# Refine dataframe
|
| 19 |
df_rd=df_rd[['rd','introdate','rd_link','ridentifier','rin','introducedbin','chamberpass_atleast1','chamberpass_2','becamelawbin','vetobin']]
|
| 20 |
|
| 21 |
+
# Get the latest RD intro date
|
| 22 |
+
last_rd_date=max(df_rd['introdate'].astype('datetime64[ns]'))
|
| 23 |
+
|
| 24 |
# Define RD status variable
|
| 25 |
df_rd['rd_status']=df_rd[['chamberpass_atleast1','chamberpass_2','becamelawbin','vetobin']].sum(axis=1)
|
| 26 |
|
|
|
|
| 35 |
|
| 36 |
# Rename columns
|
| 37 |
df_rd.rename(columns={'ridentifier':'citation','introducedbin':'CRA Target',
|
| 38 |
+
'rd_status':'CRA Stage','rd_date': 'RD No. & Date','rd_link':'RD Link'},inplace=True)
|
| 39 |
|
| 40 |
# Replace RD stage values
|
| 41 |
df_rd['CRA Stage'] = df_rd['CRA Stage'].replace(rd_stages)
|
| 42 |
|
| 43 |
+
return df_rd, last_rd_date
|
| 44 |
+
|
| 45 |
+
#%% Function to get last modified date of a file
|
| 46 |
+
def get_last_modified_date(file_path):
|
| 47 |
+
"""
|
| 48 |
+
Retrieves the last modified date of a file in Git.
|
| 49 |
+
|
| 50 |
+
Args:
|
| 51 |
+
file_path (str): The path to the file.
|
| 52 |
|
| 53 |
+
Returns:
|
| 54 |
+
datetime: A datetime object representing the last modified date, or None if an error occurs.
|
| 55 |
+
"""
|
| 56 |
+
try:
|
| 57 |
+
# Execute git log command to get the latest commit information for the file
|
| 58 |
+
result = subprocess.run(['git', 'log', '-n', '1', '--pretty=format:%at', '--', file_path], capture_output=True, text=True, check=True)
|
| 59 |
+
timestamp = int(result.stdout.strip())
|
| 60 |
+
return datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d")
|
| 61 |
+
except subprocess.CalledProcessError as e:
|
| 62 |
+
print(f"Error: {e}")
|
| 63 |
+
return None
|
| 64 |
+
except ValueError:
|
| 65 |
+
print(f"Error: Could not parse timestamp from git log output.")
|
| 66 |
+
return None
|
| 67 |
+
|
| 68 |
+
#%% Function to merge RD data with FR data
|
| 69 |
+
def get_rd(df_fr):
|
| 70 |
# Read CRA data set
|
| 71 |
cra_file_path='congress_data\cra_data.csv'
|
| 72 |
+
df_rd,_=read_cra_data(cra_file_path)
|
|
|
|
| 73 |
|
| 74 |
# Merge
|
| 75 |
df_merged=df_fr.merge(df_rd,on='citation',how='left')
|
| 76 |
|
| 77 |
+
# Fill null
|
| 78 |
df_merged['CRA Target']=df_merged['CRA Target'].fillna(0)
|
| 79 |
|
| 80 |
return df_merged
|
| 81 |
|
| 82 |
+
#%% Function to get last modified date of the RD dataset
|
| 83 |
+
def get_cra_updated_date(cra_file_path='congress_data\cra_data.csv'):
|
| 84 |
+
cra_last_updated = get_last_modified_date(cra_file_path)
|
| 85 |
+
|
| 86 |
+
if cra_last_updated:
|
| 87 |
+
return cra_last_updated
|
| 88 |
+
else:
|
| 89 |
+
_,last_rd_date=read_cra_data(cra_file_path)
|
| 90 |
+
return last_rd_date.strftime("%Y-%m-%d")
|
| 91 |
+
|
| 92 |
+
#%% Create objects to import in app
|
| 93 |
+
CRA_LAST_UPDATED=get_cra_updated_date()
|