""" ligging_figuur2.py -> python ligging_figuur2.py [csv] ========================================================= Banden schalen mee met de Shellgrootte; consolidatiepunt per Shell (met window-n, zodat dunne data zichtbaar is); en de 'collapse'-figuur. Bevinding: Shell-30 en Shell-40 vallen samen op de genormaliseerde as (werkende punten / Shellgrootte) en consolideren rond ~70%. Shell-20 (twee uitgeschakelde zijkleuren) is een eigen regime: azen in de korte kleuren tellen wel als werkend maar groeien de Shell niet, dus de fractie lekt boven 100%, en de robuustheid komt vooral uit ruffs (liggings-onafhankelijk). """ #!/usr/bin/env python3 import csv, sys, statistics as st import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt CSVNAME = sys.argv[1] if len(sys.argv) > 1 else "ligging_perspel.csv" rows = [dict(kleur=d['kleur'], T=int(d['DD_werkelijk']), work=int(d['werkende_punten']), shell=int(d['shellgrootte']), mk=float(d['maakkans_manche'])) for d in csv.DictReader(open(CSVNAME))] manches = [r for r in rows if r['kleur'] != 'SA' and r['T'] >= 10] SHELLS = [20, 30, 40] COL = {20: '#cc7a00', 30: '#1f77b4', 40: '#2ca02c'} CLEAN = [30, 40] # goed bemonsterde, niet-lekkende regimes def stats(grp): n = len(grp) return (n, st.mean(r['mk'] for r in grp), sum(r['mk'] < 0.60 for r in grp) / n, sum(r['mk'] >= 0.90 for r in grp) / n) # ---- 1) fractionele banden ---- FB = [(0.0, .50), (.50, .60), (.60, .70), (.70, .80), (.80, 9)] def flbl(lo, hi): if lo == 0.0: return f"<{int(hi*100)}%" if hi >= 9: return f">{int(lo*100)}%" return f"{int(lo*100)}-{int(hi*100)}%" print("\n Manche-op-snit naar werkende punten ALS FRACTIE VAN DE SHELLGROOTTE\n") for sh in SHELLS: grp = [r for r in manches if r['shell'] == sh] med = st.median(r['work']/sh for r in grp); lek = sum(r['work']/sh > 1 for r in grp) print(f" --- Shell-{sh} (n={len(grp)}; mediaan-fractie {med:.2f}; " f"{100*lek/len(grp):.0f}% boven 100%) ---") print(f" {'fractie':>8} {'~punten':>8} {'n':>4} {'maakkans':>9} {'op-snit':>8} {'robuust':>8}") for lo, hi in FB: g = [r for r in grp if lo <= r['work']/sh < hi] if not g: continue n, mk, op, rob = stats(g) ap = f">{round(lo*sh)}" if hi >= 9 else f"{round(lo*sh)}-{round(hi*sh)}" print(f" {flbl(lo,hi):>8} {ap:>8} {n:4d} {mk*100:8.0f}% {op*100:7.0f}% {rob*100:7.0f}%") print() # ---- 2) consolidatiepunt (met window-n) ---- def smoothed_abs(grp, half=1, minn=8): out = [] for w in range(min(r['work'] for r in grp), max(r['work'] for r in grp) + 1): win = [r for r in grp if abs(r['work'] - w) <= half] if len(win) >= minn: n, mk, op, rob = stats(win); out.append((w, mk, op, rob, len(win))) return out def consolidation(grp, thr=0.80): for w, mk, op, rob, nwin in smoothed_abs(grp): if mk >= thr: return w, nwin return None, 0 print(" Consolidatiepunt (gladde maakkans >= 80%):") cons = {} for sh in SHELLS: grp = [r for r in manches if r['shell'] == sh] cp, nwin = consolidation(grp) if cp: cons[sh] = cp flag = "" if (nwin >= 20 and sh in CLEAN) else " <- dun/lekkend, onbetrouwbaar" print(f" Shell-{sh}: {cp:2d} punten = {100*cp/sh:3.0f}% van de Shellgrootte " f"(window-n={nwin}){flag}") clean_frac = st.mean(100*cons[sh]/sh for sh in CLEAN if sh in cons) print(f" -> schone collapse (Shell-30 & -40): ~{clean_frac:.0f}% van de Shellgrootte") # ---- 3) figuur ---- def curve_abs(grp, half=1, minn=12): xs, ys = [], [] for w in range(min(r['work'] for r in grp), max(r['work'] for r in grp) + 1): win = [r for r in grp if abs(r['work'] - w) <= half] if len(win) >= minn: xs.append(w); ys.append(st.mean(r['mk'] for r in win)*100) return xs, ys def curve_norm(grp, halffrac=0.025, minn=12): xs, ys = [], [] fr = sorted(r['work']/r['shell'] for r in grp); x = fr[0] while x <= fr[-1] + 1e-9: win = [r for r in grp if abs(r['work']/r['shell'] - x) <= halffrac] if len(win) >= minn: xs.append(x*100); ys.append(st.mean(r['mk'] for r in win)*100) x += 0.02 return xs, ys fig, (axA, axB) = plt.subplots(1, 2, figsize=(13.5, 5.2)) for sh in SHELLS: grp = [r for r in manches if r['shell'] == sh] style = dict(color=COL[sh], marker='o') if sh not in CLEAN: style.update(linestyle='--', alpha=.55, marker='x') xa, ya = curve_abs(grp); axA.plot(xa, ya, label=f"Shell-{sh}", **style) xn, yn = curve_norm(grp); axB.plot(xn, yn, label=f"Shell-{sh}", **style) axA.set_title("Absoluut: maakkans vs werkende punten") axA.set_xlabel("werkende punten"); axA.set_ylabel("maakkans van de manche (%)") axA.axhline(80, ls=':', color='gray', lw=1); axA.grid(alpha=.3); axA.legend() axB.set_title("Genormaliseerd: werkende punten ÷ Shellgrootte") axB.set_xlabel("werkende punten als % van de Shellgrootte") axB.axhline(80, ls=':', color='gray', lw=1) axB.axvline(clean_frac, ls='--', color='black', lw=1.2, label=f"~{clean_frac:.0f}% (Shell-30/40)") axB.axvline(100, ls=':', color='#cc7a00', lw=1, alpha=.6) axB.grid(alpha=.3); axB.legend() fig.suptitle("Shell-30 en Shell-40 vallen samen rond ~70% van de Shellgrootte; " "Shell-20 (extreme vorm) is een eigen, ruff-gedreven regime", fontsize=12) fig.tight_layout(); fig.savefig("ligging_collapse.png", dpi=140) print("\n [figuur weggeschreven: ligging_collapse.png]")