Phase 1 project prototype
This commit is contained in:
parent
29215e2bd2
commit
2c9ae1c312
29 changed files with 2967 additions and 22 deletions
97
src/admin_analytics/dashboard/pages/staffing.py
Normal file
97
src/admin_analytics/dashboard/pages/staffing.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"""Page 3: Staffing & Enrollment."""
|
||||
|
||||
import duckdb
|
||||
from dash import html, dcc
|
||||
import plotly.graph_objects as go
|
||||
|
||||
from admin_analytics.dashboard.queries import (
|
||||
query_staff_composition,
|
||||
query_student_staff_ratios,
|
||||
query_growth_index,
|
||||
)
|
||||
|
||||
_NO_DATA = html.Div(
|
||||
"No IPEDS staff data loaded. Run: admin-analytics ingest ipeds",
|
||||
style={"textAlign": "center", "padding": "40px", "color": "#888"},
|
||||
)
|
||||
|
||||
|
||||
def layout(conn: duckdb.DuckDBPyConnection):
|
||||
staff_df = query_staff_composition(conn)
|
||||
if staff_df.height == 0:
|
||||
return _NO_DATA
|
||||
|
||||
staff_pd = staff_df.to_pandas()
|
||||
|
||||
# Staff composition stacked area
|
||||
comp_fig = go.Figure()
|
||||
for col, label, color in [
|
||||
("faculty_total", "Faculty", "#00539F"),
|
||||
("management_total", "Management", "#E07A5F"),
|
||||
("other_staff", "Other Staff", "#7FB069"),
|
||||
]:
|
||||
comp_fig.add_trace(go.Scatter(
|
||||
x=staff_pd["year"], y=staff_pd[col],
|
||||
mode="lines", name=label,
|
||||
stackgroup="one",
|
||||
line={"color": color},
|
||||
))
|
||||
comp_fig.update_layout(
|
||||
title="Staff Composition Over Time",
|
||||
xaxis_title="Year", yaxis_title="Headcount",
|
||||
template="plotly_white", height=420,
|
||||
)
|
||||
|
||||
# Student-to-staff ratios
|
||||
ratio_df = query_student_staff_ratios(conn)
|
||||
ratio_fig = go.Figure()
|
||||
if ratio_df.height > 0:
|
||||
ratio_pd = ratio_df.to_pandas()
|
||||
ratio_fig.add_trace(go.Scatter(
|
||||
x=ratio_pd["year"], y=ratio_pd["students_per_staff"],
|
||||
mode="lines+markers", name="Students per Staff",
|
||||
line={"color": "#00539F"},
|
||||
))
|
||||
ratio_fig.add_trace(go.Scatter(
|
||||
x=ratio_pd["year"], y=ratio_pd["students_per_faculty"],
|
||||
mode="lines+markers", name="Students per Faculty",
|
||||
line={"color": "#FFD200"},
|
||||
))
|
||||
ratio_fig.update_layout(
|
||||
title="Student-to-Staff Ratios",
|
||||
xaxis_title="Year", yaxis_title="Ratio",
|
||||
template="plotly_white", height=380,
|
||||
)
|
||||
|
||||
# Growth index
|
||||
growth_df = query_growth_index(conn)
|
||||
growth_fig = go.Figure()
|
||||
if growth_df.height > 0:
|
||||
growth_pd = growth_df.to_pandas()
|
||||
growth_fig.add_trace(go.Scatter(
|
||||
x=growth_pd["year"], y=growth_pd["mgmt_index"],
|
||||
mode="lines+markers", name="Management Growth",
|
||||
line={"color": "#E07A5F"},
|
||||
))
|
||||
growth_fig.add_trace(go.Scatter(
|
||||
x=growth_pd["year"], y=growth_pd["enrollment_index"],
|
||||
mode="lines+markers", name="Enrollment Growth",
|
||||
line={"color": "#00539F"},
|
||||
))
|
||||
growth_fig.add_hline(y=100, line_dash="dot", line_color="#ccc")
|
||||
growth_fig.update_layout(
|
||||
title="Management vs Enrollment Growth (Indexed, Base Year = 100)",
|
||||
xaxis_title="Year", yaxis_title="Index",
|
||||
template="plotly_white", height=380,
|
||||
)
|
||||
|
||||
return html.Div([
|
||||
dcc.Graph(figure=comp_fig),
|
||||
html.Div(
|
||||
[
|
||||
html.Div(dcc.Graph(figure=ratio_fig), style={"flex": "1"}),
|
||||
html.Div(dcc.Graph(figure=growth_fig), style={"flex": "1"}),
|
||||
],
|
||||
style={"display": "flex", "gap": "16px"},
|
||||
),
|
||||
])
|
||||
Loading…
Add table
Add a link
Reference in a new issue