Download app.py from Legislation/Legislation_Data_Dashboard: direct link, hf CLI and curl.
- Browser
- Download file 5.28 kB
-
https://huggingface.co/spaces/Legislation/Legislation_Data_Dashboard/resolve/main/app.py
- Command line
-
hf download hf://spaces/Legislation/Legislation_Data_Dashboard/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Legislation/Legislation_Data_Dashboard/resolve/main/app.py
5.28 kB
| 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.") | |