To upload files, please first save the app
import streamlit as st
import pandas as pd
import plotly.express as px
from us_state_abbrev import us_state_abbrev
# DATA SOURCE: https://www.bbc.com/news/articles/cvglg3klrpzo
def standardize_state_names(state):
"""Standardize state names to full names."""
# First, check if it's already a full name
abbrev = us_state_abbrev[state]
return abbrev
@st.cache_data
def load_data():
df = pd.read_csv('./result.csv')
df['Candidate'] = df['Candidate'].str.replace(' wins', '', regex=False)
df['Party'] = df['Party'].str.replace(' (incumbent)', '', regex=False)
df['Votes'] = df['Votes'].str.replace(',', '').astype(int)
df['Electoral votes'] = df['Electoral votes'].astype(int)
# Calculate voting power
state_data = df.groupby('State').agg({
'Votes': 'sum',
'Electoral votes': 'sum'
}).reset_index()
state_data.loc[state_data['State'] == 'Nevada', 'Electoral votes'] = 6
state_data.loc[state_data['State'] == 'Arizona', 'Electoral votes'] = 11
state_data['Voting Power'] = (state_data['Electoral votes'] / state_data['Votes']) * 1000000 # Multiply by 1M for readability
# Get winners and reset index to ensure proper alignment
winners = df.loc[df.groupby('State')['Votes'].idxmax()].reset_index(drop=True)
# Merge winners into state_data
state_data = state_data.merge(
winners[['State', 'Party']],
on='State',
how='left'
)
# Rename Party column to Winner
state_data = state_data.rename(columns={'Party': 'Winner'})
return df, state_data
def percentage_to_float(value):
return float(value.strip('%')) / 100 if isinstance(value, str) else value
def create_vote_share_map(state_data, filter_type, selected_filter, color_scheme):
fig = px.choropleth(
state_data,
locations='State_abv',
locationmode='USA-states',
color='Vote share',
hover_name='State',
hover_data={'Vote share': ':.1%', 'Votes': ':,', 'Electoral votes': True},
color_continuous_scale=color_scheme,
scope='usa',
labels={'Vote share': 'Vote Share'}
)
fig.update_coloraxes(colorbar_tickformat='.0%')
fig.update_layout(
title_text=f'Election Results - {filter_type}: {selected_filter}',
geo_scope='usa',
)
return fig
def create_voting_power_map(state_data):
fig = px.choropleth(
state_data,
locations='State_abv',
locationmode='USA-states',
color='Voting Power',
hover_name='State',
hover_data={
'Voting Power': ':.4f',
'Electoral votes': True,
'Votes': ':,',
},
color_continuous_scale='Viridis',
scope='usa',
labels={'Voting Power': 'Electoral Votes per Million Voters'}
)
fig.update_layout(
title_text='State Voting Power (Electoral Votes per Million Voters)',
geo_scope='usa',
)
return fig
def main():
st.title('US Election Results')
# Load the data
df, state_data = load_data()
# Get unique parties and candidates
parties = df['Party'].unique()
candidates = df['Candidate'].unique()
# Create sidebar for user input
st.sidebar.header('Filter Options')
# Add visualization type selector
viz_type = st.sidebar.radio('Visualization:', ('Vote Share', 'Voting Power'))
if viz_type == 'Vote Share':
filter_type = st.sidebar.radio('Filter by:', ('Party', 'Candidate'))
if filter_type == 'Party':
selected_filter = st.sidebar.selectbox('Select a party:', parties)
filtered_df = df[df['Party'] == selected_filter]
else:
selected_filter = st.sidebar.selectbox('Select a candidate:', candidates)
filtered_df = df[df['Candidate'] == selected_filter]
# Process vote share data
filtered_df['Vote share'] = filtered_df['Vote share'].apply(percentage_to_float)
state_data = filtered_df.groupby('State').agg({
'Votes': 'sum',
'Vote share': 'mean',
'Electoral votes': 'sum'
}).reset_index()
# Standardize state names
state_data['State_abv'] = state_data['State'].apply(standardize_state_names)
state_data['Vote share %'] = state_data['Vote share'].apply(lambda x: f"{x:.1%}")
# Determine color scheme
color = "Greys"
if filter_type == 'Party':
if selected_filter == "Republican":
color = "Reds"
if selected_filter == "Democrat":
color = "Blues"
else:
if selected_filter == "Donald Trump":
color = "Reds"
if selected_filter == "Kamala Harris":
color = "Blues"
# Create and display vote share map
fig = create_vote_share_map(state_data, filter_type, selected_filter, color)
st.plotly_chart(fig)
else: # Voting Power visualization
# Prepare state data for voting power visualization
state_data['State_abv'] = state_data['State'].apply(standardize_state_names)
# Create and display voting power map
fig = create_voting_power_map(state_data)
st.plotly_chart(fig)
# Add explanation of voting power
st.info("""
**Understanding Voting Power**
The voting power metric shows how much electoral influence each voter has in different states.
It is calculated as: (Electoral Votes / Total Votes) × 1,000,000
- Higher values (lighter colors) indicate states where each voter has more electoral influence
- Lower values (darker colors) indicate states where each voter has less electoral influence
""")
# Display the data table
st.subheader('Detailed Results')
display_cols = ['State', 'Votes', 'Electoral votes']
if viz_type == 'Vote Share':
display_cols.append('Vote share %')
st.dataframe(state_data[display_cols])
if __name__ == '__main__':
main()
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?