"""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"}, ), ])