Spaces:
Runtime error
Runtime error
Upload 2 files
Browse files
app.py
CHANGED
|
@@ -7,7 +7,7 @@ from sklearn import datasets
|
|
| 7 |
from sklearn.preprocessing import StandardScaler
|
| 8 |
from sklearn.decomposition import PCA
|
| 9 |
import plotly.graph_objects as go
|
| 10 |
-
import
|
| 11 |
|
| 12 |
FEATURE_LABELS = {
|
| 13 |
"age": "Leeftijd",
|
|
@@ -24,31 +24,6 @@ FEATURE_LABELS = {
|
|
| 24 |
}
|
| 25 |
LABEL_TO_KEY = {v: k for k, v in FEATURE_LABELS.items()}
|
| 26 |
|
| 27 |
-
MEDICAL_MD = """
|
| 28 |
-
### Medisch nut
|
| 29 |
-
|
| 30 |
-
**Wat zien we hier?**
|
| 31 |
-
Ik heb een bestaande, anonieme gezondheidsdataset gebruikt die speciaal beschikbaar is gemaakt voor onderzoek en studie. In deze gegevens staan metingen van een grote groep patiënten, zoals **bloedwaarden, BMI, cholesterol en bloedsuiker**.
|
| 32 |
-
|
| 33 |
-
Zo'n enorme berg cijfers is voor artsen en ziekenhuizen bijna niet in één keer te overzien. Het is gewoon te veel om met het blote oog patronen uit te halen.
|
| 34 |
-
|
| 35 |
-
**Daar komt kunstmatige intelligentie om de hoek kijken.**
|
| 36 |
-
Met deze techniek (PCA) kan de computer de data slim samenvatten en patronen zichtbaar maken. Dit programma dat ik heb ontworpen laat live zien hoe die samenvatting werkt.
|
| 37 |
-
|
| 38 |
-
- Elke punt is één patiënt.
|
| 39 |
-
- De kleur laat zien hoe hoog of laag een bepaalde meting is (standaard: BMI).
|
| 40 |
-
- De pijlen laten zien welke metingen het meeste invloed hebben.
|
| 41 |
-
- Links bovenin kun je kiezen welke meting je als uitgangspunt wilt nemen.
|
| 42 |
-
|
| 43 |
-
**En wat heb je hieraan?**
|
| 44 |
-
In de praktijk gebruiken artsen en onderzoekers zo'n plot om patronen en verbanden te ontdekken. 👉 Het is dus niet alleen een mooi plaatje, maar echt een manier om grote hoeveelheden data sneller en slimmer te begrijpen.
|
| 45 |
-
|
| 46 |
-
Met AI kunnen we patronen vinden die je met het blote oog nooit zou zien. Dat maakt dit niet alleen een mooie visualisatie, maar ook een knap stukje technologie met échte waarde voor onderzoek en zorg.
|
| 47 |
-
|
| 48 |
-
**Speel zelf de onderzoeker!**
|
| 49 |
-
Doe alsof je een arts bent en kies links bovenin een waarde, bijvoorbeeld **cholesterol**, **leeftijd** of **geslacht**. Klik daarna op *Update visualisaties* en ontdek je eigen patronen in de data.
|
| 50 |
-
"""
|
| 51 |
-
|
| 52 |
def load_diabetes_df():
|
| 53 |
d = datasets.load_diabetes()
|
| 54 |
X = pd.DataFrame(d.data, columns=d.feature_names)
|
|
@@ -57,293 +32,101 @@ def load_diabetes_df():
|
|
| 57 |
df["target"] = y
|
| 58 |
return df
|
| 59 |
|
| 60 |
-
def
|
| 61 |
-
keys = ["bmi","bp","s1","s2","s3","s4","s5","s6"]
|
| 62 |
-
rows = []
|
| 63 |
-
for k in keys:
|
| 64 |
-
vals = df[k].dropna().values
|
| 65 |
-
if vals.size == 0:
|
| 66 |
-
continue
|
| 67 |
-
mean = float(vals.mean())
|
| 68 |
-
pct_above = float((vals > 0).mean() * 100.0) # standardized: 0 ~ mean
|
| 69 |
-
pct_below = float((vals < 0).mean() * 100.0)
|
| 70 |
-
rows.append({
|
| 71 |
-
"Meting": FEATURE_LABELS.get(k, k),
|
| 72 |
-
"Gemiddelde (gestandaardiseerd)": round(mean, 3),
|
| 73 |
-
"% boven gemiddelde": round(pct_above, 1),
|
| 74 |
-
"% onder gemiddelde": round(pct_below, 1),
|
| 75 |
-
})
|
| 76 |
-
table = pd.DataFrame(rows)
|
| 77 |
-
note = ("Let op: waarden in deze dataset zijn **gestandaardiseerd**. "
|
| 78 |
-
"`0` betekent ongeveer het **algemene gemiddelde**. "
|
| 79 |
-
"Positief = hoger dan gemiddeld, negatief = lager dan gemiddeld.")
|
| 80 |
-
return table, note
|
| 81 |
-
|
| 82 |
-
def compute_top_correlations(df: pd.DataFrame, top_n: int = 6):
|
| 83 |
-
feats = [c for c in df.columns if c != "target"]
|
| 84 |
-
corr = pd.DataFrame(df[feats]).corr()
|
| 85 |
-
pairs = []
|
| 86 |
-
for i, a in enumerate(feats):
|
| 87 |
-
for j, b in enumerate(feats):
|
| 88 |
-
if j <= i:
|
| 89 |
-
continue
|
| 90 |
-
pairs.append({
|
| 91 |
-
"Combinatie": f"{FEATURE_LABELS.get(a,a)} ↔ {FEATURE_LABELS.get(b,b)}",
|
| 92 |
-
"Correlatie": corr.loc[a, b]
|
| 93 |
-
})
|
| 94 |
-
out = pd.DataFrame(pairs)
|
| 95 |
-
out["Sterkte (|r|)"] = out["Correlatie"].abs()
|
| 96 |
-
out = out.sort_values("Sterkte (|r|)", ascending=False).head(top_n).reset_index(drop=True)
|
| 97 |
-
out["Correlatie"] = out["Correlatie"].round(3)
|
| 98 |
-
out["Sterkte (|r|)"] = out["Sterkte (|r|)"].round(3)
|
| 99 |
-
return out[["Combinatie", "Correlatie", "Sterkte (|r|)"]]
|
| 100 |
-
|
| 101 |
-
def compute_pca(df: pd.DataFrame, n_components: int, standardize: bool):
|
| 102 |
feats = [c for c in df.columns if c != "target"]
|
| 103 |
X = df[feats].values
|
| 104 |
if standardize:
|
| 105 |
-
scaler = StandardScaler(
|
| 106 |
Xs = scaler.fit_transform(X)
|
| 107 |
else:
|
| 108 |
Xs = X
|
| 109 |
-
pca = PCA(n_components=min(
|
| 110 |
Z = pca.fit_transform(Xs)
|
| 111 |
loadings = pca.components_.T
|
| 112 |
expl = pca.explained_variance_ratio_
|
| 113 |
return feats, Xs, Z, loadings, expl
|
| 114 |
|
| 115 |
-
def build_biplot(Z, loadings, feats,
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
return fig
|
| 133 |
|
| 134 |
def build_variance_plot(expl):
|
| 135 |
-
fig = plt.figure(
|
| 136 |
ax = fig.add_subplot(111)
|
| 137 |
-
xs = np.arange(1,
|
| 138 |
-
ax.bar(xs, expl,
|
| 139 |
-
ax.
|
| 140 |
-
|
| 141 |
-
ax.set_xlabel("Principal Component")
|
| 142 |
-
ax.set_ylabel("Explained variance ratio")
|
| 143 |
-
ax.set_title("Uitlegvariantie per component (balken) + cumulatief (lijn)")
|
| 144 |
-
ax.grid(True, linestyle=":", linewidth=0.6)
|
| 145 |
-
plt.tight_layout()
|
| 146 |
return fig
|
| 147 |
|
| 148 |
-
def
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
)
|
| 155 |
-
fig.update_layout(
|
| 156 |
-
title="PCA 3D — PC1 · PC2 · PC3",
|
| 157 |
-
scene=dict(xaxis_title="PC1", yaxis_title="PC2", zaxis_title="PC3"),
|
| 158 |
-
margin=dict(l=0, r=0, t=40, b=0),
|
| 159 |
-
height=520
|
| 160 |
-
)
|
| 161 |
return fig
|
| 162 |
|
| 163 |
-
def
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
feats, Xs, Z, loadings, expl = compute_pca(df, n_components, standardize)
|
| 169 |
-
color_key = LABEL_TO_KEY.get(color_label, "bmi")
|
| 170 |
-
color_label_nl = FEATURE_LABELS.get(color_key, color_key)
|
| 171 |
-
color_vals = df[color_key].values
|
| 172 |
-
|
| 173 |
-
fig1 = build_biplot(Z, loadings, feats, color_vals, arrow_scale, point_size, alpha, color_label_nl)
|
| 174 |
-
fig2 = build_variance_plot(expl)
|
| 175 |
-
|
| 176 |
-
load_df = pd.DataFrame({
|
| 177 |
-
"feature_key": feats,
|
| 178 |
-
"PC1_loading": loadings[:, 0],
|
| 179 |
-
"PC2_loading": loadings[:, 1],
|
| 180 |
-
"PC1_abs": np.abs(loadings[:, 0]),
|
| 181 |
-
"PC2_abs": np.abs(loadings[:, 1]),
|
| 182 |
-
})
|
| 183 |
-
load_df["Feature (PC1)"] = load_df["feature_key"].map(lambda k: FEATURE_LABELS.get(k, k))
|
| 184 |
-
load_df["Feature (PC2)"] = load_df["feature_key"].map(lambda k: FEATURE_LABELS.get(k, k))
|
| 185 |
-
top_pc1 = load_df.sort_values("PC1_abs", ascending=False)[["Feature (PC1)", "PC1_loading"]].head(6).reset_index(drop=True)
|
| 186 |
-
top_pc2 = load_df.sort_values("PC2_abs", ascending=False)[["Feature (PC2)", "PC2_loading"]].head(6).reset_index(drop=True)
|
| 187 |
-
max_len = max(len(top_pc1), len(top_pc2))
|
| 188 |
-
top_pc1 = top_pc1.reindex(range(max_len)); top_pc2 = top_pc2.reindex(range(max_len))
|
| 189 |
-
table = pd.concat([top_pc1, top_pc2], axis=1)
|
| 190 |
|
| 191 |
-
|
| 192 |
-
### Wat zie je hier?
|
| 193 |
-
- **Punten (patiënten)** geprojecteerd in 2D met **PCA**. Dicht bij elkaar = **lijken op elkaar** over meerdere metingen.
|
| 194 |
-
- **Kleur** = **{color_label_nl}**. Zo zie je meteen of deze eigenschap een **gradiënt** vormt.
|
| 195 |
-
- **Pijlen** = bijdrage van **metingen** aan de richting van **PC1/PC2**. **Langere pijlen** wegen zwaarder.
|
| 196 |
-
- **Balkgrafiek** = per component hoeveel variatie hij uitlegt; **lijn** = cumulatief.
|
| 197 |
-
"""
|
| 198 |
-
|
| 199 |
-
# 3D
|
| 200 |
-
if show_3d:
|
| 201 |
-
# Zorg dat we minstens 3 componenten hebben
|
| 202 |
-
if Z.shape[1] < 3:
|
| 203 |
-
pca3 = PCA(n_components=3)
|
| 204 |
-
Z3 = pca3.fit_transform(Xs)
|
| 205 |
-
else:
|
| 206 |
-
Z3 = Z[:, :3]
|
| 207 |
-
fig3 = build_pca3d(Z3, color_vals, color_label_nl, point_size, alpha)
|
| 208 |
-
pca3d_out = gr.update(value=fig3, visible=True)
|
| 209 |
-
else:
|
| 210 |
-
pca3d_out = gr.update(value=None, visible=False)
|
| 211 |
-
|
| 212 |
-
return fig1, fig2, table, summary_md, overview_df, overview_note, corr_tbl, pca3d_out
|
| 213 |
-
|
| 214 |
-
def animate_pca(color_label="BMI (Body Mass Index)", point_size=32, alpha=0.85, n_components=10, standardize=True, frames=40, pause=0.0):
|
| 215 |
df = load_diabetes_df()
|
| 216 |
feats, Xs, Z, loadings, expl = compute_pca(df, n_components, standardize)
|
| 217 |
-
color_key = LABEL_TO_KEY
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
ax.axvline(0, color="grey", linewidth=0.6, linestyle=":")
|
| 232 |
-
ax.grid(True, linestyle=":", linewidth=0.6)
|
| 233 |
-
plt.tight_layout()
|
| 234 |
-
yield fig
|
| 235 |
-
if pause > 0:
|
| 236 |
-
time.sleep(pause)
|
| 237 |
-
|
| 238 |
-
def export_biplot_png(color_label="BMI (Body Mass Index)", arrow_scale=2.0, point_size=32, alpha=0.85, n_components=10, standardize=True):
|
| 239 |
-
df = load_diabetes_df()
|
| 240 |
-
feats, Xs, Z, loadings, expl = compute_pca(df, n_components, standardize)
|
| 241 |
-
color_key = LABEL_TO_KEY.get(color_label, "bmi")
|
| 242 |
-
color_label_nl = FEATURE_LABELS.get(color_key, color_key)
|
| 243 |
-
color_vals = df[color_key].values
|
| 244 |
-
fig = build_biplot(Z, loadings, feats, color_vals, arrow_scale, point_size, alpha, color_label_nl)
|
| 245 |
-
path = f"/mnt/data/biplot_{int(time.time())}.png"
|
| 246 |
-
fig.savefig(path, dpi=150, bbox_inches="tight")
|
| 247 |
-
plt.close(fig)
|
| 248 |
-
return path
|
| 249 |
-
|
| 250 |
-
def export_variance_png(n_components=10, standardize=True):
|
| 251 |
-
df = load_diabetes_df()
|
| 252 |
-
feats, Xs, Z, loadings, expl = compute_pca(df, n_components, standardize)
|
| 253 |
-
fig = build_variance_plot(expl)
|
| 254 |
-
path = f"/mnt/data/variance_{int(time.time())}.png"
|
| 255 |
-
fig.savefig(path, dpi=150, bbox_inches="tight")
|
| 256 |
-
plt.close(fig)
|
| 257 |
-
return path
|
| 258 |
-
|
| 259 |
-
with gr.Blocks(title="PCA Biplot — Diabetes (Dashboard)") as demo:
|
| 260 |
-
gr.HTML("""
|
| 261 |
-
<style>
|
| 262 |
-
.card {background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);}
|
| 263 |
-
.callout {padding:12px 14px; border-left:4px solid #2563eb; background:#f1f5f9; border-radius:8px; margin: 8px 0 18px;}
|
| 264 |
-
.smallnote {font-size: 0.92em; opacity: 0.85;}
|
| 265 |
-
</style>
|
| 266 |
-
""")
|
| 267 |
-
|
| 268 |
-
gr.Markdown("# PCA Biplot — Diabetes (Dashboard)")
|
| 269 |
-
gr.Markdown(MEDICAL_MD)
|
| 270 |
-
|
| 271 |
with gr.Row():
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
show_3d = gr.Checkbox(value=True, label="Toon 3D PCA (PC1–PC3)")
|
| 283 |
-
run_btn = gr.Button("Update visualisaties")
|
| 284 |
-
gr.HTML('<div class="callout smallnote">💡 <b>Tip:</b> Kies links een meting (bijv. BMI of cholesterol) en klik daarna op <b>Update visualisaties</b>.</div>')
|
| 285 |
-
with gr.Group():
|
| 286 |
-
gr.Markdown("### Animatie")
|
| 287 |
-
animate_btn = gr.Button("▶ Animate PCA (PC1 → PC2)")
|
| 288 |
-
anim_plot = gr.Plot(label="Animatie van projectie")
|
| 289 |
-
|
| 290 |
-
with gr.Group():
|
| 291 |
-
gr.Markdown("### Downloads")
|
| 292 |
-
dl_biplot = gr.DownloadButton("Download biplot (PNG)")
|
| 293 |
-
dl_var = gr.DownloadButton("Download variatieplot (PNG)")
|
| 294 |
-
file_biplot = gr.File(label="Biplot PNG", visible=False)
|
| 295 |
-
file_var = gr.File(label="Variatieplot PNG", visible=False)
|
| 296 |
-
|
| 297 |
-
with gr.Column(scale=2):
|
| 298 |
-
with gr.Row():
|
| 299 |
-
with gr.Column():
|
| 300 |
-
gr.Markdown("### Biplot (2D)")
|
| 301 |
-
plot_biplot = gr.Plot()
|
| 302 |
-
with gr.Column():
|
| 303 |
-
gr.Markdown("### Uitlegvariantie")
|
| 304 |
-
plot_expl = gr.Plot()
|
| 305 |
-
with gr.Row():
|
| 306 |
-
with gr.Column():
|
| 307 |
-
gr.Markdown("### Top-features (PC1 / PC2)")
|
| 308 |
-
table = gr.Dataframe(headers=["Feature (PC1)", "Loading PC1", "Feature (PC2)", "Loading PC2"], row_count=6)
|
| 309 |
-
with gr.Column():
|
| 310 |
-
gr.Markdown("### Overzicht (gemiddelden & verdeling)")
|
| 311 |
-
overview_tbl = gr.Dataframe(interactive=False)
|
| 312 |
-
overview_note_md = gr.Markdown()
|
| 313 |
-
with gr.Row():
|
| 314 |
-
with gr.Column():
|
| 315 |
-
gr.Markdown("### Samenvatting")
|
| 316 |
-
summary = gr.Markdown()
|
| 317 |
-
with gr.Column():
|
| 318 |
-
gr.Markdown("### Top correlaties (features)")
|
| 319 |
-
topcorr_tbl = gr.Dataframe(interactive=False)
|
| 320 |
-
with gr.Row():
|
| 321 |
-
with gr.Column():
|
| 322 |
-
gr.Markdown("### 3D PCA (PC1–PC3 — sleep om te draaien)")
|
| 323 |
-
plot3d = gr.Plot(visible=True)
|
| 324 |
-
|
| 325 |
-
inputs = [color_feat, arrow_scale, point_size, alpha, n_components, standardize, show_3d]
|
| 326 |
-
run_btn.click(fn=pca_biplot, inputs=inputs,
|
| 327 |
-
outputs=[plot_biplot, plot_expl, table, summary, overview_tbl, overview_note_md, topcorr_tbl, plot3d])
|
| 328 |
-
demo.load(fn=pca_biplot, inputs=inputs,
|
| 329 |
-
outputs=[plot_biplot, plot_expl, table, summary, overview_tbl, overview_note_md, topcorr_tbl, plot3d])
|
| 330 |
-
|
| 331 |
-
animate_btn.click(fn=animate_pca,
|
| 332 |
-
inputs=[color_feat, point_size, alpha, n_components, standardize],
|
| 333 |
-
outputs=anim_plot)
|
| 334 |
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
dl_biplot.click(fn=export_biplot_png,
|
| 339 |
-
inputs=[color_feat, arrow_scale, point_size, alpha, n_components, standardize],
|
| 340 |
-
outputs=[file_biplot])
|
| 341 |
-
dl_var.click(fn=export_variance_png,
|
| 342 |
-
inputs=[n_components, standardize],
|
| 343 |
-
outputs=[dl_var])
|
| 344 |
-
dl_var.click(fn=export_variance_png,
|
| 345 |
-
inputs=[n_components, standardize],
|
| 346 |
-
outputs=[file_var])
|
| 347 |
|
| 348 |
-
if __name__
|
| 349 |
-
demo.queue().launch(server_name="0.0.0.0", server_port=7860
|
|
|
|
| 7 |
from sklearn.preprocessing import StandardScaler
|
| 8 |
from sklearn.decomposition import PCA
|
| 9 |
import plotly.graph_objects as go
|
| 10 |
+
import plotly.express as px
|
| 11 |
|
| 12 |
FEATURE_LABELS = {
|
| 13 |
"age": "Leeftijd",
|
|
|
|
| 24 |
}
|
| 25 |
LABEL_TO_KEY = {v: k for k, v in FEATURE_LABELS.items()}
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
def load_diabetes_df():
|
| 28 |
d = datasets.load_diabetes()
|
| 29 |
X = pd.DataFrame(d.data, columns=d.feature_names)
|
|
|
|
| 32 |
df["target"] = y
|
| 33 |
return df
|
| 34 |
|
| 35 |
+
def compute_pca(df, n_components=10, standardize=True):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
feats = [c for c in df.columns if c != "target"]
|
| 37 |
X = df[feats].values
|
| 38 |
if standardize:
|
| 39 |
+
scaler = StandardScaler()
|
| 40 |
Xs = scaler.fit_transform(X)
|
| 41 |
else:
|
| 42 |
Xs = X
|
| 43 |
+
pca = PCA(n_components=min(n_components, Xs.shape[1]))
|
| 44 |
Z = pca.fit_transform(Xs)
|
| 45 |
loadings = pca.components_.T
|
| 46 |
expl = pca.explained_variance_ratio_
|
| 47 |
return feats, Xs, Z, loadings, expl
|
| 48 |
|
| 49 |
+
def build_biplot(df, Z, loadings, feats, color_key):
|
| 50 |
+
hover_text = []
|
| 51 |
+
for idx in range(len(df)):
|
| 52 |
+
parts = [f"{FEATURE_LABELS.get(k,k)}: {df.iloc[idx][k]:.3f}" for k in df.columns]
|
| 53 |
+
hover_text.append("<br>".join(parts))
|
| 54 |
+
fig = go.Figure()
|
| 55 |
+
fig.add_trace(go.Scatter(x=Z[:,0], y=Z[:,1], mode="markers",
|
| 56 |
+
marker=dict(size=7, color=df[color_key].values),
|
| 57 |
+
text=hover_text,
|
| 58 |
+
hovertemplate="%{text}<extra></extra>"))
|
| 59 |
+
# arrows
|
| 60 |
+
scale=2.0
|
| 61 |
+
for i,key in enumerate(feats):
|
| 62 |
+
x = loadings[i,0]*scale; y = loadings[i,1]*scale
|
| 63 |
+
fig.add_annotation(x=x, y=y, ax=0, ay=0, showarrow=True, arrowhead=3)
|
| 64 |
+
fig.add_annotation(x=x*1.05, y=y*1.05, text=FEATURE_LABELS.get(key,key), showarrow=False, font=dict(size=10))
|
| 65 |
+
fig.update_layout(title="PCA-biplot (2D, hover)", xaxis_title="PC1", yaxis_title="PC2", height=500)
|
| 66 |
+
return fig
|
| 67 |
+
|
| 68 |
+
def build_pca3d(Z3, color_vals):
|
| 69 |
+
fig = go.Figure(data=[go.Scatter3d(x=Z3[:,0], y=Z3[:,1], z=Z3[:,2], mode="markers",
|
| 70 |
+
marker=dict(size=4,color=color_vals,opacity=0.85))])
|
| 71 |
+
fig.update_layout(title="PCA 3D", scene=dict(xaxis_title="PC1", yaxis_title="PC2", zaxis_title="PC3"), height=500)
|
| 72 |
return fig
|
| 73 |
|
| 74 |
def build_variance_plot(expl):
|
| 75 |
+
fig = plt.figure()
|
| 76 |
ax = fig.add_subplot(111)
|
| 77 |
+
xs = np.arange(1,len(expl)+1)
|
| 78 |
+
ax.bar(xs, expl); ax.plot(xs, np.cumsum(expl), marker="o")
|
| 79 |
+
ax.set_xlabel("PC"); ax.set_ylabel("Explained variance ratio")
|
| 80 |
+
fig.tight_layout()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
return fig
|
| 82 |
|
| 83 |
+
def build_corr_heatmap(df):
|
| 84 |
+
feats = [c for c in df.columns if c != "target"]
|
| 85 |
+
corr = pd.DataFrame(df[feats]).corr()
|
| 86 |
+
order = corr.abs().sum().sort_values(ascending=False).index.tolist()
|
| 87 |
+
corr_sorted = corr.loc[order, order]
|
| 88 |
+
fig = px.imshow(corr_sorted, color_continuous_scale="RdBu", origin="lower", zmin=-1, zmax=1)
|
| 89 |
+
fig.update_layout(title="Correlatie-heatmap")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
return fig
|
| 91 |
|
| 92 |
+
def build_hist_box(df, color_key):
|
| 93 |
+
series = df[color_key]
|
| 94 |
+
fig_hist = px.histogram(series, nbins=30, title=f"Histogram — {FEATURE_LABELS.get(color_key,color_key)}")
|
| 95 |
+
fig_box = px.box(series, points="outliers", title=f"Boxplot — {FEATURE_LABELS.get(color_key,color_key)}")
|
| 96 |
+
return fig_hist, fig_box
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
+
def controller(color_label="BMI (Body Mass Index)", n_components=10, standardize=True):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
df = load_diabetes_df()
|
| 100 |
feats, Xs, Z, loadings, expl = compute_pca(df, n_components, standardize)
|
| 101 |
+
color_key = LABEL_TO_KEY[color_label]
|
| 102 |
+
fig2d = build_biplot(df, Z, loadings, feats, color_key)
|
| 103 |
+
if Z.shape[1] < 3:
|
| 104 |
+
pca3 = PCA(n_components=3); Z3 = pca3.fit_transform(Xs)
|
| 105 |
+
else:
|
| 106 |
+
Z3 = Z[:,:3]
|
| 107 |
+
fig3d = build_pca3d(Z3, df[color_key].values)
|
| 108 |
+
fig_var = build_variance_plot(expl)
|
| 109 |
+
fig_heat = build_corr_heatmap(df)
|
| 110 |
+
fig_hist, fig_box = build_hist_box(df, color_key)
|
| 111 |
+
return fig2d, fig3d, fig_var, fig_heat, fig_hist, fig_box
|
| 112 |
+
|
| 113 |
+
with gr.Blocks() as demo:
|
| 114 |
+
gr.Markdown("# PCA Dashboard — Diabetes")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
with gr.Row():
|
| 116 |
+
color_feat = gr.Dropdown(choices=list(LABEL_TO_KEY.keys()), value="BMI (Body Mass Index)", label="Kleur op meting")
|
| 117 |
+
n_components = gr.Slider(3,10,10,step=1,label="Aantal PCA-componenten")
|
| 118 |
+
standardize = gr.Checkbox(value=True,label="Standaardiseer")
|
| 119 |
+
run_btn = gr.Button("Update")
|
| 120 |
+
with gr.Row():
|
| 121 |
+
plot2d = gr.Plot(); plot3d = gr.Plot()
|
| 122 |
+
with gr.Row():
|
| 123 |
+
plot_var = gr.Plot(); plot_heat = gr.Plot()
|
| 124 |
+
with gr.Row():
|
| 125 |
+
plot_hist = gr.Plot(); plot_box = gr.Plot()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
+
inputs=[color_feat,n_components,standardize]
|
| 128 |
+
run_btn.click(fn=controller, inputs=inputs, outputs=[plot2d,plot3d,plot_var,plot_heat,plot_hist,plot_box])
|
| 129 |
+
demo.load(fn=controller, inputs=inputs, outputs=[plot2d,plot3d,plot_var,plot_heat,plot_hist,plot_box])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
+
if __name__=="__main__":
|
| 132 |
+
demo.queue().launch(server_name="0.0.0.0", server_port=7860)
|