-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
new file: .DS_Store new file: .ignore/ContributionsList (3).xls new file: .ignore/ContributionsList (4).xls new file: .ignore/ContributionsList.xls new file: .ignore/ContributionsList10.xls new file: .ignore/ContributionsList11.xls new file: .ignore/ContributionsList12.xls new file: .ignore/ContributionsList13.xls new file: .ignore/ContributionsList14.xls new file: .ignore/ContributionsList15.xls new file: .ignore/ContributionsList16.xls new file: .ignore/ContributionsList17.xls new file: .ignore/ContributionsList6.xls new file: .ignore/ContributionsList7.xls new file: .ignore/ContributionsList8.xls new file: .ignore/ContributionsList9.xls new file: .ignore/Untitled.ipynb new file: .ignore/developercrossreference.xls new file: .ipynb_checkpoints/Untitled-checkpoint.ipynb new file: Home.py new file: __pycache__/db_load.cpython-39.pyc new file: __pycache__/functions.cpython-39.pyc new file: __pycache__/sqlite.cpython-39.pyc new file: combined.jpeg new file: contributions.db new file: modules/.DS_Store new file: modules/__pycache__/db_load.cpython-39.pyc new file: modules/__pycache__/functions.cpython-39.pyc new file: modules/db_load.py new file: modules/functions.py new file: pages/1_Overview.py new file: pages/2_Analysis.py new file: pages/3_Figures.py new file: style/style.css
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import streamlit as st | ||
|
||
st.title('Howard County Local Election Campaign Finance') | ||
st.write( | ||
""" | ||
This website presents campaign finance data for Howard County candidates. It includes all | ||
contribution data, since 2006, of all candidates who have participated in county council and | ||
county executive races. It will be updated with new candidates over time. | ||
This page provides a visual analysis of all-time campaign contributions for | ||
candidates running for the County Council and County Executive. | ||
""" | ||
) | ||
st.markdown(""" | ||
[Click Here](https://data.howardcountymd.gov/DataExplorer/Search.aspx?Application=CouncilMember) | ||
to navigate to the county website to find your Councilmember then pick the **District** and **Filing Period** | ||
to examine from the left sidebar. | ||
""") | ||
|
||
st.write('__________________') | ||
|
||
|
||
st.markdown(""" | ||
The entities and individuals classified as developer contributions closely aligns with the classification | ||
in the [No Developer Pledge](https://www.hocopledge.com/candidate-signing/). The process to identify the | ||
entities entails establishing connections based on local groups that deal with zoning and land use, looking | ||
at Maryland Corporate and LLC registration info, looking up reported addresses, reviewing campaign contributions | ||
for other candidates, and public testimony and affidavit. Please use the contact form to share your thoughts on the | ||
list and how it may be improved. | ||
This list will be updated over time. | ||
""") | ||
|
||
st.header(":mailbox: Share your thoughts here.") | ||
|
||
contact_form = """ | ||
<form action="https://formsubmit.co/[email protected]" method="POST"> | ||
<input type="hidden" name="_captcha" value="false"> | ||
<input type="text" name="name" placeholder="Your name" required> | ||
<input type="email" name="email" placeholder="Your email" required> | ||
<textarea name="message" placeholder="Your message here"></textarea> | ||
<button type="submit">Send</button> | ||
</form> | ||
""" | ||
|
||
st.markdown(contact_form, unsafe_allow_html=True) | ||
|
||
# Use Local CSS File | ||
def local_css(file_name): | ||
with open(file_name) as f: | ||
st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) | ||
|
||
|
||
local_css("style/style.css") | ||
|
||
hide_st_style = """ | ||
<style> | ||
#MainMenu {visibility: hidden;} | ||
footer {visibility: hidden;} | ||
header {visibility: hidden;} | ||
</style> | ||
""" | ||
st.markdown(hide_st_style, unsafe_allow_html=True) | ||
|
||
# plot_data = st.sidebar.checkbox('Show Plots for Selected Criteria', value=True) | ||
|
||
# if plot_data: | ||
|
||
# plots = ['Developer Percent Contribution','Top N Contributions', 'By Filing Period'] | ||
# picked_plot = st.sidebar.selectbox('Pick a Plot', plots) | ||
# #st.write(f'{len(picked_plot)}') | ||
# if picked_plot == plots[0]: | ||
# if developer: | ||
# try: | ||
# # st.write('Select the "Display Developer Contributions" checkbox') | ||
# data_set=['Developer Donations', 'Remaining'] | ||
# percent_dev = df_master[mask]['Contribution Amount'].sum()/df_master[base_mask]['Contribution Amount'].sum() | ||
# values = [percent_dev, 1-percent_dev] | ||
# fig = px.pie(df_master['Contribution Amount'], values=values, names=data_set) | ||
# st.caption('Percent share of contributions from developers. Note that some candidates\ | ||
# participate in public financing or did not file for the selected criteria.') | ||
# display = st.plotly_chart(fig) | ||
# except ValueError: | ||
# st.markdown('### Data does not exist for selected criteria.') | ||
# st.code('Try a different filing period.') | ||
# else: | ||
# st.markdown('Select the **Display Developer Contributions Only** checkbox') | ||
# elif picked_plot == plots[1]: | ||
# n = st.sidebar.slider('How Many Contributions?:', | ||
# min_value = 10, | ||
# max_value = 40) | ||
# try: | ||
# table_cols = df_grouped_for_plot.reset_index().sort_values(by=['Total Contribution'], ascending = False).head(n) | ||
# candidate_names(candidates, table_cols, 'Receiving Committee') | ||
# fig = px.bar(table_cols, x=table_cols['Contributor Name'], y=table_cols['Total Contribution'],color=table_cols['Candidate Name']) | ||
# display = st.plotly_chart(fig) | ||
# except ValueError: | ||
# st.markdown('### Data does not exist for selected criteria.') | ||
# st.code('Try a different filing period.') | ||
# elif picked_plot == plots[2]: | ||
# try: | ||
# if bar_mask: | ||
# df_master_bar = df_master[developer_filter] | ||
# else: | ||
# df_master_bar = df_master | ||
|
||
# contribution_by_filing_period = df_master_bar.groupby(['Candidate Name','Filing Period']) | ||
# contribution_by_filing_period=contribution_by_filing_period.agg( | ||
# TotalContribution =('Contribution Amount','sum')).reset_index() | ||
# fig = px.bar(contribution_by_filing_period, x = contribution_by_filing_period['Filing Period'], | ||
# y=contribution_by_filing_period['TotalContribution'],color=contribution_by_filing_period['Candidate Name']) | ||
# display = st.plotly_chart(fig) | ||
# except ValueError: | ||
# st.markdown('### Data does not exist for selected criteria.') | ||
# st.code('Try a different filing period.') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import pandas as pd | ||
import sqlite3 as db | ||
import datetime as dt | ||
import streamlit as st | ||
|
||
conn = db.connect('contributions.db', check_same_thread=False) | ||
c = conn.cursor() | ||
sql_query = """SELECT name FROM sqlite_master | ||
WHERE type='table';""" | ||
|
||
# executing our sql query | ||
c.execute(sql_query) | ||
|
||
# printing all tables list | ||
list = c.fetchall() | ||
|
||
list.remove(('developercrossreference',)) | ||
|
||
def contributions(name): | ||
table = pd.read_sql_query(f'select * from {name}',conn) | ||
table['Contribution Date'] = pd.to_datetime(table['Contribution Date']).dt.date | ||
table['Contribution Amount'] = table['Contribution Amount'].astype(float) | ||
table = table.drop(columns='index') | ||
return table | ||
|
||
candidate_data_frame = {} | ||
|
||
@st.cache_data | ||
def load(): | ||
raw_table = pd.DataFrame() | ||
for n in list: | ||
raw_table = pd.concat([raw_table, contributions(n[0])]) | ||
raw_table = raw_table.reset_index().drop(columns='index') | ||
return raw_table | ||
@st.cache_data | ||
def developer(): | ||
table1 = pd.read_sql_query(f'select * from developercrossreference',conn) | ||
table1 = table1.drop(columns='index') | ||
return table1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import pandas as pd | ||
|
||
|
||
def group_by_filing_period(table, args): | ||
|
||
group_by_filing_period = table.set_index(args).groupby(level=[i for i in range(len(args))]).sum(numeric_only=True) | ||
|
||
return group_by_filing_period |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import streamlit as st | ||
import pandas as pd | ||
import sqlite3 as db | ||
import plotly.express as px | ||
import datetime as dt | ||
|
||
st.markdown('### Fundraising data for all candidates for county council and county executive since 2006.') | ||
|
||
conn = db.connect('contributions.db', check_same_thread=False) | ||
sqlite_select_query = """SELECT name FROM sqlite_master WHERE type='table';""" | ||
c = conn.cursor() | ||
c.execute(sqlite_select_query) | ||
records = c.fetchall() | ||
|
||
def contributions(name): | ||
table = pd.read_sql_query(f'select * from {name}',conn) | ||
table['Contribution Date'] = pd.to_datetime(table['Contribution Date']).dt.date | ||
table['Contribution Amount'] = table['Contribution Amount'].astype(float) | ||
table = table.drop(columns='index') | ||
return table | ||
|
||
candidate_data_frame = {} | ||
|
||
def load(): | ||
raw_table = pd.DataFrame() | ||
for n in records: | ||
if n[0] == 'developercrossreference': | ||
continue | ||
raw_table = pd.concat([raw_table, contributions(n[0])]) | ||
raw_table = raw_table.reset_index().drop(columns='index') | ||
return raw_table | ||
|
||
raw_table = load() | ||
|
||
office_options = st.sidebar.selectbox('Office', raw_table['Office'].unique()) | ||
mask = raw_table['Office']==office_options | ||
filtered_by_office = raw_table[mask] | ||
|
||
district_options= st.sidebar.selectbox('Councilmanic District', filtered_by_office['Councilmanic District'].unique()) | ||
mask1 = filtered_by_office['Councilmanic District'] == district_options | ||
filtered_by_district = filtered_by_office[mask1] | ||
|
||
|
||
name_options = st.sidebar.selectbox('Candidate Name', filtered_by_district['Candidate Name'].unique()) | ||
mask2 = filtered_by_district['Candidate Name'] == name_options | ||
|
||
filtered_by_name = filtered_by_district[mask2] | ||
|
||
start_date = filtered_by_name['Contribution Date'].min() | ||
end_date = filtered_by_name['Contribution Date'].max() | ||
value = [start_date, end_date] | ||
|
||
val = st.date_input(label='Date Range: ', value=value, help="The start and end date time") | ||
|
||
try: | ||
start_date, end_date = val | ||
except ValueError: | ||
st.error("You must pick a start and end date") | ||
st.stop() | ||
|
||
mask3 = (filtered_by_name['Contribution Date']>=val[0]) & (filtered_by_name['Contribution Date'] <=val[1]) | ||
filtered_by_date = filtered_by_name[mask3] | ||
filtered_by_date = filtered_by_date.sort_values(['Receiving Committee','Contribution Date']).reset_index().drop(columns='index') | ||
|
||
filing_options = filtered_by_date['Filing Period'].unique().tolist() | ||
filing_options.insert(0, 'All Filing Periods') | ||
|
||
select_filing_period = st.selectbox('Select Filing Period',options=filing_options) | ||
|
||
if select_filing_period =='All Filing Periods': | ||
filtered_by_filing_period = filtered_by_date | ||
else: | ||
mask4 = filtered_by_date['Filing Period']==select_filing_period | ||
filtered_by_filing_period = filtered_by_date[mask4] | ||
|
||
# Filter the dataframe based on the selected date range and categories | ||
|
||
candidate_options = filtered_by_filing_period['Receiving Committee'].unique() | ||
select_candidates = st.multiselect('Select Campaign Committees',options=candidate_options, default=candidate_options) | ||
mask5 = filtered_by_date['Receiving Committee'].isin(select_candidates) | ||
|
||
filtered_by_candidate = filtered_by_filing_period[mask5] | ||
col1, col2 = st.columns(2) | ||
|
||
with col1: | ||
st.metric('Total Number of Contributions:',filtered_by_candidate['Contribution Amount'].count()) | ||
|
||
with col2: | ||
st.metric('Total Money Raised:','${:,.2f}'.format(filtered_by_candidate['Contribution Amount'].sum())) | ||
|
||
|
||
excluded_row = ['Receiving Committee', 'Filing Period','Office','Fundtype','Candidate Name', 'Councilmanic District'] | ||
# Display the filtered dataframe | ||
st.write(filtered_by_candidate.loc[:,~filtered_by_candidate.columns.isin(excluded_row)]) | ||
|
||
st.markdown(""" | ||
<style> | ||
div[data-testid="metric-container"] { | ||
background-color: rgba(28, 131, 225, 0.1); | ||
border: 1px solid rgba(28, 131, 225, 0.1); | ||
padding: 5% 5% 5% 10%; | ||
border-radius: 5px; | ||
color: rgb(30, 103, 119); | ||
overflow-wrap: break-word; | ||
} | ||
/* breakline for metric text */ | ||
div[data-testid="metric-container"] > label[data-testid="stMetricLabel"] > div { | ||
overflow-wrap: break-word; | ||
white-space: break-spaces; | ||
color: red; font-size: 200% !important; | ||
} | ||
</style> | ||
""" | ||
, unsafe_allow_html=True) |