import streamlit as st import pandas as pd import plotly.express as px import plotly.graph_objects as go # Streamlit page setup st.set_page_config(page_title="Legislative Bill Analysis", layout="wide") st.title("Legislative Bill Analysis Dashboard") # File uploader uploaded_file = st.file_uploader("Upload Illinois_Entire_Data_Insights_Final_v2.csv", type=["csv", "xlsx"]) if uploaded_file: # Read 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!") # Preprocessing date and year df['status_date'] = pd.to_datetime(df['status_date'], errors='coerce') df['year'] = df['status_date'].dt.year # ------------------------ # Visualization 1: Yearly Bills by Intent # ------------------------ 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) # ------------------------ # Visualization 2: Animated Stance Distribution by Policy Area # ------------------------ 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) # ------------------------ # Visualization 3: Sankey Diagram - Intent → Beneficiaries → Increasing Aspects # ------------------------ 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.")