%22%22%22%0ANYC%20Congestion%20Pricing%20Impact%20Analysis%0A%0AThis%20notebook%20demonstrates%20reactive%20dataflow%20in%20exploratory%20analysis%2C%0Ausing%20NYC%20taxi%20data%20to%20explore%20the%20impact%20of%20congestion%20pricing%0Athat%20went%20into%20effect%20on%20January%205%2C%202025.%0A%0AData%3A%20NYC%20TLC%20High-Volume%20For-Hire%20Vehicle%20(HVFHS)%20trip%20records%0A%20%20%20%20%20%20Uber%2C%20Lyft%2C%20Via%20trip%20data%20with%20detailed%20pricing%20and%20fees%0A%22%22%22%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.19.5%22%0Aapp%20%3D%20marimo.App(width%3D%22full%22%2C%20app_title%3D%22NYC%20Congestion%20Pricing%20Impact%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20datetime%20import%20datetime%0A%0A%20%20%20%20import%20duckdb%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20plotly.express%20as%20px%0A%20%20%20%20import%20plotly.graph_objects%20as%20go%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20return%20datetime%2C%20duckdb%2C%20go%2C%20mo%2C%20pl%2C%20px%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%20NYC%20Congestion%20Pricing%20Impact%20Analysis%0A%0A%20%20%20%20**January%205%2C%202025**%20marked%20the%20launch%20of%20NYC's%20Congestion%20Relief%20Zone%20pricing%20%E2%80%94%0A%20%20%20%20the%20first%20major%20congestion%20charge%20in%20the%20United%20States.%0A%0A%20%20%20%20This%20interactive%20analysis%20explores%20how%20the%20policy%20affected%20rideshare%20patterns%0A%20%20%20%20using%20**22%2B%20million**%20HVFHS%20(Uber%2C%20Lyft%2C%20Via)%20trip%20records.%0A%0A%20%20%20%20%3E%20*This%20notebook%20demonstrates%20**reactive%20dataflow**%20in%20exploratory%20analysis.%0A%20%20%20%20%3E%20Change%20any%20input%20below%20and%20watch%20dependent%20computations%20update%20automatically.*%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Analysis%20Controls%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20sample_slider%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D1%2C%20stop%3D20%2C%20step%3D1%2C%20value%3D5%2C%20label%3D%22Sample%20%25%20(larger%20%3D%20slower%20but%20more%20accurate)%22%0A%20%20%20%20)%0A%0A%20%20%20%20company_select%20%3D%20mo.ui.multiselect(%0A%20%20%20%20%20%20%20%20options%3D%5B%22Uber%22%2C%20%22Lyft%22%2C%20%22Via%22%5D%2C%20value%3D%5B%22Uber%22%2C%20%22Lyft%22%5D%2C%20label%3D%22Companies%20to%20compare%22%0A%20%20%20%20)%0A%0A%20%20%20%20date_range%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Jan%202025%20only%22%3A%20%22jan_2025%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Dec%202024%20%2B%20Jan%202025%20(before%2Fafter)%22%3A%20%22dec_jan%22%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Dec%202024%20%2B%20Jan%202025%20(before%2Fafter)%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Date%20range%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.hstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Bsample_slider%2C%20mo.md(%22*Adjust%20to%20balance%20speed%20vs%20accuracy*%22)%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Bcompany_select%2C%20mo.md(%22*Select%20companies%20to%20include*%22)%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Bdate_range%2C%20mo.md(%22*Compare%20before%2Fafter%20congestion%20pricing*%22)%5D)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20justify%3D%22space-around%22%2C%0A%20%20%20%20%20%20%20%20gap%3D2%2C%0A%20%20%20%20)%0A%20%20%20%20return%20company_select%2C%20date_range%2C%20sample_slider%0A%0A%0A%40app.cell%0Adef%20_(date_range%2C%20datetime%2C%20duckdb%2C%20mo%2C%20pl%2C%20sample_slider)%3A%0A%20%20%20%20HVFHS_COMPANIES%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22HV0002%22%3A%20%22Juno%22%2C%0A%20%20%20%20%20%20%20%20%22HV0003%22%3A%20%22Uber%22%2C%0A%20%20%20%20%20%20%20%20%22HV0004%22%3A%20%22Via%22%2C%0A%20%20%20%20%20%20%20%20%22HV0005%22%3A%20%22Lyft%22%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20_sample_pct%20%3D%20sample_slider.value%0A%20%20%20%20_sample_clause%20%3D%20f%22USING%20SAMPLE%20%7B_sample_pct%7D%20PERCENT%22%20if%20_sample_pct%20%3C%20100%20else%20%22%22%0A%20%20%20%20_conn%20%3D%20duckdb.connect()%0A%0A%20%20%20%20_jan%20%3D%20_conn.execute(f%22%22%22%0A%20%20%20%20%20%20%20%20SELECT%20%0A%20%20%20%20%20%20%20%20%20%20%20%20hvfhs_license_num%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pickup_datetime%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20dropoff_datetime%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20PULocationID%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20DOLocationID%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20trip_miles%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20trip_time%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20base_passenger_fare%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tips%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20driver_pay%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20congestion_surcharge%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cbd_congestion_fee%0A%20%20%20%20%20%20%20%20FROM%20read_parquet('data%2Ffhvhv_tripdata_2025-01.parquet')%0A%20%20%20%20%20%20%20%20WHERE%20base_passenger_fare%20%3E%200%20AND%20trip_miles%20%3E%200%0A%20%20%20%20%20%20%20%20%7B_sample_clause%7D%0A%20%20%20%20%22%22%22).pl()%0A%0A%20%20%20%20if%20date_range.value%20%3D%3D%20%22dec_jan%22%3A%0A%20%20%20%20%20%20%20%20_dec%20%3D%20_conn.execute(f%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20SELECT%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20hvfhs_license_num%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pickup_datetime%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dropoff_datetime%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PULocationID%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DOLocationID%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20trip_miles%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20trip_time%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20base_passenger_fare%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tips%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20driver_pay%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20congestion_surcharge%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NULL%3A%3ADOUBLE%20as%20cbd_congestion_fee%0A%20%20%20%20%20%20%20%20%20%20%20%20FROM%20read_parquet('data%2Ffhvhv_tripdata_2024-12.parquet')%0A%20%20%20%20%20%20%20%20%20%20%20%20WHERE%20base_passenger_fare%20%3E%200%20AND%20trip_miles%20%3E%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B_sample_clause%7D%0A%20%20%20%20%20%20%20%20%22%22%22).pl()%0A%20%20%20%20%20%20%20%20trips_df%20%3D%20pl.concat(%5B_jan%2C%20_dec%5D%2C%20how%3D%22diagonal%22)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20trips_df%20%3D%20_jan%0A%0A%20%20%20%20CONGESTION_START%20%3D%20datetime(2025%2C%201%2C%205)%0A%0A%20%20%20%20trips_df%20%3D%20trips_df.with_columns(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22hvfhs_license_num%22).replace(HVFHS_COMPANIES).alias(%22company%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22pickup_datetime%22).dt.hour().alias(%22hour%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22pickup_datetime%22).dt.weekday().alias(%22weekday%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22pickup_datetime%22).dt.date().alias(%22trip_date%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(pl.col(%22pickup_datetime%22)%20%3E%3D%20pl.lit(CONGESTION_START)).alias(%22post_congestion%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(pl.col(%22cbd_congestion_fee%22).fill_null(0)%20%3E%200).alias(%22paid_cbd_fee%22)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20_period%20%3D%20%22Dec%202024%20%2B%20Jan%202025%22%20if%20date_range.value%20%3D%3D%20%22dec_jan%22%20else%20%22Jan%202025%22%0A%20%20%20%20mo.callout(%0A%20%20%20%20%20%20%20%20mo.md(f%22**Loaded%20%7Blen(trips_df)%3A%2C%7D%20trips**%20(%7B_sample_pct%7D%25%20sample)%20%E2%80%94%20%7B_period%7D%22)%2C%0A%20%20%20%20%20%20%20%20kind%3D%22success%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(trips_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Key%20Metrics%20Dashboard%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(company_select%2C%20mo%2C%20pl%2C%20trips_df)%3A%0A%20%20%20%20_selected%20%3D%20company_select.value%20if%20company_select.value%20else%20%5B%22Uber%22%2C%20%22Lyft%22%5D%0A%20%20%20%20filtered_df%20%3D%20trips_df.filter(pl.col(%22company%22).is_in(_selected))%0A%0A%20%20%20%20_total_trips%20%3D%20len(filtered_df)%0A%20%20%20%20_total_revenue%20%3D%20filtered_df%5B%22base_passenger_fare%22%5D.sum()%0A%20%20%20%20_total_cbd_fees%20%3D%20filtered_df%5B%22cbd_congestion_fee%22%5D.fill_null(0).sum()%0A%20%20%20%20_pct_with_fee%20%3D%20(%0A%20%20%20%20%20%20%20%20(filtered_df%5B%22paid_cbd_fee%22%5D.sum()%20%2F%20_total_trips%20*%20100)%20if%20_total_trips%20%3E%200%20else%200%0A%20%20%20%20)%0A%20%20%20%20_avg_fare%20%3D%20filtered_df%5B%22base_passenger_fare%22%5D.mean()%0A%20%20%20%20_avg_tip_pct%20%3D%20filtered_df%5B%22tips%22%5D.sum()%20%2F%20filtered_df%5B%22base_passenger_fare%22%5D.sum()%20*%20100%0A%0A%20%20%20%20mo.hstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%7B_total_trips%3A%2C%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Total%20Trips%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3Df%22Selected%3A%20%7B'%2C%20'.join(_selected)%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%24%7B_total_revenue%20%2F%201e6%3A.1f%7DM%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Total%20Fares%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22Base%20passenger%20fare%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%24%7B_total_cbd_fees%20%2F%201e6%3A.2f%7DM%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22CBD%20Congestion%20Fees%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22%241.50%20per%20trip%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%7B_pct_with_fee%3A.1f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Trips%20with%20CBD%20Fee%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22Entered%20congestion%20zone%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%24%7B_avg_fare%3A.2f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Avg%20Fare%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22Per%20trip%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.stat(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3Df%22%7B_avg_tip_pct%3A.1f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Tip%20Rate%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20caption%3D%22Tips%20%2F%20Fare%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20justify%3D%22space-around%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(filtered_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Before%20vs%20After%3A%20January%205%2C%202025%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(date_range%2C%20datetime%2C%20filtered_df%2C%20go%2C%20mo%2C%20pl)%3A%0A%20%20%20%20if%20date_range.value%20!%3D%20%22dec_jan%22%3A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.callout(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Select%20**Dec%202024%20%2B%20Jan%202025**%20in%20controls%20above%20to%20see%20before%2Fafter%20comparison%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20kind%3D%22warn%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20_daily%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20filtered_df.group_by(%22trip_date%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.len().alias(%22trips%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22base_passenger_fare%22).mean().alias(%22avg_fare%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22paid_cbd_fee%22).mean().alias(%22pct_with_fee%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.sort(%22trip_date%22)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_daily%20%3D%20go.Figure()%0A%0A%20%20%20%20%20%20%20%20fig_daily.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3D_daily%5B%22trip_date%22%5D.to_list()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D_daily%5B%22trips%22%5D.to_list()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%2Bmarkers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Daily%20Trips%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%233b82f6%22%2C%20width%3D2)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(size%3D4)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_daily.add_vline(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Ddatetime(2025%2C%201%2C%205)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line_dash%3D%22dash%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line_color%3D%22red%22%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_daily.add_annotation(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Ddatetime(2025%2C%201%2C%205)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20yref%3D%22paper%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D%22Congestion%20Pricing%20Starts%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20showarrow%3DFalse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20yanchor%3D%22bottom%22%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_daily.update_layout(%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Daily%20Trip%20Volume%20%E2%80%94%20Before%20and%20After%20Congestion%20Pricing%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20xaxis_title%3D%22Date%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20yaxis_title%3D%22Number%20of%20Trips%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3D400%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DFalse%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.ui.plotly(fig_daily)%0A%0A%20%20%20%20_output%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(date_range%2C%20filtered_df%2C%20mo%2C%20pl%2C%20px)%3A%0A%20%20%20%20if%20date_range.value%20%3D%3D%20%22dec_jan%22%3A%0A%20%20%20%20%20%20%20%20_comparison%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20filtered_df.group_by(%22post_congestion%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.len().alias(%22trips%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22base_passenger_fare%22).mean().alias(%22avg_fare%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22trip_miles%22).mean().alias(%22avg_distance%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(pl.col(%22tips%22)%20%2F%20pl.col(%22base_passenger_fare%22)).mean().alias(%22tip_rate%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.when(pl.col(%22post_congestion%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22After%20(Jan%205%2B)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.otherwise(pl.lit(%22Before%20(Dec%2FEarly%20Jan)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.alias(%22period%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.sort(%22post_congestion%22)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_compare%20%3D%20px.bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20_comparison.to_pandas()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D%22period%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5B%22avg_fare%22%2C%20%22avg_distance%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20barmode%3D%22group%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Average%20Fare%20and%20Distance%3A%20Before%20vs%20After%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color_discrete_sequence%3D%5B%22%233b82f6%22%2C%20%22%2310b981%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20labels%3D%7B%22value%22%3A%20%22Amount%22%2C%20%22variable%22%3A%20%22Metric%22%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fig_compare.update_layout(template%3D%22plotly_white%22%2C%20height%3D350)%0A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.ui.plotly(fig_compare)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.md(%22%22)%0A%0A%20%20%20%20_output%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Market%20Share%20by%20Company%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(filtered_df%2C%20mo%2C%20pl%2C%20px)%3A%0A%20%20%20%20_market_share%20%3D%20(%0A%20%20%20%20%20%20%20%20filtered_df.group_by(%22company%22)%0A%20%20%20%20%20%20%20%20.agg(pl.len().alias(%22trips%22))%0A%20%20%20%20%20%20%20%20.with_columns((pl.col(%22trips%22)%20%2F%20pl.col(%22trips%22).sum()%20*%20100).alias(%22share%22))%0A%20%20%20%20%20%20%20%20.sort(%22trips%22%2C%20descending%3DTrue)%0A%20%20%20%20)%0A%0A%20%20%20%20fig_market%20%3D%20px.pie(%0A%20%20%20%20%20%20%20%20_market_share.to_pandas()%2C%0A%20%20%20%20%20%20%20%20values%3D%22trips%22%2C%0A%20%20%20%20%20%20%20%20names%3D%22company%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Trip%20Volume%20by%20Company%22%2C%0A%20%20%20%20%20%20%20%20color_discrete_sequence%3Dpx.colors.qualitative.Set2%2C%0A%20%20%20%20%20%20%20%20hole%3D0.4%2C%0A%20%20%20%20)%0A%20%20%20%20fig_market.update_traces(textposition%3D%22inside%22%2C%20textinfo%3D%22percent%2Blabel%22)%0A%20%20%20%20fig_market.update_layout(template%3D%22plotly_white%22%2C%20height%3D400)%0A%0A%20%20%20%20mo.hstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.ui.plotly(fig_market)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22%23%23%23%20Market%20Share%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_market_share.select(%5B%22company%22%2C%20%22trips%22%2C%20%22share%22%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Hourly%20Demand%20Patterns%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(filtered_df%2C%20mo%2C%20pl%2C%20px)%3A%0A%20%20%20%20_hourly%20%3D%20(%0A%20%20%20%20%20%20%20%20filtered_df.group_by(%5B%22hour%22%2C%20%22company%22%5D)%0A%20%20%20%20%20%20%20%20.agg(pl.len().alias(%22trips%22))%0A%20%20%20%20%20%20%20%20.sort(%5B%22company%22%2C%20%22hour%22%5D)%0A%20%20%20%20)%0A%0A%20%20%20%20fig_hourly%20%3D%20px.line(%0A%20%20%20%20%20%20%20%20_hourly.to_pandas()%2C%0A%20%20%20%20%20%20%20%20x%3D%22hour%22%2C%0A%20%20%20%20%20%20%20%20y%3D%22trips%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22company%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Trips%20by%20Hour%20of%20Day%22%2C%0A%20%20%20%20%20%20%20%20markers%3DTrue%2C%0A%20%20%20%20%20%20%20%20color_discrete_sequence%3Dpx.colors.qualitative.Set2%2C%0A%20%20%20%20)%0A%20%20%20%20fig_hourly.update_layout(%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D400%2C%0A%20%20%20%20%20%20%20%20xaxis%3Ddict(tickmode%3D%22linear%22%2C%20dtick%3D2)%2C%0A%20%20%20%20%20%20%20%20xaxis_title%3D%22Hour%20of%20Day%22%2C%0A%20%20%20%20%20%20%20%20yaxis_title%3D%22Number%20of%20Trips%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.ui.plotly(fig_hourly)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Congestion%20Fee%20Impact%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(filtered_df%2C%20mo%2C%20pl%2C%20px)%3A%0A%20%20%20%20_cbd_trips%20%3D%20filtered_df.filter(%0A%20%20%20%20%20%20%20%20(pl.col(%22post_congestion%22)%20%3D%3D%20True)%20%26%20(pl.col(%22cbd_congestion_fee%22).is_not_null())%0A%20%20%20%20)%0A%0A%20%20%20%20if%20len(_cbd_trips)%20%3E%200%3A%0A%20%20%20%20%20%20%20%20_cbd_analysis%20%3D%20_cbd_trips.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20(pl.col(%22cbd_congestion_fee%22)%20%2F%20pl.col(%22base_passenger_fare%22)%20*%20100).alias(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fee_pct_of_fare%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20_by_distance%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20_cbd_analysis.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.when(pl.col(%22trip_miles%22)%20%3C%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22Short%20(%3C2%20mi)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.when(pl.col(%22trip_miles%22)%20%3C%205)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22Medium%20(2-5%20mi)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.when(pl.col(%22trip_miles%22)%20%3C%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.then(pl.lit(%22Long%20(5-10%20mi)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.otherwise(pl.lit(%22Very%20Long%20(10%2B%20mi)%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.alias(%22distance_bucket%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20.group_by(%22distance_bucket%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.agg(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.len().alias(%22trips%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22fee_pct_of_fare%22).mean().alias(%22avg_fee_pct%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pl.col(%22base_passenger_fare%22).mean().alias(%22avg_fare%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20fig_fee%20%3D%20px.bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20_by_distance.to_pandas()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D%22distance_bucket%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%22avg_fee_pct%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22CBD%20Fee%20as%20%25%20of%20Fare%20(by%20Trip%20Distance)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22avg_fee_pct%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color_continuous_scale%3D%22Reds%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20labels%3D%7B%22avg_fee_pct%22%3A%20%22Fee%20%25%20of%20Fare%22%2C%20%22distance_bucket%22%3A%20%22Trip%20Distance%22%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fig_fee.update_layout(template%3D%22plotly_white%22%2C%20height%3D400)%0A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.callout(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20**Key%20Finding**%3A%20The%20%241.50%20CBD%20congestion%20fee%20is%20**regressive**%20%E2%80%94%20%0A%20%20%20%20it%20represents%20a%20larger%20percentage%20of%20short%20trips%20than%20long%20trips.%0A%0A%20%20%20%20-%20Short%20trips%20(%3C2%20mi)%3A%20Fee%20is%20~5-8%25%20of%20fare%0A%20%20%20%20-%20Long%20trips%20(10%2B%20mi)%3A%20Fee%20is%20%3C2%25%20of%20fare%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind%3D%22info%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.ui.plotly(fig_fee)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20_output%20%3D%20mo.callout(mo.md(%22No%20CBD%20fee%20data%20available%20in%20current%20selection%22)%2C%20kind%3D%22warn%22)%0A%0A%20%20%20%20_output%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
7917fcfe2e4815e6b333a4000cde4937