diff --git a/portfolio/sb125_fund_split_analysis/00__sb125_fund_split_analysis__.ipynb b/portfolio/sb125_fund_split_analysis/00__sb125_fund_split_analysis__.ipynb new file mode 100644 index 000000000..e8736314b --- /dev/null +++ b/portfolio/sb125_fund_split_analysis/00__sb125_fund_split_analysis__.ipynb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e5753c39432f7f9d8ca9fabc6dfc9e74647f2c6e42572783d33c81452b4d288 +size 314411 diff --git a/portfolio/sb125_fund_split_analysis/README.md b/portfolio/sb125_fund_split_analysis/README.md new file mode 100644 index 000000000..735c639f4 --- /dev/null +++ b/portfolio/sb125_fund_split_analysis/README.md @@ -0,0 +1,33 @@ + # SB125 Fund Split Analysis +As a condition of receiving SB125 (TIRCP and ZETCP programs) funds, RTPAs are required to complete an Initial Allocation Package describing their full four-year plan for use of these formulaic funds. + +Agencies or RTPAs are requried to submit a summary Excel table (`SB 125 Fund Request.xlsx`) that explains the proposed uses of TIRCP and ZETCP funds by fiscal year of availability. This table is subdivided between funding for capital projects and funding for operations expenses, with each project and its implementing agency specifically identified, and each operator that will receive operations funding also specifically identified. + +This analysis aims to answer the question of "of all the fund request tables received, how much money is allocated to operating expenses and capital projects?" + +Answering these questions will help inform CalSTA, Caltrans and other stakeholders of how agencies plan to use these funds to fulfill the objectives of SB125 and transform transit in California. + + +## Definitions +- SB125: Senate Bill-125 Transportation budget trailer bill +- TIRCP: Transit and Intercity Rail Capital Program +- ZETCP: Zero-Emission Transit Capital Program +- RTPA: Regional transportation planning agencies +- CalSTA: California State Transportation Agency +- State Fiscal Year: July 1 to June 30 + + +## Methodology +Excel tables were cleaned and prepared to a uniform format. Fund data was then aggregated by RTPA, implementing agency and state fiscal year. + + +## Data Sources +All fund request excel tables were extracted from all available allocation packages. + + +## Who We Are +This website was created by the [California Department of Transportation](https://dot.ca.gov/)'s Division of Data and Digital Services. We are a group of data analysts and scientists who analyze transportation data, such as General Transit Feed Specification (GTFS) data, or data from funding programs such as the Active Transportation Program. Our goal is to transform messy and indecipherable original datasets into usable, customer-friendly products to better the transportation landscape. For more of our work, visit our [portfolio](https://analysis.calitp.org/). + +Alt text Alt text + +
Caltrans®, the California Department of Transportation® and the Caltrans logo are registered service marks of the California Department of Transportation and may not be copied, distributed, displayed, reproduced or transmitted in any form without prior written permission from the California Department of Transportation. diff --git a/portfolio/sb125_fund_split_analysis/_config.yml b/portfolio/sb125_fund_split_analysis/_config.yml new file mode 100644 index 000000000..2f0fdfd86 --- /dev/null +++ b/portfolio/sb125_fund_split_analysis/_config.yml @@ -0,0 +1,43 @@ +# Book settings +# Learn more at https://jupyterbook.org/customize/config.html + +title: SB125 Fund Split Analysis +author: Cal-ITP +copyright: "2024" +#logo: calitp_logo_MAIN.png + +# Force re-execution of notebooks on each build. +# See https://jupyterbook.org/content/execute.html +execute: + execute_notebooks: 'off' + allow_errors: false + timeout: -1 + +# Define the name of the latex output file for PDF builds +latex: + latex_documents: + targetname: book.tex + +launch_buttons: + binderhub_url: "https://mybinder.org" + jupyterhub_url: "https://hubtest.k8s.calitp.jarv.us" + thebe: true + +repository: + url: https://github.com/cal-itp/data-analyses/ # Online location of your book +# path_to_book: docs # Optional path to your book, relative to the repository root + path_to_book: sb125_analyses/sb125_fund_split_analysis + branch: main # Which branch of the repository should be used when creating links (optional) + +# Add GitHub buttons to your book +# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository +html: + use_issues_button: true + use_repository_button: true + use_edit_page_button: true + google_analytics_id: 'G-JCX3Z8JZJC' + +sphinx: + config: + html_js_files: + - https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js \ No newline at end of file diff --git a/portfolio/sb125_fund_split_analysis/_toc.yml b/portfolio/sb125_fund_split_analysis/_toc.yml new file mode 100644 index 000000000..57ed58d92 --- /dev/null +++ b/portfolio/sb125_fund_split_analysis/_toc.yml @@ -0,0 +1,6 @@ +format: jb-book +parts: +- caption: null + chapters: + - file: 00__sb125_fund_split_analysis__.ipynb +root: README diff --git a/portfolio/sites/sb125_fund_split_analysis.yml b/portfolio/sites/sb125_fund_split_analysis.yml new file mode 100644 index 000000000..c203434d3 --- /dev/null +++ b/portfolio/sites/sb125_fund_split_analysis.yml @@ -0,0 +1,7 @@ +title: SB125 Fund Split Analysis +directory: ./sb125_analyses/sb125_fund_split_analysis/ +readme: ./sb125_analyses/sb125_fund_split_analysis/README.md +parts: +- caption: SB125 Fund Split Analysis +- chapters: + - notebook: ./sb125_analyses/sb125_fund_split_analysis/sb125_fund_split_analysis.ipynb \ No newline at end of file diff --git a/sb125_analyses/sb125_fund_split_analysis/README.md b/sb125_analyses/sb125_fund_split_analysis/README.md new file mode 100644 index 000000000..735c639f4 --- /dev/null +++ b/sb125_analyses/sb125_fund_split_analysis/README.md @@ -0,0 +1,33 @@ + # SB125 Fund Split Analysis +As a condition of receiving SB125 (TIRCP and ZETCP programs) funds, RTPAs are required to complete an Initial Allocation Package describing their full four-year plan for use of these formulaic funds. + +Agencies or RTPAs are requried to submit a summary Excel table (`SB 125 Fund Request.xlsx`) that explains the proposed uses of TIRCP and ZETCP funds by fiscal year of availability. This table is subdivided between funding for capital projects and funding for operations expenses, with each project and its implementing agency specifically identified, and each operator that will receive operations funding also specifically identified. + +This analysis aims to answer the question of "of all the fund request tables received, how much money is allocated to operating expenses and capital projects?" + +Answering these questions will help inform CalSTA, Caltrans and other stakeholders of how agencies plan to use these funds to fulfill the objectives of SB125 and transform transit in California. + + +## Definitions +- SB125: Senate Bill-125 Transportation budget trailer bill +- TIRCP: Transit and Intercity Rail Capital Program +- ZETCP: Zero-Emission Transit Capital Program +- RTPA: Regional transportation planning agencies +- CalSTA: California State Transportation Agency +- State Fiscal Year: July 1 to June 30 + + +## Methodology +Excel tables were cleaned and prepared to a uniform format. Fund data was then aggregated by RTPA, implementing agency and state fiscal year. + + +## Data Sources +All fund request excel tables were extracted from all available allocation packages. + + +## Who We Are +This website was created by the [California Department of Transportation](https://dot.ca.gov/)'s Division of Data and Digital Services. We are a group of data analysts and scientists who analyze transportation data, such as General Transit Feed Specification (GTFS) data, or data from funding programs such as the Active Transportation Program. Our goal is to transform messy and indecipherable original datasets into usable, customer-friendly products to better the transportation landscape. For more of our work, visit our [portfolio](https://analysis.calitp.org/). + +Alt text Alt text + +
Caltrans®, the California Department of Transportation® and the Caltrans logo are registered service marks of the California Department of Transportation and may not be copied, distributed, displayed, reproduced or transmitted in any form without prior written permission from the California Department of Transportation. diff --git a/sb125_analyses/sb125_fund_split_analysis/fund_split.py b/sb125_analyses/sb125_fund_split_analysis/fund_split.py new file mode 100644 index 000000000..2690cccb3 --- /dev/null +++ b/sb125_analyses/sb125_fund_split_analysis/fund_split.py @@ -0,0 +1,669 @@ +# A lot of dataframes needed to be uniquly cleaned, + +import altair as alt +import pandas as pd + +GCS_PATH = "gs://calitp-analytics-data/data-analyses/sb125/fund_split/" + +file_list = [ + "sierra_fund_request.xlsx", + "slocog_fund_request.xlsx", + "tehema_fund_request.xlsx", + "tuolumne_fund_request.xlsx", + "ventura_fund_request.xlsx", + "alpine_fund_request.xlsx", + "amador_fund_request.xlsx", + "butte_fund_request.xlsx", + "calaveras_fund_request.xlsx", + "del_norte_fund_request.xlsx", + "el_dorado_fund_request.xlsx", + "humboldt_fund_request.xlsx", + "kern_fund_request.xlsx", + "kings_fund_request.xlsx", + "la_metro_fund_request.xlsx", + "lake_fund_request.xlsx", + "lassen_fund_request.xlsx", + "madera_fund_request.xlsx", + "mariposa_fund_request.xlsx", + "mendocino_fund_request.xlsx", + "merced_fund_request.xlsx", + "mtc_fund_request.xlsx", + "nevada_fund_request.xlsx", + "orange_fund_request.xlsx", + "placer_fund_request.xlsx", + "plumas_fund_request.xlsx", + "riverside_fund_request.xlsx", + "san_benito_fund_request.xlsx", + "san_diego_mts_fund_request.xlsx", + "santa_cruz_fund_request.xlsx", + "shasta_fund_request.xlsx", +] + +file_list.sort() + +col_names = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + "total", +] + + +def clean_fund_request(file: str) -> pd.DataFrame: + """ + reads in the file from GCS, maps col_names list to df columns, drops all the blank rows. + returns df. + """ + col_names = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + "total", + ] + + df = pd.read_excel(f"{GCS_PATH}{file}", header=2, nrows=40, names=col_names).drop( + columns="total" + ) + row_drop = df["rtpa"].isin(["Grand Total", "RTPA"]) + df = df.drop(df[row_drop].index) + df = df.dropna(how="all") + df[["rtpa", "implementing agenc-y/-ies", "project"]] = df[ + ["rtpa", "implementing agenc-y/-ies", "project"] + ].ffill() + + return df + + +def fund_request_checker_v3(file_list: list) -> tuple: + """takes in list of fund_request excel file name. reads in each file, checks if DF has 13 columns. + if yes, appends do good-to-go list. else, appends to needs-manual-review. + output is a tuple of the 2 list. + assign 2 variables to use this func. + """ + gtg_files = [] + manual_review = [] + for file in file_list: + + df = pd.read_excel(f"{GCS_PATH}{file}", nrows=40) + df = df.dropna(how="all") + + if len(df.columns) == 13: + gtg_files.append(f"{file}") + else: + manual_review.append(f"{file}") + return gtg_files, manual_review + + +def cleaner_loop(gtg_list: list) -> dict: + """ + takes in good-to-go list from fund_request_checker. + applies the clean_fund_request function to each item on the list, then appends to dictionary. + key is name of the file, value is the cleaned dataframe. + output is dictionary. + """ + cleaned_df = {} + + for name in gtg_list: + cleaned_df[name] = clean_fund_request(name) + return cleaned_df + + +def clean_humboldt(): + cleaned_fund_request["humboldt_fund_request.xlsx"][ + ["operating_FY24-25", "operating_FY25-26", "operating_FY26-27"] +] = cleaned_fund_request["humboldt_fund_request.xlsx"][ + ["operating_FY24-25", "operating_FY25-26", "operating_FY26-27"] +].replace( + "-", 0 +) + return + + +def clean_amador(): + cleaned_fund_request["amador_fund_request.xlsx"] = cleaned_fund_request[ + "amador_fund_request.xlsx" + ][cleaned_fund_request["amador_fund_request.xlsx"]["fund source"].notna() + ] + return + + +def clean_merced(): + cleaned_fund_request["merced_fund_request.xlsx"]= cleaned_fund_request[ + "merced_fund_request.xlsx"][cleaned_fund_request["merced_fund_request.xlsx"]["project"].notna()].drop([34, 36, 37]) + + # is there another way to update these values that doesnt include using the number index + cleaned_fund_request["merced_fund_request.xlsx"].at[13, "fund source"] = "`5339" + cleaned_fund_request["merced_fund_request.xlsx"].at[19, "fund source"] = "`5307" + + return + + +def clean_san_benito(): + cleaned_fund_request["san_benito_fund_request.xlsx"] = cleaned_fund_request["san_benito_fund_request.xlsx"][ + cleaned_fund_request["san_benito_fund_request.xlsx"]["fund source"].notna()] + + return + + +def clean_mts(): + cleaned_fund_request["san_diego_mts_fund_request.xlsx"] = cleaned_fund_request["san_diego_mts_fund_request.xlsx"].iloc[7:] + + return + + +def clean_sierra(): + cleaned_fund_request["sierra_fund_request.xlsx"] = cleaned_fund_request["sierra_fund_request.xlsx"].iloc[:-8] + + return + + +def clean_nevada(): + cleaned_fund_request["nevada_fund_request.xlsx"]=cleaned_fund_request["nevada_fund_request.xlsx"][ + cleaned_fund_request["nevada_fund_request.xlsx"]["fund source"].notna()] + + return + + +def clean_plumas(): + cleaned_fund_request["plumas_fund_request.xlsx"]=cleaned_fund_request["plumas_fund_request.xlsx"][cleaned_fund_request["plumas_fund_request.xlsx"][ + "fund source"].notna()] + + return + + +def clean_lassen(): + lassen = pd.read_excel( + f"{GCS_PATH}lassen_fund_request.xlsx", + sheet_name="D.2. Detailed Fund Request", + skiprows=6, + header=0, + skipfooter=12, + ).drop(columns=["Unnamed: 0", "Project Type", "Operator"]) + + # can work with this. may be able to remove the top rows then use cleaner loop + lassen.columns = col_names + lassen_cleaned = lassen.drop(columns="total") + + return lassen_cleaned + + +def clean_butte(): + butte = pd.read_excel( + f"{GCS_PATH}butte_fund_request.xlsx", + skiprows=2, + header=0, + skipfooter=17, + ) + + butte_cleaned = butte.copy() + + butte_cleaned[["RTPA", "Implementing Agenc-y/-ies", "Project"]] = butte_cleaned[ + ["RTPA", "Implementing Agenc-y/-ies", "Project"] + ].ffill() + + butte_cleaned.insert(6, "operations FY25-26", 0) + butte_cleaned.insert(7, "operations FY26-27", 0) + butte_cleaned.columns = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "total", + ] + butte_cleaned = butte_cleaned.drop(columns="total") + + return butte_cleaned + + +def clean_mtc(): + mtc = pd.read_excel( + f"{GCS_PATH}mtc_fund_request.xlsx", skiprows=2, header=0, skipfooter=21 + ).drop(columns=["Unnamed: 13", "Unnamed: 14", "Unnamed: 15"]) + + mtc_cleaned = mtc.copy() + mtc_cleaned.columns = col_names + mtc_cleaned = mtc_cleaned.drop(columns="total") + + return mtc_cleaned + + +def clean_orange(): + orange = pd.read_excel( + f"{GCS_PATH}orange_fund_request.xlsx", skiprows=3, header=0, skipfooter=1 + ) + + orange_cleaned = orange.copy() + + orange_cleaned.rename(columns={"Unnamed: 0": "RTPA"}, inplace=True) + orange_cleaned["RTPA"] = "OCTA" + orange_cleaned = orange_cleaned.drop( + columns=["FY27-28", "FY28-29", "FY27-28.1", "FY28-29.1"] + ) + + orange_cleaned.columns = col_names + orange_cleaned = orange_cleaned.drop(columns="total") + + return orange_cleaned + + +def clean_santa_cruz(): + santa_cruz = pd.read_excel( + f"{GCS_PATH}santa_cruz_fund_request.xlsx", skiprows=4, header=0, skipfooter=5 + ).iloc[:, 0:13] + + santa_cruz_cleaned = santa_cruz.copy() + + santa_cruz_cleaned.columns = col_names + santa_cruz_cleaned.drop(columns="total", inplace=True) + + return santa_cruz_cleaned + + +def clean_ventura(): + #clean TIRCP sections + ventura_tircp_capital = pd.read_excel( + f"{GCS_PATH}ventura_fund_request.xlsx", + sheet_name="Project Breakdown", + skiprows=2, + header=0, + skipfooter=40, + ) + + ventura_tircp_operating = pd.read_excel( + f"{GCS_PATH}ventura_fund_request.xlsx", + sheet_name="Project Breakdown", + skiprows=51, + header=0, + skipfooter=1, + ) + + ventura_tircp_merge = ventura_tircp_capital.merge( + ventura_tircp_operating, + how="outer", + on=["Implementing Agenc-y/-ies", "Project Category", "Project"], + suffixes=["_capital", "_operating"], + ).drop( + columns=[ + "Year Requested", + "Unnamed: 8_capital", + "Unnamed: 8_operating", + "Project Category", + ] + ) + + #merging TIRCP sections + ventura_tircp_merge["rtpa"] = "VCTC" + ventura_tircp_merge["Fund Source"] = "TIRCP" + + ventura_col_dict = { + "Implementing Agenc-y/-ies": "implementing agenc-y/-ies", + "Project": "project", + "Fund Source": "fund source", + "FY23-24_capital": "capital_FY23-24", + "FY24-25_capital": "capital_FY24-25", + "FY25-26_capital": "capital_FY25-26", + "FY26-27_capital": "capital_FY26-27", + "FY23-24_operating": "operating_FY23-24", + "FY24-25_operating": "operating_FY24-25", + "FY25-26_operating": "operating_FY25-26", + "FY26-27_operating": "operating_FY26-27", + } + + col_order = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + ] + + ventura_tircp_merge.rename(columns=ventura_col_dict, inplace=True) + + ventura_tircp_merge = ventura_tircp_merge[col_order] + + # clean zetcp sections + ventura_zetcp_capital = pd.read_excel( + f"{GCS_PATH}ventura_fund_request.xlsx", + sheet_name="Project Breakdown", + skiprows=32, + header=0, + skipfooter=21, + ).drop(columns=["Unnamed: 7", "Unnamed: 8"]) + fund_dict = { + "GGRF Y1": "ZETCP (GGRF)", + "GGRF Y2": "ZETCP (GGRF)", + "GGRF Y3": "ZETCP (GGRF)", + "GGRF Y4": "ZETCP (GGRF)", + "PTA": "ZETCP (PTA)", + } + + ven_col = { + "Implementing Agenc-y/-ies": "implementing agenc-y/-ies", + "Project": "project", + "Fund Source": "fund source", + "FY23-24": "capital_FY23-24", + "FY24-25": "capital_FY24-25", + "FY25-26": "capital_FY25-26", + "FY26-27": "capital_FY26-27", + } + + ventura_zetcp_capital["Fund Source"] = ventura_zetcp_capital["Fund Source"].replace( + fund_dict + ) + + ventura_zetcp_capital["rtpa"] = "VCTC" + + ventura_zetcp_capital.rename(columns=ven_col, inplace=True) + + ventura_zetcp_capital = ventura_zetcp_capital[col_order[0:8]] + + #final merge + ventura_big_merge = ventura_tircp_merge.merge( + ventura_zetcp_capital, + how="outer", + on=[ + "implementing agenc-y/-ies", + "project", + "fund source", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "rtpa", + ], + suffixes=("_zetcp_cap", "_tircp"), + ) + return ventura_big_merge + + +def get_kern_data(head_count: int, foot_count: int, agency: str, proj_title: str): + + kern_cols = { + "Unnamed: 0": "fund source", + "Unnamed: 1": "capital_FY23-24", + "Unnamed: 2": "operating_FY23-24", + "Unnamed: 3": "capital_FY24-25", + "Unnamed: 4": "operating_FY24-25", + "Unnamed: 5": "capital_FY25-26", + "Unnamed: 6": "operating_FY25-26", + "Unnamed: 7": "capital_FY26-27", + "Unnamed: 8": "operating_FY26-27", + } + df = ( + pd.read_excel( + f"{GCS_PATH}kern_fund_request.xlsx", + header=head_count, + skipfooter=foot_count, + ) + .rename(columns=kern_cols) + .assign(implementing_agency=agency, rtpa="Kern COG", project=proj_title) + ) + return df + + +def clean_kern(): + + col_order = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + ] + + kern_cols = { + "Unnamed: 0": "fund source", + "Unnamed: 1": "capital_FY23-24", + "Unnamed: 2": "operating_FY23-24", + "Unnamed: 3": "capital_FY24-25", + "Unnamed: 4": "operating_FY24-25", + "Unnamed: 5": "capital_FY25-26", + "Unnamed: 6": "operating_FY25-26", + "Unnamed: 7": "capital_FY26-27", + "Unnamed: 8": "operating_FY26-27", + } + + arvin = get_kern_data( + 3, + 43, + "arvin", + "Purcahse and install EV mirco-grid Purcahse and install EV mirco-grid", + ) + + california_city = get_kern_data( + 7, + 39, + "california city", + "Purchase and construct transit building to house EV vans and solar charging stations", + ) + + delano = get_kern_data(11, 35, "delano", "Construct transit Facility") + + get = get_kern_data( + 15, + 31, + "get", + "Golden Empire Transit Free or near free transit fares Back up hydrogent fuel plant", + ) + + kern_transit = get_kern_data( + 19, + 27, + "kern transit", + "Transition to Zero-Emission Vehicles and supporting infrastructure", + ) + + mcfarland = get_kern_data( + 23, + 23, + "mcfarland", + "Design and construct a transit station providing a transit office , waitning area, restrooms and EV charging stations", + ) + + ridgecrest = get_kern_data( + 27, + 19, + "ridgecrest", + "Replacement of Cutaway Buses with Electric Vans and Construction of Bus Stop at North Norma Street and West Felspar Avenue", + ) + + shafter = get_kern_data( + 31, 15, "shafter", "bus storage, new transit vehicles, free ridership fare program" + ) + + taft = get_kern_data( + 35, + 11, + "taft", + "convert the City’s gasoline powered fleet of on-demand transit vehicles to plug-in electric vans compatible with the solar-powered charging infrastructure being completed now.", + ) + + tehahapi = get_kern_data( + 39, + 9, + "tehahapi", + "Improvements to Downtown Transit Center and Installation of EV Charging Infrastructure", + ) + + wasco = get_kern_data( + 43, + 3, + "wasco", "New Transit Operating and Maintenance Facility" + ) + + kern_concat = pd.concat( + [ + wasco, + tehahapi, + taft, + shafter, + ridgecrest, + mcfarland, + kern_transit, + get, + arvin, + california_city, + delano, + ], + ignore_index=True, + ) + + kern_clean = kern_concat[kern_concat["fund source"].isin(["TIRCP", "ZETCP"])].rename( + columns={"implementing_agency": "implementing agenc-y/-ies"} + ) + + kern_clean = kern_clean[col_order] + + return kern_clean + + +def concat_everything(): + all_fund_requests = pd.concat(cleaned_fund_request.values(), ignore_index=True) + + all_fund_requests = pd.concat( + [ + all_fund_requests, + santa_cruz_cleaned, + orange_cleaned, + butte_cleaned, + lassen_cleaned, + ventura_cleaned, + kern_cleaned, + ], + ignore_index=True, + ) + + all_fund_requests["fund source"] = all_fund_requests["fund source"].astype(str) + + return all_fund_requests + + +def fund_request_melt(df): + id_vars = [ + "rtpa", + "implementing agenc-y/-ies", + "project", + "fund source", + ] + val_vars = [ + "capital_FY23-24", + "capital_FY24-25", + "capital_FY25-26", + "capital_FY26-27", + "operating_FY23-24", + "operating_FY24-25", + "operating_FY25-26", + "operating_FY26-27", + ] + + melt = df.melt( + id_vars=id_vars, + value_vars=val_vars, + var_name="capital/operation fy", + value_name="fund amount", + ignore_index=True, + ) + + # splitting the cap/operations columns + + melt[["project type", "fiscal year"]] = melt["capital/operation fy"].str.split( + "_FY", expand=True + ) + + melt["fund amount"] = melt["fund amount"].fillna(0).astype("int64") + melt["fund source"] = melt["fund source"].astype("str") + + return melt + + + +if __name__ == "__main__": + + good_list, review_list = fund_request_checker_v3(file_list) + + cleaned_fund_request = cleaner_loop(good_list) + + #these functions clean specific values (DFs) in the cleaned_fund_request dict + clean_humboldt() + + clean_amador() + + clean_merced() + + clean_san_benito() + + clean_mts() + + clean_sierra() + + clean_nevada() + + clean_plumas() + + #these functions clean the problem data sets + lassen_cleaned = clean_lassen() + + butte_cleaned = clean_butte() + + mtc_cleaned = clean_mtc() + + orange_cleaned = clean_orange() + + santa_cruz_cleaned = clean_santa_cruz() + + ventura_cleaned = clean_ventura() + + kern_cleaned = clean_kern() + + # concat all values (DFs) from cleaned_fund_request dict to be a single DF and concat the rest of the DFs + + all_fund_requests = concat_everything() + + # SAVING TO GCS! + all_fund_requests.to_parquet(f"{GCS_PATH}all_fund_requests_concat.parquet") + + #melt all fund requests + all_melt = fund_request_melt(all_fund_requests) + + #saving to gcs + all_melt.to_parquet(f"{GCS_PATH}all_fund_requests_melt.parquet") \ No newline at end of file diff --git a/sb125_analyses/sb125_fund_split_analysis/fund_split_explore.ipynb b/sb125_analyses/sb125_fund_split_analysis/fund_split_explore.ipynb new file mode 100644 index 000000000..8b8298c8e --- /dev/null +++ b/sb125_analyses/sb125_fund_split_analysis/fund_split_explore.ipynb @@ -0,0 +1,3215 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "18bf8d66-e8cf-45bd-8d51-f316ad5eb588", + "metadata": {}, + "outputs": [], + "source": [ + "import altair as alt\n", + "import pandas as pd\n", + "from IPython.display import HTML, Image, Markdown, display, display_html\n", + "\n", + "pd.set_option(\"display.max_columns\", None)\n", + "pd.set_option(\"display.max_rows\", None)\n", + "\n", + "GCS_PATH = \"gs://calitp-analytics-data/data-analyses/sb125/fund_split/\"" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "f1acbbd9-87dd-47bb-b1d1-7f94296a1b4b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# move filter location to the top\n", + "\n", + "display(HTML( \"\"\"\"\"\"))" + ] + }, + { + "cell_type": "markdown", + "id": "b7df6d2c-ad3e-4630-8690-975e48049278", + "metadata": {}, + "source": [ + "# SB125 Fund Split Analysis" + ] + }, + { + "cell_type": "markdown", + "id": "42fdef6f-d9ca-419f-861e-54e94098b951", + "metadata": {}, + "source": [ + "## Question:\n", + "- How did RTAs split SB125 funds between operations and capital?" + ] + }, + { + "cell_type": "markdown", + "id": "56b377e1-5f8e-481b-af19-2a6ba2ff92e0", + "metadata": {}, + "source": [ + "## Methodology:\n", + "- upload all avilable `SB125 fund request template` files to gcs\n", + "- examine all files for consistencies:\n", + " - come with cleaning plan for inconsistent examples (files withot capital/operating columns)\n", + "- concat all rows across all files\n" + ] + }, + { + "cell_type": "markdown", + "id": "ed15b993-c361-4cd0-b1b6-facf2efbba1f", + "metadata": {}, + "source": [ + "## Notes:\n", + "- Some RTPAs did not submit a `SB125 fund request template.xlsx` file, but instead included an equivilent file their allocation package\n", + "- There are ~30 files to analyze, most of which need to be uniquely cleaned. All cleaning steps are done in the `fund_split.py` script and saved to GCS" + ] + }, + { + "cell_type": "markdown", + "id": "081bd92f-5114-4678-87aa-500ea78f85ed", + "metadata": {}, + "source": [ + "# Read in Melt DF parquet from GCS" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c041c6eb-cda1-47fd-aecf-7dd04b6f52e7", + "metadata": {}, + "outputs": [], + "source": [ + "all_melt = pd.read_parquet(f\"{GCS_PATH}all_fund_requests_melt.parquet\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6460a800-8204-46ed-9cbc-4861f1114791", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2296, 8)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "rtpa object\n", + "implementing agenc-y/-ies object\n", + "project object\n", + "fund source object\n", + "capital/operation fy object\n", + "fund amount int64\n", + "project type object\n", + "fiscal year object\n", + "dtype: object" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(all_melt.shape, all_melt.dtypes)" + ] + }, + { + "cell_type": "markdown", + "id": "bc95fb74-b3ce-48f4-ba39-512e24557512", + "metadata": {}, + "source": [ + "**Altair Data Types**\n", + "\n", + "\"*:Q\" - Quantitative (quantity, numerical numbers)\n", + "\n", + "\"*:T\" - Temporal (dates and times)\n", + "\n", + "\"*:O\" - Ordinal (ranked order, small-med-large, \n", + "\n", + "\"*:N\" - Nominal (categorical)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c0ffa614-96db-46a0-9b53-b67c481dcf4e", + "metadata": {}, + "outputs": [], + "source": [ + "by_source = (\n", + " all_melt.groupby([\"fund source\"])\n", + " .agg({\"fund amount\": \"sum\", \"rtpa\": \"nunique\"})\n", + " .reset_index()\n", + ")\n", + "by_type = (\n", + " all_melt.groupby([\"project type\"])\n", + " .agg(\n", + " {\n", + " \"fund amount\": \"sum\",\n", + " }\n", + " )\n", + " .reset_index()\n", + ")\n", + "by_year = (\n", + " all_melt.groupby([\"fiscal year\", \"project type\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")\n", + "by_rtpa = (\n", + " all_melt.groupby([\"rtpa\", \"project type\", \"fiscal year\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")\n", + "\n", + "by_agency = (\n", + " all_melt.groupby([\"implementing agenc-y/-ies\", \"project type\", \"fiscal year\"])\n", + " .agg({\"fund amount\":\"sum\"})\n", + ").reset_index()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8ee99824-6216-41cc-9b61-67ef3c9ce384", + "metadata": {}, + "outputs": [], + "source": [ + "# aggregate by rtpa, agency, project type and FY\n", + "rtpa_group = (\n", + " all_melt.groupby(\n", + " [\"rtpa\", \"implementing agenc-y/-ies\", \"project type\", \"fiscal year\"]\n", + " )\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a7180b38-ce35-456d-9060-7d5cb940a36a", + "metadata": { + "tags": [] + }, + "source": [ + "# Main Charts" + ] + }, + { + "cell_type": "markdown", + "id": "e756fd1f-3a0d-4560-9bf6-6c8098dbe1c5", + "metadata": {}, + "source": [ + "## overall summary charts" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "572c255d-0ae5-4588-a0b1-5c9cfbef4870", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#Overall summary charts\n", + "\n", + "stack_chart = (\n", + " alt.Chart(by_year)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"fiscal year\",\n", + " x=\"fund amount\",\n", + " color=\"project type\",\n", + " tooltip=[\"project type\", \"fund amount\"],\n", + " )\n", + " .properties(\n", + " title=\"SB125 allocation funds by capital/operating expenses, by fiscal year\",\n", + " width=600,\n", + " height=300,\n", + " )\n", + ")\n", + "\n", + "stack_text = stack_chart.mark_text(\n", + " align=\"left\",\n", + " dx=-10,\n", + " dy=10\n", + ").encode(\n", + " text=\"fund amount\", color=alt.value(\"black\")\n", + ")\n", + "\n", + "overall_chart = (\n", + " alt.Chart(by_type)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"project type\",\n", + " x=\"fund amount\",\n", + " color=\"project type\",\n", + " tooltip=[\"project type\", \"fund amount\"],\n", + " )\n", + " .properties(\n", + " title=\"Overall split of SB125 allocation funds by capital/operating expenses\",\n", + " width=600,\n", + " height=300,\n", + " )\n", + ")\n", + "\n", + "overall_text = overall_chart.mark_text(\n", + " align=\"left\",\n", + " dx=0,\n", + " dy=10\n", + ").encode(\n", + " text=\"fund amount\", color=alt.value(\"black\")\n", + ")\n", + "\n", + "source_chart = (\n", + " alt.Chart(by_source)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"fund source\",\n", + " x=\"fund amount\",\n", + " # color=\"project type\",\n", + " tooltip=[\"fund source\", \"fund amount\"],\n", + " )\n", + " .properties(title=\"Allocation funds by funding source\", width=600, height=300)\n", + ")\n", + "\n", + "source_text = source_chart.mark_text(\n", + " align=\"left\",\n", + " dx=0,\n", + " dy=10\n", + ").encode(\n", + " text=\"fund amount\", color=alt.value(\"black\")\n", + ")\n", + "\n", + "\n", + "display(\n", + " overall_chart + overall_text,\n", + " stack_chart + stack_text,\n", + " source_chart + source_text,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "49ed628a-9eae-41fc-ae13-8a6238854ab9", + "metadata": { + "tags": [] + }, + "source": [ + "## mini charts of agencies, with drop down menu for RTPA.\n", + "- per katrina\n", + "- in each mini chart\n", + " - stacked bar chart of capX/opX funds, for each FY" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "fe296afc-d4f0-4a65-b59c-f6f0143177e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.FacetChart(...)" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#initial bar chart\n", + "rtpa_bar_chart_2 = alt.Chart(rtpa_group).mark_line(point=True).encode(\n", + " alt.Y(\"fund amount\"),\n", + " alt.X(\"fiscal year\"),\n", + " color=\"project type\",\n", + " #tooltip=[\"rtpa\",\"implementing agenc-y/-ies\",\"project type\", \"fund amount\", \"fiscal year\"]\n", + ")\n", + "\n", + "# create drop down\n", + "\n", + "## list of rtpas\n", + "rtpa_list = list(rtpa_group[\"rtpa\"].unique())\n", + "\n", + "## actual drop down mechanism\n", + "rtpa_dropdown = alt.binding_select(\n", + " options = rtpa_list,\n", + " name= \"Select RTPA\"\n", + ")\n", + "\n", + "rtpa_selector = alt.selection_point(fields=['rtpa'], value=\"VCTC\", bind=rtpa_dropdown)\n", + "\n", + "# data label text\n", + "rtpa_chart_text_2 = rtpa_bar_chart_2.mark_text(\n", + " align=\"center\",\n", + " dx=0,\n", + " dy=-10,\n", + " \n", + " ).encode(text=\"fund amount:N\", color=alt.value(\"black\"))\n", + "\n", + "# combine bar and text charts\n", + "rtpa_chart_combo_2 = (rtpa_bar_chart_2 + rtpa_chart_text_2).properties(\n", + " title=\"Implementing agency funding split\",\n", + " width=300,\n", + " height=150\n", + ")\n", + "\n", + "# add facets by agency\n", + "rtpa_facet_2 = rtpa_chart_combo_2.add_params(\n", + " rtpa_selector\n", + ").facet(\n", + " facet=alt.Facet(\"implementing agenc-y/-ies\", title=\"SB 125 Funding by capital/operating cost by fiscal year, by agencies in RTPAs\"), columns=3\n", + ").resolve_scale(\n", + " x=\"independent\", y=\"independent\"\n", + ").transform_filter(\n", + " rtpa_selector\n", + ")\n", + "\n", + "# render chart\n", + "rtpa_facet_2" + ] + }, + { + "cell_type": "markdown", + "id": "bdb0ecf9-a89d-42c7-bc66-9330d8374c2d", + "metadata": { + "tags": [] + }, + "source": [ + "## side-by-side charts comparing operating and capital expesnes for agencies in an RTPA\n", + "- with drop down for selectable RTPA" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "5e62b714-7875-41ca-b35b-3d379a28046f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.HConcatChart(...)" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list of RTPAs\n", + "rtpa_list = list(rtpa_group[\"rtpa\"].unique())\n", + "\n", + "#selectors\n", + "rtpa_dropdown = alt.binding_select(\n", + " options = rtpa_list,\n", + " name= \"Select RTPA\"\n", + ")\n", + "\n", + "rtpa_selector = alt.selection_point(\n", + " fields=['rtpa'], value=\"VCTC\", bind=rtpa_dropdown\n", + ")\n", + "\n", + "#opx chart\n", + "opx_chart = alt.Chart(rtpa_group[rtpa_group['project type']==\"operating\"], title=\"Operating Funds\").mark_bar().encode(\n", + " alt.Y(\"implementing agenc-y/-ies\").title(\"Agency\"),\n", + " alt.X(\"fund amount\"),\n", + " alt.YOffset(\"fiscal year\"),\n", + " alt.Color(\"implementing agenc-y/-ies\"),\n", + " tooltip=[\"fund amount\", \"fiscal year\"]\n", + ").add_params(\n", + " rtpa_selector\n", + ").transform_filter(\n", + " rtpa_selector\n", + ").properties(\n", + " width=400,\n", + " height=400,\n", + ").resolve_scale(\n", + " x=\"shared\", y=\"independent\"\n", + ")\n", + "\n", + "opx_text = opx_chart.mark_text(\n", + " align=\"left\",\n", + " dx=0,\n", + " dy=0\n", + ").encode(\n", + " text=\"fund amount\", color=alt.value(\"black\")\n", + ")\n", + "\n", + "\n", + "opx_chart_text = (opx_chart + opx_text)\n", + "\n", + "\n", + "#capx chart\n", + "capx_chart = opx_chart.properties(\n", + " data=rtpa_group[rtpa_group['project type']==\"capital\"], title=\"Capital Funds\"\n", + ").transform_filter(\n", + " rtpa_selector\n", + ")\n", + "\n", + "capx_text = capx_chart.mark_text(\n", + " align=\"left\",\n", + " dx=0,\n", + " dy=0\n", + ").encode(\n", + " text=\"fund amount\", color=alt.value(\"black\")\n", + ")\n", + "\n", + "capx_chart_text = (capx_chart + capx_text)\n", + "\n", + "opx_capx_chart = alt.hconcat(\n", + " opx_chart, capx_chart\n", + ").resolve_scale(\n", + " x=\"shared\", y=\"independent\"\n", + ").properties(\n", + " title=alt.TitleParams(\n", + " text=\"RTPA split of Operating and Capital Funds Requested by Agencies\",\n", + " subtitle=\"Separated by Fiscal Year\"\n", + " )\n", + ")\n", + "\n", + "\n", + "opx_capx_chart\n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "bd332555-b4b7-414c-a873-555523f75ecd", + "metadata": {}, + "outputs": [ + { + "ename": "SchemaValidationError", + "evalue": "Multiple errors were found.\n\nError 1: `LayerChart` has no parameter named 'mark'\n\n Existing parameter names are:\n layer data height projection usermeta \n autosize datasets name resolve view \n background description padding title width \n config encoding params transform \n\n See the help for `LayerChart` to read the full description of these parameters\n\nError 2: `LayerChart` has no parameter named 'mark'\n\n Existing parameter names are:\n layer data height projection usermeta \n autosize datasets name resolve view \n background description padding title width \n config encoding params transform \n\n See the help for `LayerChart` to read the full description of these parameters", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mSchemaValidationError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/opt/conda/lib/python3.9/site-packages/altair/vegalite/v5/api.py:961\u001b[0m, in \u001b[0;36mTopLevelMixin.to_dict\u001b[0;34m(self, validate, format, ignore, context)\u001b[0m\n\u001b[1;32m 956\u001b[0m context[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtop_level\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[1;32m 958\u001b[0m \u001b[38;5;66;03m# TopLevelMixin instance does not necessarily have to_dict defined\u001b[39;00m\n\u001b[1;32m 959\u001b[0m \u001b[38;5;66;03m# but due to how Altair is set up this should hold.\u001b[39;00m\n\u001b[1;32m 960\u001b[0m \u001b[38;5;66;03m# Too complex to type hint right now\u001b[39;00m\n\u001b[0;32m--> 961\u001b[0m vegalite_spec \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mTopLevelMixin\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_dict\u001b[49m\u001b[43m(\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[misc]\u001b[39;49;00m\n\u001b[1;32m 962\u001b[0m \u001b[43m \u001b[49m\u001b[43mvalidate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mvalidate\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mignore\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mignore\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mdict\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mcontext\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpre_transform\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 963\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 965\u001b[0m \u001b[38;5;66;03m# TODO: following entries are added after validation. Should they be validated?\u001b[39;00m\n\u001b[1;32m 966\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_top_level:\n\u001b[1;32m 967\u001b[0m \u001b[38;5;66;03m# since this is top-level we add $schema if it's missing\u001b[39;00m\n", + "File \u001b[0;32m/opt/conda/lib/python3.9/site-packages/altair/utils/schemapi.py:978\u001b[0m, in \u001b[0;36mSchemaBase.to_dict\u001b[0;34m(self, validate, ignore, context)\u001b[0m\n\u001b[1;32m 971\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvalidate(result)\n\u001b[1;32m 972\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m jsonschema\u001b[38;5;241m.\u001b[39mValidationError \u001b[38;5;28;01mas\u001b[39;00m err:\n\u001b[1;32m 973\u001b[0m \u001b[38;5;66;03m# We do not raise `from err` as else the resulting\u001b[39;00m\n\u001b[1;32m 974\u001b[0m \u001b[38;5;66;03m# traceback is very long as it contains part\u001b[39;00m\n\u001b[1;32m 975\u001b[0m \u001b[38;5;66;03m# of the Vega-Lite schema. It would also first\u001b[39;00m\n\u001b[1;32m 976\u001b[0m \u001b[38;5;66;03m# show the less helpful ValidationError instead of\u001b[39;00m\n\u001b[1;32m 977\u001b[0m \u001b[38;5;66;03m# the more user friendly SchemaValidationError\u001b[39;00m\n\u001b[0;32m--> 978\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SchemaValidationError(\u001b[38;5;28mself\u001b[39m, err) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 979\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n", + "\u001b[0;31mSchemaValidationError\u001b[0m: Multiple errors were found.\n\nError 1: `LayerChart` has no parameter named 'mark'\n\n Existing parameter names are:\n layer data height projection usermeta \n autosize datasets name resolve view \n background description padding title width \n config encoding params transform \n\n See the help for `LayerChart` to read the full description of these parameters\n\nError 2: `LayerChart` has no parameter named 'mark'\n\n Existing parameter names are:\n layer data height projection usermeta \n autosize datasets name resolve view \n background description padding title width \n config encoding params transform \n\n See the help for `LayerChart` to read the full description of these parameters" + ] + }, + { + "data": { + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "capx_chart + capx_chart.mark_text()" + ] + }, + { + "cell_type": "markdown", + "id": "7e6fc118-6ad7-4832-9c03-f32e18ce4cfe", + "metadata": { + "tags": [] + }, + "source": [ + "# Draft Aggregations" + ] + }, + { + "cell_type": "markdown", + "id": "6f4a78bb-3af1-4360-84c1-525f576bdffe", + "metadata": { + "tags": [] + }, + "source": [ + "## simple bar chart function with altair" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "643a9cf4-7cc4-45cf-a29c-7513dd18123f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "28ffc2ba-9d8e-4c5d-8be5-30e718906099", + "metadata": {}, + "outputs": [], + "source": [ + "def make_bar(data, x_axis, y_axis):\n", + " chart = (\n", + " alt.Chart(data)\n", + " .mark_bar()\n", + " .encode(\n", + " x=x_axis,\n", + " y=y_axis,\n", + " # color= color_val,\n", + " )\n", + " .properties(width=\"container\", height=400)\n", + " )\n", + " text = chart.mark_text(align=\"center\", baseline=\"middle\", dx=3).encode(\n", + " text=\"fund amount\"\n", + " )\n", + " return chart + text" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d6371a85-059d-4c5d-903f-5525ab9dd8df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "make_bar(\n", + " by_source[\n", + " by_source[\"fund source\"].isin([\"TIRCP\", \"ZETCP\", \"ZETCP (GGRF)\", \"ZETCP (PTA)\"])\n", + " ],\n", + " y_axis=\"fund amount\",\n", + " x_axis=\"fund source\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "debb4b2d-6869-4ee5-8f69-93620f40adbf", + "metadata": { + "tags": [] + }, + "source": [ + "## Split of capx/ops by RTPA" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2843981d-6e21-4e67-be9e-52bbf35c10fa", + "metadata": {}, + "outputs": [], + "source": [ + "rtpa_split = (\n", + " alt.Chart(\n", + " by_rtpa\n", + " )\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " x=alt.X(\"rtpa:N\", sort=\"-y\"),\n", + " xOffset=\"fiscal year:O\",\n", + " y=\"fund amount:Q\",\n", + " color=\"project type:N\",\n", + " tooltip=[\"rtpa\", \"project type\", \"fund amount\", \"fiscal year\"],\n", + " )\n", + " .properties(\n", + " title=\"CapX/Ops funding split by RTPA by Fiscal Year\",\n", + " width=\"container\",\n", + " height=400,\n", + " )\n", + ")\n", + "rtpa_split_2 = rtpa_split.add_params(rtpa_selector).transform_filter(rtpa_selector)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a0879a57-3f78-4b82-b4b0-2c7f5b534e42", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rtpa_split_2" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2e39f5fc-584b-4e14-a882-9311f88a947a", + "metadata": {}, + "outputs": [], + "source": [ + "metro_split = (\n", + " alt.Chart(\n", + " by_rtpa[\n", + " by_rtpa[\"rtpa\"]\n", + " == \"Los Angeles County Metropolitan Transportation Authority\"\n", + " ]\n", + " )\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " x=\"rtpa\",\n", + " xOffset=\"fiscal year\",\n", + " y=\"fund amount\",\n", + " color=\"project type\",\n", + " detail=\"fiscal year\",\n", + " tooltip=[\"rtpa\", \"project type\", \"fund amount\", \"fiscal year\"],\n", + " )\n", + " .properties(\n", + " title=\"CapX/Ops funding split for METRO by Fiscal Year\",\n", + " width=\"container\",\n", + " height=400,\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "257c9270-0b88-4704-b21d-ad227e8c5fdc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metro_split" + ] + }, + { + "cell_type": "markdown", + "id": "d5e73386-aa4a-4bb5-8945-02f7d77c6e27", + "metadata": { + "tags": [] + }, + "source": [ + "## Which RTPAs request the most/least funds?" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "651a6052-b020-46c1-aef9-3b810ed0c2f9", + "metadata": {}, + "outputs": [], + "source": [ + "# I want to see the top 10 RTPAs by total fund amount. then see their split of funds\n", + "top_list = (\n", + " by_rtpa.groupby([\"rtpa\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .sort_values(by=\"fund amount\", ascending=False)\n", + " .reset_index()[1:7]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4d32899e-0a9e-400c-a197-9d0e186bcc7d", + "metadata": {}, + "outputs": [], + "source": [ + "# I want to see the bottom 10 RTPAs by total fund amount. then see their split of funds\n", + "\n", + "bottom_list = (\n", + " by_rtpa.groupby([\"rtpa\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .sort_values(by=\"fund amount\", ascending=False)\n", + " .reset_index()\n", + " .tail(23)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "4108bad0-db05-4ccf-8174-b9a8b93be229", + "metadata": {}, + "outputs": [], + "source": [ + "# just list of the rtpa names\n", + "top_rtpa = list(top_list[\"rtpa\"])\n", + "bottom_rtpa = list(bottom_list[\"rtpa\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "f77f6b86-4558-4cf7-9b88-cad569fa1e77", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The RTPA with the most requested funds is LA METRO.\n", + "Afterwards, these RPTAs requested the most funds.\n", + " rtpa fund amount\n", + "1 OCTA 380916077\n", + "2 San Diego Metropolitan Transit System 283651605\n", + "3 RCTC 138210990\n", + "4 Kern COG 103242581\n", + "5 VCTC 98560329\n", + "6 Merced County Association of Governments (MCAG) 38377592\n", + "\n" + ] + } + ], + "source": [ + "print(\n", + " f\"\"\"\n", + "The RTPA with the most requested funds is LA METRO.\n", + "Afterwards, these RPTAs requested the most funds.\n", + "{(top_list)}\n", + "\"\"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "86ed6429-be83-426d-b2c1-576b606f7d6f", + "metadata": {}, + "outputs": [], + "source": [ + "top_15 = (\n", + " alt.Chart(by_rtpa[by_rtpa[\"rtpa\"].isin(top_rtpa)])\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " x=alt.X(\"rtpa:N\", sort=\"-y\"),\n", + " xOffset=\"fiscal year:N\",\n", + " y=\"fund amount:Q\",\n", + " color=\"project type\",\n", + " detail=\"fiscal year\",\n", + " tooltip=[\"rtpa\", \"project type\", \"fund amount\", \"fiscal year\"],\n", + " )\n", + " .properties(\n", + " title=\"CapX/Ops funding split for top 15 most funds requested by RTPA by Fiscal Year\",\n", + " width=\"container\",\n", + " height=600,\n", + " )\n", + " .resolve_scale(x=\"shared\", y=\"independent\")\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "e3404ae7-7676-46f8-912e-30e214ff48a7", + "metadata": {}, + "outputs": [], + "source": [ + "bottom_15 = (\n", + " alt.Chart(by_rtpa[by_rtpa[\"rtpa\"].isin(bottom_rtpa)])\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " x=alt.X(\"rtpa:N\", sort=\"-y\"),\n", + " xOffset=\"fiscal year:N\",\n", + " y=\"fund amount:Q\",\n", + " color=\"project type\",\n", + " detail=\"fiscal year\",\n", + " tooltip=[\"rtpa\", \"project type\", \"fund amount\", \"fiscal year\"],\n", + " )\n", + " .properties(\n", + " title=\"CapX/Ops funding split for bottom 15 most funds requested by RTPA by Fiscal Year\",\n", + " width=\"container\",\n", + " height=600,\n", + " )\n", + " .resolve_scale(x=\"shared\", y=\"independent\")\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "7a95df8f-caa1-42fd-b413-13a9036cb564", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# now, can i use this list on `by_rtpa?\n", + "top_15" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "e79828ee-efd3-4e17-a946-8cb66cded3c9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bottom_15" + ] + }, + { + "cell_type": "markdown", + "id": "3c51ea73-2d47-4f18-950b-e4bcf1a7c08d", + "metadata": { + "tags": [] + }, + "source": [ + "## Chart of each RTPA and their agencies, showing split of funds by OpX/CapX by FY" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "9fd8ca2c-0617-4057-aa44-8dff760bbea9", + "metadata": {}, + "outputs": [], + "source": [ + "# melted DF for altair\n", + "rtpa_melt = rtpa_group.melt(\n", + " id_vars=[\"rtpa\", \"implementing agenc-y/-ies\", \"fiscal year\", \"project type\"],\n", + " value_vars=\"fund amount\",\n", + " value_name=\"dollars\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "eed8d760-a8c8-4407-bf5c-e479d584fd13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2296, 8)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rtpaimplementing agenc-y/-iesprojectfund sourcecapital/operation fyfund amountproject typefiscal year
0Alpine County Transportation CommissionAlpine County Transportation CommissionTransit Facility Conversion ProjectTIRCPcapital_FY23-24360641capital23-24
1Alpine County Transportation CommissionAlpine County Transportation CommissionTransit Facility Conversion ProjectTIRCPcapital_FY23-240capital23-24
2Alpine County Transportation CommissionAlpine County Transportation CommissionTransit Facility Conversion ProjectZETCP (GGRF)capital_FY23-243616capital23-24
3Alpine County Transportation CommissionAlpine County Transportation CommissionTransit Facility Conversion ProjectZETCP (PTA)capital_FY23-243123capital23-24
4Amador County Transportation CommissionAmador TransitNoneTIRCPcapital_FY23-24100000capital23-24
\n", + "
" + ], + "text/plain": [ + " rtpa \\\n", + "0 Alpine County Transportation Commission \n", + "1 Alpine County Transportation Commission \n", + "2 Alpine County Transportation Commission \n", + "3 Alpine County Transportation Commission \n", + "4 Amador County Transportation Commission \n", + "\n", + " implementing agenc-y/-ies \\\n", + "0 Alpine County Transportation Commission \n", + "1 Alpine County Transportation Commission \n", + "2 Alpine County Transportation Commission \n", + "3 Alpine County Transportation Commission \n", + "4 Amador Transit \n", + "\n", + " project fund source capital/operation fy \\\n", + "0 Transit Facility Conversion Project TIRCP capital_FY23-24 \n", + "1 Transit Facility Conversion Project TIRCP capital_FY23-24 \n", + "2 Transit Facility Conversion Project ZETCP (GGRF) capital_FY23-24 \n", + "3 Transit Facility Conversion Project ZETCP (PTA) capital_FY23-24 \n", + "4 None TIRCP capital_FY23-24 \n", + "\n", + " fund amount project type fiscal year \n", + "0 360641 capital 23-24 \n", + "1 0 capital 23-24 \n", + "2 3616 capital 23-24 \n", + "3 3123 capital 23-24 \n", + "4 100000 capital 23-24 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(704, 5)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rtpaimplementing agenc-y/-iesproject typefiscal yearfund amount
0Alpine County Transportation CommissionAlpine County Transportation Commissioncapital23-24367380
1Alpine County Transportation CommissionAlpine County Transportation Commissioncapital24-25364575
2Alpine County Transportation CommissionAlpine County Transportation Commissioncapital25-263781
3Alpine County Transportation CommissionAlpine County Transportation Commissioncapital26-273781
4Alpine County Transportation CommissionAlpine County Transportation Commissionoperating23-240
\n", + "
" + ], + "text/plain": [ + " rtpa \\\n", + "0 Alpine County Transportation Commission \n", + "1 Alpine County Transportation Commission \n", + "2 Alpine County Transportation Commission \n", + "3 Alpine County Transportation Commission \n", + "4 Alpine County Transportation Commission \n", + "\n", + " implementing agenc-y/-ies project type fiscal year \\\n", + "0 Alpine County Transportation Commission capital 23-24 \n", + "1 Alpine County Transportation Commission capital 24-25 \n", + "2 Alpine County Transportation Commission capital 25-26 \n", + "3 Alpine County Transportation Commission capital 26-27 \n", + "4 Alpine County Transportation Commission operating 23-24 \n", + "\n", + " fund amount \n", + "0 367380 \n", + "1 364575 \n", + "2 3781 \n", + "3 3781 \n", + "4 0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(704, 6)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rtpaimplementing agenc-y/-iesfiscal yearproject typevariabledollars
0Alpine County Transportation CommissionAlpine County Transportation Commission23-24capitalfund amount367380
1Alpine County Transportation CommissionAlpine County Transportation Commission24-25capitalfund amount364575
2Alpine County Transportation CommissionAlpine County Transportation Commission25-26capitalfund amount3781
3Alpine County Transportation CommissionAlpine County Transportation Commission26-27capitalfund amount3781
4Alpine County Transportation CommissionAlpine County Transportation Commission23-24operatingfund amount0
\n", + "
" + ], + "text/plain": [ + " rtpa \\\n", + "0 Alpine County Transportation Commission \n", + "1 Alpine County Transportation Commission \n", + "2 Alpine County Transportation Commission \n", + "3 Alpine County Transportation Commission \n", + "4 Alpine County Transportation Commission \n", + "\n", + " implementing agenc-y/-ies fiscal year project type \\\n", + "0 Alpine County Transportation Commission 23-24 capital \n", + "1 Alpine County Transportation Commission 24-25 capital \n", + "2 Alpine County Transportation Commission 25-26 capital \n", + "3 Alpine County Transportation Commission 26-27 capital \n", + "4 Alpine County Transportation Commission 23-24 operating \n", + "\n", + " variable dollars \n", + "0 fund amount 367380 \n", + "1 fund amount 364575 \n", + "2 fund amount 3781 \n", + "3 fund amount 3781 \n", + "4 fund amount 0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(\n", + " all_melt.shape,\n", + " all_melt.head(),\n", + " \n", + " rtpa_group.shape,\n", + " rtpa_group.head(),\n", + " \n", + " rtpa_melt.shape,\n", + " rtpa_melt.head()\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "f574930c-9894-43f9-8475-9c673449d23a", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.FacetChart(...)" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Chart it!\n", + "\n", + "#initial bar chart\n", + "rtpa_bar_chart = alt.Chart(rtpa_melt).mark_bar().encode(\n", + " y=alt.Y(\"dollars\"),\n", + " #yOffset=\"rtpa\",\n", + " x=alt.X(\"project type\"),\n", + " xOffset=\"fiscal year\",\n", + " color=\"implementing agenc-y/-ies\",\n", + " #column=\"rtpa\",\n", + " #row=\"rtpa\",\n", + " tooltip=[\"rtpa\",\"implementing agenc-y/-ies\",\"project type\", \"dollars\", \"fiscal year\"]\n", + ")\n", + "\n", + "# data label text\n", + "rtpa_chart_text = rtpa_bar_chart.mark_text(\n", + " align=\"center\",\n", + " dx=0,\n", + " dy=-10,\n", + " \n", + " ).encode(text=\"dollars:N\", color=alt.value(\"black\"))\n", + "\n", + "# combine bar and text charts\n", + "rtpa_chart_combo = (rtpa_bar_chart + rtpa_chart_text).properties(\n", + " title=\"Implementing agency funding split\",\n", + " width=400\n", + ")\n", + "\n", + "# add facets by RTPA\n", + "rtpa_facet = rtpa_chart_combo.facet(\n", + " facet=alt.Facet(\"rtpa\", title=\"SB 125 Funding by capital/operating cost by fiscal year, by agencies in RTPAs\"), columns=2\n", + ").resolve_scale(\n", + " x=\"shared\", y=\"independent\"\n", + ")\n", + "\n", + "# render chart\n", + "rtpa_facet" + ] + }, + { + "cell_type": "markdown", + "id": "d085109e-0b1a-4133-a40c-4ea2b3c87e9a", + "metadata": { + "tags": [] + }, + "source": [ + "### line chart of just capital funds, mini charts of each RTPA" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "b1e007df-6ba3-4d28-abf3-e27be3d928b4", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# line chart, just capital\n", + "\n", + "\n", + "rtpa_line= alt.Chart(rtpa_melt[rtpa_melt[\"project type\"] == \"capital\"]).mark_line(point=True).encode(\n", + " y=alt.Y(\"dollars\"),\n", + " #yOffset=\"rtpa\",\n", + " x=alt.X(\"fiscal year\"),\n", + " #xOffset=\"project type\",\n", + " color=\"implementing agenc-y/-ies\",\n", + " #column=\"rtpa\",\n", + " #row=\"rtpa\",\n", + " tooltip=[\"rtpa\",\"implementing agenc-y/-ies\",\"project type\", \"dollars\", \"fiscal year\"]\n", + ")\n", + "\n", + "cap_line_text = rtpa_line.mark_text(\n", + " align=\"center\",\n", + " dx=0,\n", + " dy=-10,\n", + " ).encode(text=\"dollars:N\", color=alt.value(\"black\")\n", + " )\n", + "\n", + "rtpa_capital = (rtpa_line + cap_line_text).properties(\n", + " width=400\n", + ")\n", + "\n", + "rtpa_capital_facet = rtpa_capital.facet(\n", + " facet=alt.Facet(\"rtpa\", title=\"Capital funds by agencies in RTPAs, by fiscal year\"), columns=1\n", + ").resolve_scale(\n", + " x=\"independent\", y=\"independent\"\n", + ")\n", + "\n", + " \n", + "#rtpa_capital_facet" + ] + }, + { + "cell_type": "markdown", + "id": "030595b3-8a47-4bfd-bc19-5361c4f31af9", + "metadata": { + "tags": [] + }, + "source": [ + "### line just of just operating funds, mini charts of each RTPA" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "0b1e5c85-5519-4906-bda0-52bfbc17fa95", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# line chart, just operating\n", + "\n", + "\n", + "rtpa_op_line= alt.Chart(rtpa_melt[rtpa_melt[\"project type\"] == \"operating\"]).mark_line(point=True).encode(\n", + " alt.Y(\"dollars\"),\n", + " #yOffset=\"rtpa\",\n", + " alt.X(\"fiscal year\"),\n", + " #xOffset=\"project type\",\n", + " color=\"implementing agenc-y/-ies\",\n", + " #column=\"rtpa\",\n", + " #row=\"rtpa\",\n", + " tooltip=[\"rtpa\",\"implementing agenc-y/-ies\",\"project type\", \"dollars\", \"fiscal year\"]\n", + ")\n", + "\n", + "op_line_text = rtpa_op_line.mark_text(\n", + " align=\"center\",\n", + " dx=0,\n", + " dy=-10,\n", + " ).encode(text=\"dollars:N\", color=alt.value(\"black\")\n", + " )\n", + "\n", + "rtpa_operating = (rtpa_op_line + op_line_text).properties(\n", + " width=400\n", + ")\n", + "\n", + "rtpa_operating_facet = rtpa_operating.facet(\n", + " alt.Facet(\"rtpa\", title=\"Operating funds by agencies in RTPAs, by fiscal year\"), columns=1\n", + ").resolve_scale(\n", + " x=\"independent\", y=\"independent\"\n", + ")\n", + "\n", + " \n", + "#rtpa_operating_facet" + ] + }, + { + "cell_type": "markdown", + "id": "76eadca5-ffab-40b8-889d-ef3e1b926c6a", + "metadata": {}, + "source": [ + "## concat of just capital and just operating " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "d027bccc-39dd-47cc-a8d5-6024aa17ebe1", + "metadata": {}, + "outputs": [], + "source": [ + "#rtpa_capital_facet | rtpa_operating_facet" + ] + }, + { + "cell_type": "markdown", + "id": "e02df9e7-18e1-4506-9c34-5d474e75235d", + "metadata": {}, + "source": [ + "## big single chart of all agencies fund amount, same color, fading from most to least" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "75eda001-b08d-454e-95ca-6103f7609023", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.Chart(...)" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "alt.Chart(by_agency).mark_bar(size=20).encode(\n", + " alt.X(\"sum(fund amount):Q\"),\n", + " alt.YOffset(\"implementing agenc-y/-ies:N\"),\n", + " alt.Y(\"fiscal year:N\"),\n", + " #alt.Size(\"sum(fund amount):Q\"),\n", + " #alt.OpacityValue(0.4),\n", + " alt.Color(\"fund amount\", \n", + " legend=alt.Legend(orient='bottom', columns=8),\n", + " #scale=alt.Scale(scheme='blues')\n", + " ),\n", + " tooltip=[\"implementing agenc-y/-ies:N\"]\n", + " #alt.Stroke(\"sum(fund amount):Q\", ),\n", + ").properties(\n", + " title=\"Total funding amount by Transit Agencies for each Fiscal Year\",\n", + " width=\"container\",\n", + " height=600\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "28f9d144-514a-4d6c-8504-62eea0dc9394", + "metadata": { + "tags": [] + }, + "source": [ + "## RPTA to district?" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "bfc3cbbf-b1d4-4191-b546-b2b7784d6519", + "metadata": {}, + "outputs": [], + "source": [ + "# read in final_crosswalk.csv from ntd bucket\n", + "crosswalk = pd.read_excel(\"gs://calitp-analytics-data/data-analyses/sb125/fund_split/rtpa_to_county_to_district_crosswalk.xlsx\", sheet_name=\"rtpa_county_district_crosswalk\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "a1524a6e-f62c-49a8-b897-ff5fe95b42a4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(58, 3)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Index(['COUNTY', 'RTPA', 'DISTRICT'], dtype='object')" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(crosswalk.shape, crosswalk.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "5e5e3665-cb05-4b0b-acbf-e55188994b56", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
COUNTYRTPADISTRICT
0AlamedaMetropolitan Transportation Commission4
1AlpineAlpine County Local Transportation Commission10
2AmadorAmador County Transportation Commission10
3ButteButte County Association of Governments3
4CalaverasCalaveras Council of Governments10
5ColusaColusa County Transportation Commission3
6Contra CostaMetropolitan Transportation Commission4
7Del NorteDel Norte Local Transportation Commission1
8El DoradoEl Dorado County Transportation Commission3
9FresnoFresno Council of Governments6
10GlennGlenn County Transportation Commission3
11HumboldtHumboldt County Association of Governments1
12ImperialSouthern California Association of Governments11
13InyoInyo County Local Transportation Commission9
14KernKern Council of Governments6
15KingsKings County Association of Governments6
16LakeLake County/City Area Planning Council1
17LassenLassen County Transportation Commission2
18Los AngelesSouthern California Association of Governments7
19MaderaMadera County Transportation Commission6
20MarinMetropolitan Transportation Commission4
21MariposaMariposa County Local Transportation Commission10
22MendocinoMendocino Council of Governments1
23MercedMerced County Association of Governments10
24ModocModoc County Transportation Commission2
25MonoMono County Local Transportation Commission9
26MontereyTransportation Agency for Monterey County5
27NapaMetropolitan Transportation Commission4
28NevadaNevada County Transportation Commission3
29OrangeSouthern California Association of Governments12
30PlacerPlacer County Transportation Planning Agency3
31PlumasPlumas County Transportation Commission2
32RiversideSouthern California Association of Governments8
33SacramentoSacramento Area Council of Governments3
34San BenitoCouncil of San Benito County Governments5
35San BernardinoSouthern California Association of Governments8
36San DiegoSan Diego Association of Governments11
37San FranciscoMetropolitan Transportation Commission4
38San JoaquinSan Joaquin Council of Governments10
39San Luis ObispoSan Luis Obispo Council of Governments5
40San MateoMetropolitan Transportation Commission4
41Santa BarbaraSanta Barbara County Association of Governments5
42Santa ClaraMetropolitan Transportation Commission4
43Santa CruzSanta Cruz County Regional Transportation Comm...5
44ShastaShasta Regional Transportation Agency2
45SierraSierra County Local Transportation Commission3
46SiskiyouSiskiyou County Local Transportation Commission2
47SolanoMetropolitan Transportation Commission4
48SonomaMetropolitan Transportation Commission4
49StanislausStanislaus Council of Governments10
50SutterSacramento Area Council of Governments3
51TehamaTehama County Transportation Commission2
52TrinityTrinity County Transportation Commission2
53TulareTulare County Association of Governments6
54TuolumneTuolumne County Transportation Council10
55VenturaSouthern California Association of Governments7
56YoloSacramento Area Council of Governments3
57YubaSacramento Area Council of Governments3
\n", + "
" + ], + "text/plain": [ + " COUNTY RTPA \\\n", + "0 Alameda Metropolitan Transportation Commission \n", + "1 Alpine Alpine County Local Transportation Commission \n", + "2 Amador Amador County Transportation Commission \n", + "3 Butte Butte County Association of Governments \n", + "4 Calaveras Calaveras Council of Governments \n", + "5 Colusa Colusa County Transportation Commission \n", + "6 Contra Costa Metropolitan Transportation Commission \n", + "7 Del Norte Del Norte Local Transportation Commission \n", + "8 El Dorado El Dorado County Transportation Commission \n", + "9 Fresno Fresno Council of Governments \n", + "10 Glenn Glenn County Transportation Commission \n", + "11 Humboldt Humboldt County Association of Governments \n", + "12 Imperial Southern California Association of Governments \n", + "13 Inyo Inyo County Local Transportation Commission \n", + "14 Kern Kern Council of Governments \n", + "15 Kings Kings County Association of Governments \n", + "16 Lake Lake County/City Area Planning Council \n", + "17 Lassen Lassen County Transportation Commission \n", + "18 Los Angeles Southern California Association of Governments \n", + "19 Madera Madera County Transportation Commission \n", + "20 Marin Metropolitan Transportation Commission \n", + "21 Mariposa Mariposa County Local Transportation Commission \n", + "22 Mendocino Mendocino Council of Governments \n", + "23 Merced Merced County Association of Governments \n", + "24 Modoc Modoc County Transportation Commission \n", + "25 Mono Mono County Local Transportation Commission \n", + "26 Monterey Transportation Agency for Monterey County \n", + "27 Napa Metropolitan Transportation Commission \n", + "28 Nevada Nevada County Transportation Commission \n", + "29 Orange Southern California Association of Governments \n", + "30 Placer Placer County Transportation Planning Agency \n", + "31 Plumas Plumas County Transportation Commission \n", + "32 Riverside Southern California Association of Governments \n", + "33 Sacramento Sacramento Area Council of Governments \n", + "34 San Benito Council of San Benito County Governments \n", + "35 San Bernardino Southern California Association of Governments \n", + "36 San Diego San Diego Association of Governments \n", + "37 San Francisco Metropolitan Transportation Commission \n", + "38 San Joaquin San Joaquin Council of Governments \n", + "39 San Luis Obispo San Luis Obispo Council of Governments \n", + "40 San Mateo Metropolitan Transportation Commission \n", + "41 Santa Barbara Santa Barbara County Association of Governments \n", + "42 Santa Clara Metropolitan Transportation Commission \n", + "43 Santa Cruz Santa Cruz County Regional Transportation Comm... \n", + "44 Shasta Shasta Regional Transportation Agency \n", + "45 Sierra Sierra County Local Transportation Commission \n", + "46 Siskiyou Siskiyou County Local Transportation Commission \n", + "47 Solano Metropolitan Transportation Commission \n", + "48 Sonoma Metropolitan Transportation Commission \n", + "49 Stanislaus Stanislaus Council of Governments \n", + "50 Sutter Sacramento Area Council of Governments \n", + "51 Tehama Tehama County Transportation Commission \n", + "52 Trinity Trinity County Transportation Commission \n", + "53 Tulare Tulare County Association of Governments \n", + "54 Tuolumne Tuolumne County Transportation Council \n", + "55 Ventura Southern California Association of Governments \n", + "56 Yolo Sacramento Area Council of Governments \n", + "57 Yuba Sacramento Area Council of Governments \n", + "\n", + " DISTRICT \n", + "0 4 \n", + "1 10 \n", + "2 10 \n", + "3 3 \n", + "4 10 \n", + "5 3 \n", + "6 4 \n", + "7 1 \n", + "8 3 \n", + "9 6 \n", + "10 3 \n", + "11 1 \n", + "12 11 \n", + "13 9 \n", + "14 6 \n", + "15 6 \n", + "16 1 \n", + "17 2 \n", + "18 7 \n", + "19 6 \n", + "20 4 \n", + "21 10 \n", + "22 1 \n", + "23 10 \n", + "24 2 \n", + "25 9 \n", + "26 5 \n", + "27 4 \n", + "28 3 \n", + "29 12 \n", + "30 3 \n", + "31 2 \n", + "32 8 \n", + "33 3 \n", + "34 5 \n", + "35 8 \n", + "36 11 \n", + "37 4 \n", + "38 10 \n", + "39 5 \n", + "40 4 \n", + "41 5 \n", + "42 4 \n", + "43 5 \n", + "44 2 \n", + "45 3 \n", + "46 2 \n", + "47 4 \n", + "48 4 \n", + "49 10 \n", + "50 3 \n", + "51 2 \n", + "52 2 \n", + "53 6 \n", + "54 10 \n", + "55 7 \n", + "56 3 \n", + "57 3 " + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "crosswalk" + ] + }, + { + "cell_type": "markdown", + "id": "76c5c9ba-746a-4467-a25e-b99d33744e78", + "metadata": { + "tags": [] + }, + "source": [ + "## RTPA by size?\n", + "- tie in NTD ID to the agencies in the RTPAs to get VOMS, UPT?\n", + "- or by # of agencies in each RTPA?" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "728e46cf-d457-4cfc-8d11-e6edfeda554a", + "metadata": {}, + "outputs": [], + "source": [ + "ntd_id_rtpa = pd.read_csv(\"gs://calitp-analytics-data/data-analyses/ntd/ntd_id_rtpa_crosswalk.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "f3fca874-6cd1-4b1d-84b4-09a51c7850f0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(117, 6)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Index(['NTD ID', 'Legacy NTD ID', 'Agency', 'UZA Name', 'RTPA_open_data',\n", + " 'RTPA'],\n", + " dtype='object')" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(\n", + " ntd_id_rtpa.shape,\n", + " ntd_id_rtpa.columns\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "1efb1837-cc56-4199-9d1d-c0c00461667c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NTD IDLegacy NTD IDAgencyUZA NameRTPA_open_dataRTPA
26901479147City of Los AngelesLos Angeles--Long Beach--Anaheim, CASouthern California Association of GovernmentsLos Angeles County Metropolitan Transportation...
36901549154Los Angeles County Metropolitan Transportation...Los Angeles--Long Beach--Anaheim, CASouthern California Association of GovernmentsLos Angeles County Metropolitan Transportation...
\n", + "
" + ], + "text/plain": [ + " NTD ID Legacy NTD ID Agency \\\n", + "26 90147 9147 City of Los Angeles \n", + "36 90154 9154 Los Angeles County Metropolitan Transportation... \n", + "\n", + " UZA Name \\\n", + "26 Los Angeles--Long Beach--Anaheim, CA \n", + "36 Los Angeles--Long Beach--Anaheim, CA \n", + "\n", + " RTPA_open_data \\\n", + "26 Southern California Association of Governments \n", + "36 Southern California Association of Governments \n", + "\n", + " RTPA \n", + "26 Los Angeles County Metropolitan Transportation... \n", + "36 Los Angeles County Metropolitan Transportation... " + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ntd_id_rtpa[ntd_id_rtpa[\"Agency\"].str.contains(\"Los\")]" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "a49f7589-f8c1-431f-a0c6-d56eb2a455f6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Southern California Association of Governments 40\n", + "Metropolitan Transportation Commission 27\n", + "Sacramento Area Council of Governments 12\n", + "San Diego Association of Governments 8\n", + "Tulare County Association of Governments 4\n", + "Stanislaus Council of Governments 4\n", + "San Joaquin Council of Governments 4\n", + "San Luis Obispo Council of Governments 3\n", + "Kern Council of Governments 2\n", + "Santa Barbara County Association of Governments 2\n", + "Kings County Association of Governments 2\n", + "Butte County Association of Governments 2\n", + "Merced County Association of Governments 1\n", + "Tahoe Regional Planning Agency 1\n", + "Alpine County Local Transportation Commission 1\n", + "Shasta Regional Transportation Agency 1\n", + "Fresno Council of Governments 1\n", + "Santa Cruz County Regional Transportation Commission 1\n", + "Transportation Agency for Monterey County 1\n", + "Name: RTPA_open_data, dtype: int64" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ntd_id_rtpa[\"RTPA_open_data\"].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "16615b26-78d3-4c59-8fbe-27fb468abaf4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Metropolitan Transportation Commission 27\n", + "Los Angeles County Metropolitan Transportation Authority 23\n", + "Sacramento Area Council of Governments 12\n", + "San Diego Association of Governments 8\n", + "Riverside County Transportation Commission 5\n", + "Tulare County Association of Governments 4\n", + "Ventura County Transportation Commission 4\n", + "San Joaquin Council of Governments 4\n", + "Stanislaus Council of Governments 4\n", + "San Luis Obispo Council of Governments 3\n", + "San Bernardino County Transportation Authority 3\n", + "Orange County Transportation Authority 3\n", + "Kern Council of Governments 2\n", + "Santa Barbara County Association of Governments 2\n", + "Kings County Association of Governments 2\n", + "Imperial County Transportation Commission 2\n", + "Butte County Association of Governments 2\n", + "Merced County Association of Governments 1\n", + "Alpine County Transportation Commission 1\n", + "Tahoe Regional Planning Agency 1\n", + "Shasta Regional Transportation Agency 1\n", + "Fresno County Council of Governments 1\n", + "Santa Cruz County Transportation Commission 1\n", + "Transportation Agency for Monterey County 1\n", + "Name: RTPA, dtype: int64" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ntd_id_rtpa[\"RTPA\"].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fb359b5-fc7c-4b75-b905-fa09dd272412", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "697a04be-5bb1-4ea5-8897-66a7a1667fd2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sb125_analyses/sb125_fund_split_analysis/sb125_fund_split_analysis.ipynb b/sb125_analyses/sb125_fund_split_analysis/sb125_fund_split_analysis.ipynb new file mode 100644 index 000000000..d68910a72 --- /dev/null +++ b/sb125_analyses/sb125_fund_split_analysis/sb125_fund_split_analysis.ipynb @@ -0,0 +1,857 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "0608700f-8ad0-4643-bdb3-2fadbb3b8e63", + "metadata": {}, + "outputs": [], + "source": [ + "import altair as alt\n", + "import pandas as pd\n", + "from IPython.display import HTML, Image, Markdown, display, display_html\n", + "\n", + "pd.set_option(\"display.max_columns\", None)\n", + "pd.set_option(\"display.max_rows\", None)\n", + "\n", + "GCS_PATH = \"gs://calitp-analytics-data/data-analyses/sb125/fund_split/\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "215a1c4c-06fa-4f2c-805c-bed5d85cdc8c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# move filter location to the top\n", + "\n", + "display(\n", + " HTML(\n", + " \"\"\"\"\"\"\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "804e9465-b5b3-4f92-8353-19196d78ea40", + "metadata": {}, + "source": [ + "# Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "162fdcae-26fa-4527-b108-761921fd088b", + "metadata": {}, + "outputs": [], + "source": [ + "all_melt = pd.read_parquet(f\"{GCS_PATH}all_fund_requests_melt.parquet\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d9eeb04a-df02-44f2-a10a-2ae036815bc3", + "metadata": {}, + "outputs": [], + "source": [ + "# Aggregations\n", + "\n", + "by_source = (\n", + " all_melt.groupby([\"fund source\"])\n", + " .agg({\"fund amount\": \"sum\", \"rtpa\": \"nunique\"})\n", + " .reset_index()\n", + ")\n", + "\n", + "by_type = (\n", + " all_melt.groupby([\"project type\"])\n", + " .agg(\n", + " {\n", + " \"fund amount\": \"sum\",\n", + " }\n", + " )\n", + " .reset_index()\n", + ")\n", + "\n", + "by_year = (\n", + " all_melt.groupby([\"fiscal year\", \"project type\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")\n", + "\n", + "by_rtpa = (\n", + " all_melt.groupby([\"rtpa\", \"project type\", \"fiscal year\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")\n", + "\n", + "by_agency = (\n", + " all_melt.groupby([\"implementing agenc-y/-ies\", \"project type\", \"fiscal year\"])\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")\n", + "\n", + "# aggregate by rtpa, agency, project type and FY\n", + "rtpa_group = (\n", + " all_melt.groupby(\n", + " [\"rtpa\", \"implementing agenc-y/-ies\", \"project type\", \"fiscal year\"]\n", + " )\n", + " .agg({\"fund amount\": \"sum\"})\n", + " .reset_index()\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4e82c62b-a158-4756-b2e0-47019cb8cbac", + "metadata": {}, + "outputs": [], + "source": [ + "# Overall fund split bar chart\n", + "overall_chart = (\n", + " alt.Chart(by_type)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"project type\",\n", + " x=\"fund amount\",\n", + " color=\"project type\",\n", + " tooltip=[\"project type\", \"fund amount\"],\n", + " )\n", + " .properties(\n", + " title=\"Overall split of SB125 allocation funds by capital/operating expenses\",\n", + " width=600,\n", + " height=300,\n", + " )\n", + ")\n", + "\n", + "overall_text = overall_chart.mark_text(\n", + " align=\"left\",\n", + " dx=0,\n", + " dy=10,\n", + ").encode(text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "97eab190-36df-4a08-9435-b911c81e39ce", + "metadata": {}, + "outputs": [], + "source": [ + "# Stacked bar chart showing fund split by FY\n", + "stack_chart = (\n", + " alt.Chart(by_year)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"fiscal year\",\n", + " x=\"fund amount\",\n", + " color=\"project type\",\n", + " tooltip=[\"project type\", \"fund amount\"],\n", + " )\n", + " .properties(\n", + " title=\"SB125 allocation funds by capital/operating expenses, by fiscal year\",\n", + " width=600,\n", + " height=300,\n", + " )\n", + ")\n", + "\n", + "stack_text = stack_chart.mark_text(align=\"left\", dx=-10, dy=10).encode(\n", + " text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\")\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "39b9f4b8-2815-40e4-9b2b-bd13b0e65e94", + "metadata": {}, + "outputs": [], + "source": [ + "# bar chart of fund amount by sources\n", + "\n", + "source_chart = (\n", + " alt.Chart(by_source)\n", + " .mark_bar(point=True)\n", + " .encode(\n", + " y=\"fund source\",\n", + " x=\"fund amount\",\n", + " # color=\"project type\",\n", + " tooltip=[\"fund source\", \"fund amount\"],\n", + " )\n", + " .properties(title=\"Allocation funds by funding source\", width=600, height=300)\n", + ")\n", + "\n", + "source_text = source_chart.mark_text(align=\"left\", dx=0, dy=10).encode(\n", + " text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\")\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "66f10da5-a97c-40c6-bd88-64c1b67957eb", + "metadata": {}, + "outputs": [], + "source": [ + "# Faceted line chart fund split by FY, by agencies. with drop down selector of RTPA\n", + "\n", + "rtpa_bar_chart_2 = (\n", + " alt.Chart(rtpa_group)\n", + " .mark_line(point=True)\n", + " .encode(\n", + " alt.Y(\"fund amount\"),\n", + " alt.X(\"fiscal year\"),\n", + " color=\"project type\",\n", + " )\n", + ")\n", + "\n", + "# create drop down\n", + "\n", + "## list of rtpas\n", + "rtpa_list = list(rtpa_group[\"rtpa\"].unique())\n", + "\n", + "## actual drop down mechanism\n", + "rtpa_dropdown = alt.binding_select(options=rtpa_list, name=\"Select RTPA\")\n", + "\n", + "rtpa_selector = alt.selection_point(fields=[\"rtpa\"], value=\"VCTC\", bind=rtpa_dropdown)\n", + "\n", + "# data label text\n", + "rtpa_chart_text_2 = rtpa_bar_chart_2.mark_text(\n", + " align=\"center\",\n", + " dx=0,\n", + " dy=-10,\n", + ").encode(text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\"))\n", + "\n", + "# combine bar and text charts\n", + "rtpa_chart_combo_2 = (rtpa_bar_chart_2 + rtpa_chart_text_2).properties(\n", + " title=\"Implementing agency funding split\", width=300, height=150\n", + ")\n", + "\n", + "# add facets by agency\n", + "rtpa_facet_2 = (\n", + " rtpa_chart_combo_2.add_params(rtpa_selector)\n", + " .facet(\n", + " facet=alt.Facet(\n", + " \"implementing agenc-y/-ies\",\n", + " title=\"SB 125 Funding by capital/operating cost by fiscal year, by agencies in RTPAs\",\n", + " ),\n", + " columns=3,\n", + " )\n", + " .resolve_scale(x=\"independent\", y=\"independent\")\n", + " .transform_filter(rtpa_selector)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9e03714c-a33c-4f2e-b19f-162a3c50369c", + "metadata": {}, + "outputs": [], + "source": [ + "# Split chart of Funds by fund category for FY, by agency. with drop down selection for RTPA\n", + "\n", + "# list of RTPAs\n", + "rtpa_list = list(rtpa_group[\"rtpa\"].unique())\n", + "\n", + "# selectors\n", + "rtpa_dropdown = alt.binding_select(options=rtpa_list, name=\"Select RTPA\")\n", + "\n", + "rtpa_selector = alt.selection_point(fields=[\"rtpa\"], value=\"VCTC\", bind=rtpa_dropdown)\n", + "\n", + "# opx chart\n", + "opx_chart = (\n", + " alt.Chart(\n", + " rtpa_group[rtpa_group[\"project type\"] == \"operating\"], title=\"Operating Funds\"\n", + " )\n", + " .mark_bar()\n", + " .encode(\n", + " alt.Y(\"implementing agenc-y/-ies\").title(\"Agency\"),\n", + " alt.X(\"fund amount\"),\n", + " alt.YOffset(\"fiscal year\"),\n", + " alt.Color(\"implementing agenc-y/-ies\"),\n", + " tooltip=[\"fund amount\", \"fiscal year\"],\n", + " )\n", + " .add_params(rtpa_selector)\n", + " .transform_filter(rtpa_selector)\n", + " .properties(\n", + " width=400,\n", + " height=400,\n", + " )\n", + " .resolve_scale(x=\"shared\", y=\"independent\")\n", + ")\n", + "\n", + "opx_text = opx_chart.mark_text(align=\"left\", dx=0, dy=0).encode(\n", + " text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\")\n", + ")\n", + "\n", + "\n", + "opx_chart_text = opx_chart + opx_text\n", + "\n", + "\n", + "# capx chart\n", + "capx_chart = opx_chart.properties(\n", + " data=rtpa_group[rtpa_group[\"project type\"] == \"capital\"], title=\"Capital Funds\"\n", + ").transform_filter(rtpa_selector)\n", + "\n", + "capx_text = capx_chart.mark_text(align=\"left\", dx=0, dy=0).encode(\n", + " text=alt.Text(\"fund amount:Q\", format=\"$,.2f\"), color=alt.value(\"black\")\n", + ")\n", + "\n", + "capx_chart_text = capx_chart + capx_text\n", + "\n", + "\n", + "# concat capx & opx charts\n", + "opx_capx_chart = (\n", + " alt.hconcat(capx_chart, opx_chart)\n", + " .resolve_scale(x=\"shared\", y=\"independent\")\n", + " .properties(\n", + " title=alt.TitleParams(\n", + " text=\"RTPA split of Operating and Capital Funds Requested by Agencies\",\n", + " subtitle=\"Separated by Fiscal Year\",\n", + " )\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "88d3783c-2922-454a-8e0c-b1ea17f3b3f0", + "metadata": {}, + "source": [ + "## Total Split of SB125 allocation funds by capital and operating expenses\n", + "This chart shows the total dollar amount of funds all RTPAs commit to capital and operating expense for 4 state fiscal years. " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "1e1abc91-dae8-42d1-9d2b-7304c230e20c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "overall_chart + overall_text" + ] + }, + { + "cell_type": "markdown", + "id": "452cfbd6-a746-4f8b-bbb4-b4a484285af8", + "metadata": {}, + "source": [ + "## Split of SB125 allocation funds by capital and operating expenses, by state fiscal year.\n", + "Similar to the previous chart, this chart breaks down the amount of funds all RTPAs commited, by state fiscal year." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "6e245298-1b1e-4c9e-844c-ac9aac90a3b4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack_chart + stack_text" + ] + }, + { + "cell_type": "markdown", + "id": "3d41d097-00ae-44d5-89b1-9818faf29963", + "metadata": {}, + "source": [ + "## Split of SB125 Allocation Funds by Funding Source\n", + "RTPAs are required to specify the source of of their request funds, this chart shows that distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "360b8fb0-a9e2-4690-82c6-86569c8223cb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.LayerChart(...)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "source_chart + source_text" + ] + }, + { + "cell_type": "markdown", + "id": "2dacaafa-6d40-49ee-98f5-d02fa6ec7514", + "metadata": {}, + "source": [ + "## SB125 Fund Split breakdown by transit agencies\n", + "Similar to the previous charts, this chart breaks down the funding amount by capital/operating expense, and by state fiscal year.\n", + "This interactive chart can filter between different RTPAs, and will display their associated transit agencies" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "248a7f38-1bf1-4dd6-9f4e-2f142f6a215c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.FacetChart(...)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# render chart\n", + "rtpa_facet_2" + ] + }, + { + "cell_type": "markdown", + "id": "1e9c0aac-8514-4092-beb3-0a0dda83e62d", + "metadata": {}, + "source": [ + "## Side-by-Side Comparison of Capital and Operating funds\n", + "Similar to the previous chart, this charts compares operating vs capital funds for each transit agency by fiscal year.\n", + "This chart can also be filtered by RTPAs. Useful when comparing solely-capital or solely-operating funds against other transit agencies in the same RTPA." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "3c20b9bf-8e69-45db-afbf-8bc71c8be888", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "alt.HConcatChart(...)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "opx_capx_chart" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b1af33e-32ea-4941-bd55-a41ee48f32f1", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}