File size: 11,227 Bytes
a9fc515
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b7f7cc7
a9fc515
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
"""Overview / dashboard home page."""
from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

import pandas as pd
import streamlit as st

from utils import data_loader as dl
from utils.plotting import montana_with_hospitals
from utils.styling import callout, page_setup, section, INITIATIVE_COLOR


page_setup("Overview")

# --------------------------------------------------------------------------
# Brand strip + headline
# --------------------------------------------------------------------------
st.markdown(
    "<div class='rhtp-brandbar'>"
    "<div>"
    "<div class='kicker'>Montana DPHHS &middot; Rural Health Transformation Program</div>"
    "<h1>RHTP Evaluation Dashboard</h1>"
    "<div class='subtitle'>A fixed research plan, layered, causal evaluation of all five "
    "RHTP initiatives across Montana's 56 counties and 65 hospitals.</div>"
    "</div></div>",
    unsafe_allow_html=True,
)

# --------------------------------------------------------------------------
# Top-line stats
# --------------------------------------------------------------------------
counties = dl.counties()
hosp = dl.hospitals()
fq = dl.facility_quarter_ops()
coe = dl.coe_implementation()
wf = dl.workforce_panel()

c1, c2, c3, c4, c5 = st.columns(5)
with c1:
    st.metric("Hospitals tracked", f"{len(hosp):,}",
              help="Critical Access, PPS, Tertiary, Sole Community, and Tribal/IHS facilities.")
with c2:
    rural = (counties["rurality"] != "Urban").sum()
    st.metric("Rural / tribal counties", f"{rural} / {len(counties)}")
with c3:
    treated = (coe["coe_cohort"] != "never").sum()
    st.metric("CoE-enrolled facilities", f"{treated} / {len(hosp)}",
              delta=f"{treated/len(hosp):.0%}", delta_color="off")
with c4:
    latest = fq.sort_values(["year", "quarter"]).groupby("facility_id").tail(1)
    neg_margin = (latest["operating_margin_pct"] < 0).sum()
    st.metric("Negative-margin hospitals (latest Q)",
              f"{neg_margin} / {len(latest)}",
              delta=f"{neg_margin/len(latest):.0%}", delta_color="off")
with c5:
    pop = counties["population_2020"].sum()
    st.metric("Population covered", f"{pop:,.0f}")

# --------------------------------------------------------------------------
# Evaluation framing
# --------------------------------------------------------------------------
section("Evaluation framing",
        "How this dashboard is structured and what each page answers.")

c1, c2 = st.columns([3, 2])
with c1:
    st.markdown(
        "Every initiative page follows the same three-section pattern:\n\n"
        "1. **Initiative scope** β€” KPOs (with baseline + FY2031 target + level) "
        "and treatment / intervention inputs, so you know exactly what each "
        "page is trying to move and which levers it pulls.\n"
        "2. **Data Explorer** β€” interactive panel of the underlying outcomes "
        "and treatments.\n"
        "3. **Models** β€” the exact econometric specification(s) for that "
        "initiative, with adjustable knobs so a stakeholder can see *how* an "
        "estimate is constructed.\n"
        "4. **Was the initiative successful?** β€” direction, magnitude, "
        "precision, timing, consistency, and dose-response, applied to the "
        "model's outputs.\n\n"
        "This structure mirrors the **RHTP_models_full** modeling playbook."
    )
    callout(
        "<strong>About the data.</strong> Every file in <code>/data/</code> is "
        "<strong>synthetic</strong>, generated by <code>scripts/generate_data.py</code> "
        "to mirror the schema and units of the real source feeds β€” CMS Hospital "
        "Cost Reports, Montana Medicaid claims, HRSA workforce data, BRFSS, "
        "Big Sky Care Connect HIE rosters, and the MT DPHHS facility / county "
        "files. Treatment effects are baked in deterministically (with realistic "
        "noise), so the models <em>should</em> recover positive effects on the "
        "outcomes the RHTP plan is designed to move. To switch the dashboard to "
        "live data, drop a real file with the same name and column schema into "
        "<code>/data/</code> β€” no code changes needed.",
        kind="info",
    )

with c2:
    st.markdown("##### Five initiatives")
    initiatives = [
        ("01", "Workforce"),
        ("02", "Facility Sustainability"),
        ("03", "Innovative Care & Payment"),
        ("04", "Community Prevention"),
        ("05", "Technology & Data"),
    ]
    for num, name in initiatives:
        color = INITIATIVE_COLOR[int(num)]
        st.markdown(
            f"<div class='rhtp-card' style='border-left:5px solid {color};'>"
            f"<div style='display:flex; align-items:baseline; gap:10px;'>"
            f"<span style='color:{color}; font-weight:700; "
            f"letter-spacing:0.06em; font-size:0.78rem;'>INITIATIVE {num}</span>"
            f"<h4 style='margin:0;'>{name}</h4></div>"
            f"<div style='color:#9CA3AF; font-size:0.85rem; margin-top:4px;'>"
            f"open via the sidebar</div></div>",
            unsafe_allow_html=True,
        )

# --------------------------------------------------------------------------
# Map
# --------------------------------------------------------------------------
section("Montana hospitals by county",
        "Hover any county for population and rurality; hover any marker for the "
        "hospital name, facility type, staffed beds, ownership, and CCN.")

ctrl_col, _ = st.columns([3, 1])
with ctrl_col:
    facility_types = sorted(hosp["facility_type"].unique().tolist())
    selected_types = st.multiselect(
        "Facility types to display",
        options=facility_types,
        default=facility_types,
        help="Filter the map markers. The choropleth always shows all 56 counties.",
    )

if not selected_types:
    selected_types = facility_types

fig = montana_with_hospitals(counties, hosp, facility_type_filter=selected_types,
                             height=620)
st.plotly_chart(fig, use_container_width=True, config={"displaylogo": False})

fcount = hosp[hosp["facility_type"].isin(selected_types)]
beds_total = int(fcount["staffed_beds"].sum())
m1, m2, m3, m4 = st.columns(4)
with m1:
    st.metric("Facilities shown", f"{len(fcount):,}")
with m2:
    st.metric("Staffed beds", f"{beds_total:,}")
with m3:
    cah = (fcount["facility_type"] == "CAH").sum()
    st.metric("Critical Access (CAH)", f"{cah:,}")
with m4:
    tribal = (fcount["facility_type"] == "Tribal/IHS").sum()
    st.metric("Tribal / IHS", f"{tribal:,}")

# --------------------------------------------------------------------------
# Hospital roster
# --------------------------------------------------------------------------
section("Hospital roster",
        "Schema mirrors the CMS Provider of Services file plus the MT DPHHS "
        "facility roster β€” drop in real data with the same columns to switch "
        "from synthetic to live.")

with st.expander("Show the full roster"):
    st.dataframe(
        hosp[[
            "facility_id", "facility_name", "county_name", "facility_type",
            "ownership", "staffed_beds", "ccn", "rurality", "region",
        ]].sort_values(["facility_type", "facility_name"]),
        hide_index=True, use_container_width=True,
    )

# --------------------------------------------------------------------------
# Latest workforce snapshot
# --------------------------------------------------------------------------
section("County baseline panel β€” workforce snapshot (latest year)",
        "Where Montana's rural workforce stood at the close of the most recent "
        "year of available data. Use this view alongside the Workforce page to "
        "judge what 'meaningfully improved' means relative to baseline.")

latest_year = int(wf["year"].max())
wf_latest = wf[wf["year"] == latest_year].merge(
    counties[["fips", "county_name", "rurality", "region"]], on="fips")

c1, c2 = st.columns(2)
with c1:
    metric_choice = st.selectbox(
        "Metric to display",
        options=[
            ("np_per_100k", "Nurse practitioners per 100k"),
            ("md_per_100k", "Physicians per 100k"),
            ("rn_per_100k", "Registered nurses per 100k"),
            ("turnover_rate", "Annual provider turnover rate"),
            ("provider_mh_score", "Provider mental health score (1-10)"),
        ],
        format_func=lambda x: x[1],
    )
    metric_col, metric_label = metric_choice
with c2:
    rurality_filter = st.multiselect(
        "Show counties by rurality",
        options=["Urban", "Rural", "Tribal"],
        default=["Urban", "Rural", "Tribal"],
    )

display_df = wf_latest[wf_latest["rurality"].isin(rurality_filter)].copy()
display_df = display_df[["county_name", "rurality", "region", metric_col,
                         "population", "medicaid_share", "unemployment_pct"]]
display_df = display_df.rename(columns={
    "county_name": "County", "rurality": "Type", "region": "Region",
    metric_col: metric_label, "population": "Population",
    "medicaid_share": "Medicaid share", "unemployment_pct": "Unemployment %",
})
display_df = display_df.sort_values(metric_label,
                                    ascending=metric_col == "turnover_rate")
st.dataframe(display_df, hide_index=True, use_container_width=True, height=320)

# --------------------------------------------------------------------------
# Reading guide
# --------------------------------------------------------------------------
section("How a stakeholder should read this evaluation")

c1, c2, c3 = st.columns(3)
with c1:
    st.markdown(
        "**Step 1 β€” Implementation.** Did the intervention actually roll out? "
        "Each initiative page begins by showing the cumulative reach of the "
        "intervention in question. Weak downstream effects are hard to "
        "interpret if the intervention barely reached anyone."
    )
with c2:
    st.markdown(
        "**Step 2 β€” Effect.** Did treated units improve more than comparable "
        "untreated ones? The models on each page are causal: they use county "
        "or facility fixed effects to absorb stable differences, year fixed "
        "effects to absorb statewide trends, and event-study structure to test "
        "*when* effects appear."
    )
with c3:
    st.markdown(
        "**Step 3 β€” Synthesis.** Across all five initiatives, did Montana move "
        "materially closer to its FY2031 rural health goals on workforce, "
        "access, quality, financial sustainability, and tech/data capacity? "
        "**That is the program-level success question β€” and it is a synthesis "
        "of many imperfect estimates, not a single p-value.**"
    )

st.markdown("<br/>", unsafe_allow_html=True)
callout(
    "Built as a working draft of the RHTP evaluation tool. Every visualization, model, "
    "and statistical test is fully reproducible from the file at "
    "<code>/scripts/generate_data.py</code>. Replace files in <code>/data/</code> "
    "with real source data of the same schema to switch this dashboard from "
    "synthetic to live.",
    kind="info", title="About this dashboard",
)