Spaces:
Sleeping
Sleeping
File size: 6,296 Bytes
cf54ce1 e985fcd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
import streamlit as st
import pandas as pd
import altair as alt
from vega_datasets import data
import us
# -------------------------------------------------
# PAGE CONFIG + TITLE
# -------------------------------------------------
st.set_page_config(page_title="University Donor Dashboard", layout="wide")
st.title("University Donor Dashboard")
alt.data_transformers.enable("default", max_rows=None)
# -------------------------------------------------
# DATA
# -------------------------------------------------
@st.cache_data
def load_data():
df = pd.read_csv("university-donations.csv")
df["Gift Date"] = pd.to_datetime(
df["Gift Date"],
format="%m/%d/%y",
errors="coerce"
)
df["Year"] = df["Gift Date"].dt.year.astype("Int64")
df["YearMonth"] = df["Gift Date"].dt.to_period("M").astype(str)
# 2-letter state → FIPS
state_id = {s.abbr: int(s.fips) for s in us.states.STATES}
df["state_fips"] = df["State"].map(state_id)
return df
df = load_data()
st.write("Loaded rows:", len(df)) # quick sanity check
# -------------------------------------------------
# SIDEBAR FILTERS
# -------------------------------------------------
st.sidebar.header("Filters")
col_opts = ["All"] + sorted(df["College"].dropna().unique())
mot_opts = ["All"] + sorted(df["Gift Allocation"].dropna().unique())
col_pick = st.sidebar.selectbox("College", col_opts, index=0)
mot_pick = st.sidebar.selectbox("Motivation (Gift Allocation)", mot_opts, index=0)
st.sidebar.write(f"Selected College: {col_pick}")
st.sidebar.write(f"Selected Motivation: {mot_pick}")
mask = pd.Series(True, index=df.index)
if col_pick != "All":
mask &= df["College"] == col_pick
if mot_pick != "All":
mask &= df["Gift Allocation"] == mot_pick
df_filt = df[mask]
# Check if the filtered dataframe is empty
if df_filt.empty:
st.warning("No data matches the selected filters.")
else:
# -------------------------------------------------
# SELECTIONS (empty="all" to show all data initially)
# -------------------------------------------------
state_select = alt.selection_point(fields=["state_fips"], toggle=False, empty="all")
brush = alt.selection_interval(encodings=["x"], empty="all")
subcategory_select = alt.selection_point(
fields=["Allocation Subcategory"],
toggle="event.shiftKey",
empty="all"
)
# -------------------------------------------------
# CHOROPLETH MAP
# -------------------------------------------------
state_totals = (
df_filt.groupby("state_fips", as_index=False)
.agg(Gift_Amount_sum=("Gift Amount", "sum"),
Gift_Count=("Gift Amount", "count"))
)
states = alt.topo_feature(data.us_10m.url, "states")
map_chart = (
alt.Chart(states)
.mark_geoshape(stroke="white", strokeWidth=0.5)
.encode(
color=alt.condition(
state_select,
alt.Color("Gift_Amount_sum:Q",
scale=alt.Scale(scheme="blues"),
title="Total Gifts ($)"),
alt.value("lightgray")
),
tooltip=[
alt.Tooltip("Gift_Amount_sum:Q", title="Total Gifts ($)", format=",.0f"),
alt.Tooltip("Gift_Count:Q", title="# Gifts")
]
)
.transform_lookup(
lookup="id",
from_=alt.LookupData(state_totals,
key="state_fips",
fields=["Gift_Amount_sum", "Gift_Count"])
)
.add_params(state_select)
.project(type="albersUsa")
.properties(width=380, height=250)
)
# -------------------------------------------------
# LINE – GIFTS BY YEAR
# -------------------------------------------------
line_chart = (
alt.Chart(df_filt)
.transform_filter(state_select)
.mark_line(point=True)
.encode(
x=alt.X("Year:O", sort="ascending"),
y=alt.Y("sum(Gift Amount):Q", title="Total Gifts ($)"),
tooltip=[
alt.Tooltip("Year:O", title="Year"),
alt.Tooltip("sum(Gift Amount):Q", title="Total Gifts ($)", format=",.0f")
]
)
.add_params(state_select, brush)
.properties(width=380, height=250)
)
# -------------------------------------------------
# BAR – TOTAL BY COLLEGE
# -------------------------------------------------
bar_college = (
alt.Chart(df_filt)
.transform_filter(state_select)
.mark_bar()
.encode(
y=alt.Y("College:N", sort="-x", title="College"),
x=alt.X("sum(Gift Amount):Q", title="Total Gifts ($)"),
tooltip=[
alt.Tooltip("College:N", title="College"),
alt.Tooltip("sum(Gift Amount):Q", title="Total Gifts ($)", format=",.0f")
]
)
.add_params(state_select)
.properties(width=380, height=400)
)
# -------------------------------------------------
# BAR – TOTAL BY SUB-CATEGORY
# -------------------------------------------------
bar_sub = (
alt.Chart(df_filt)
.transform_filter(state_select)
.transform_filter(brush)
.mark_bar()
.encode(
y=alt.Y("Allocation Subcategory:N", sort="-x", title="Allocation Sub-category"),
x=alt.X("sum(Gift Amount):Q", title="Total Gifts ($)"),
color=alt.condition(subcategory_select, alt.value("#1f77b4"), alt.value("lightgray")),
tooltip=[
alt.Tooltip("Allocation Subcategory:N", title="Sub-category"),
alt.Tooltip("sum(Gift Amount):Q", title="Total Gifts ($)", format=",.0f")
]
)
.add_params(state_select, brush, subcategory_select)
.properties(width=380, height=400)
)
# -------------------------------------------------
# LAYOUT
# -------------------------------------------------
upper = alt.hconcat(map_chart, line_chart).resolve_scale(color="independent")
lower = alt.hconcat(bar_college, bar_sub)
st.altair_chart(alt.vconcat(upper, lower), use_container_width=True) |