| import streamlit as st |
| import pandas as pd |
| import plotly.express as px |
| import plotly.graph_objects as go |
|
|
| |
| st.set_page_config(page_title="Legislative Bill Analysis", layout="wide") |
| st.title("Legislative Bill Analysis Dashboard") |
|
|
| |
| uploaded_file = st.file_uploader("Upload Illinois_Entire_Data_Insights_Final_v2.csv", type=["csv", "xlsx"]) |
|
|
| if uploaded_file: |
| |
| if uploaded_file.name.endswith('.csv'): |
| df = pd.read_csv(uploaded_file) |
| else: |
| df = pd.read_excel(uploaded_file) |
|
|
| st.success("File uploaded and read successfully!") |
|
|
| |
| df['status_date'] = pd.to_datetime(df['status_date'], errors='coerce') |
| df['year'] = df['status_date'].dt.year |
|
|
| |
| |
| |
| st.header(" Bills Over Time by Intent") |
| yearly_intent_counts = df.groupby(['year', 'intent_standardized']).size().reset_index(name='bill_count') |
|
|
| fig1 = px.bar( |
| yearly_intent_counts, |
| x='year', |
| y='bill_count', |
| color='intent_standardized', |
| title='Bills Over Time by Intent', |
| labels={'year': 'Year', 'bill_count': 'Number of Bills', 'intent_standardized': 'Intent'}, |
| barmode='group', |
| height=500, |
| color_discrete_sequence=px.colors.qualitative.Set2 |
| ) |
| fig1.update_layout( |
| xaxis=dict(tickangle=0), |
| legend_title_text='Intent', |
| plot_bgcolor='white', |
| paper_bgcolor='white', |
| font=dict(color='black'), |
| title_font=dict(size=20) |
| ) |
| st.plotly_chart(fig1, use_container_width=True) |
|
|
| |
| |
| |
| st.header("Stance Distribution Across Policy Areas (Animated by Year)") |
| grouped = df.groupby(['year', 'policy_impact_areas_standardized', 'stance_standardized']).size().reset_index(name='count') |
|
|
| fig2 = px.bar( |
| grouped, |
| x='count', |
| y='policy_impact_areas_standardized', |
| color='stance_standardized', |
| orientation='h', |
| animation_frame='year', |
| title='Stance Distribution Across Policy Areas (Animated by Year)', |
| labels={ |
| 'count': 'Number of Bills', |
| 'policy_impact_areas_standardized': 'Policy Area', |
| 'stance_standardized': 'Stance' |
| }, |
| height=600, |
| color_discrete_sequence=px.colors.qualitative.Set2 |
| ) |
| fig2.update_layout( |
| legend_title='Stance', |
| xaxis_title='Number of Bills', |
| yaxis_title='Policy Area', |
| plot_bgcolor='white', |
| paper_bgcolor='white', |
| font=dict(color='black'), |
| title_font=dict(size=20), |
| margin=dict(t=60, l=150) |
| ) |
| st.plotly_chart(fig2, use_container_width=True) |
|
|
| |
| |
| |
| st.header("π Top Intent β Beneficiaries β Increasing Aspect Flows (Sankey)") |
|
|
| def shorten(text, max_len=35): |
| return text if len(text) <= max_len else text[:max_len] + "..." |
|
|
| sankey_data = df[['intent_standardized', 'intended_beneficiaries_standardized', 'increasing_aspects_standardized']].dropna() |
| path_counts = ( |
| sankey_data.groupby(['intent_standardized', 'intended_beneficiaries_standardized', 'increasing_aspects_standardized']) |
| .size() |
| .reset_index(name='count') |
| .sort_values(by='count', ascending=False) |
| ) |
|
|
| TOP_N = 15 |
| filtered_paths = path_counts.head(TOP_N) |
| unique_labels = pd.unique(filtered_paths[['intent_standardized', 'intended_beneficiaries_standardized', 'increasing_aspects_standardized']].values.ravel()) |
| short_labels = [shorten(label) for label in unique_labels] |
| label_to_index = {label: i for i, label in enumerate(unique_labels)} |
| label_to_short = dict(zip(unique_labels, short_labels)) |
|
|
| sources = list(filtered_paths['intent_standardized'].map(label_to_index)) |
| targets = list(filtered_paths['intended_beneficiaries_standardized'].map(label_to_index)) |
| values = list(filtered_paths['count']) |
|
|
| sources += list(filtered_paths['intended_beneficiaries_standardized'].map(label_to_index)) |
| targets += list(filtered_paths['increasing_aspects_standardized'].map(label_to_index)) |
| values += list(filtered_paths['count']) |
|
|
| fig3 = go.Figure(data=[go.Sankey( |
| arrangement="snap", |
| node=dict( |
| pad=25, |
| thickness=20, |
| line=dict(color="black", width=0.3), |
| label=[label_to_short[label] for label in unique_labels], |
| color="lightsteelblue" |
| ), |
| link=dict( |
| source=sources, |
| target=targets, |
| value=values, |
| color="rgba(150,150,150,0.4)" |
| ) |
| )]) |
|
|
| fig3.update_layout( |
| title_text="Top Intent β Beneficiaries β Increasing Aspect Flows", |
| font_size=12, |
| height=600, |
| margin=dict(l=50, r=50, t=80, b=30) |
| ) |
| st.plotly_chart(fig3, use_container_width=True) |
|
|
| else: |
| st.info(" Please upload a dataset file to view the visualizations.") |
|
|