61 lines
2.6 KiB
Python
61 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Classify width-varying nodes in a DENSE capture by their sizing law, using the full
|
|
sample curve. Run after a dense clone: python3 scripts/analyze-dense.py <run/.clone> """
|
|
import json, sys, statistics, glob, os
|
|
run = sys.argv[1] if len(sys.argv) > 1 else "output-dense/sample/.clone"
|
|
caps = {}
|
|
for f in sorted(glob.glob(os.path.join(run, "source/capture/dom-*.json"))):
|
|
vp = int(os.path.basename(f)[4:-5])
|
|
caps[vp] = json.load(open(f))["root"]
|
|
VPS = sorted(caps)
|
|
print("sample widths:", VPS)
|
|
|
|
def flat(n, a):
|
|
if isinstance(n, dict):
|
|
a.append(n)
|
|
for c in (n.get("children") or []): flat(c, a)
|
|
F = {vp: [] for vp in VPS}
|
|
for vp in VPS: flat(caps[vp], F[vp])
|
|
def wp(n, p, m):
|
|
m[id(n)] = p
|
|
for c in (n.get("children") or []): wp(c, n, m)
|
|
PM = {vp: {} for vp in VPS}
|
|
for vp in VPS: wp(caps[vp], None, PM[vp])
|
|
def pf(v):
|
|
try: return float(str(v).replace("px", ""))
|
|
except: return 0.0
|
|
|
|
n = min(len(F[vp]) for vp in VPS)
|
|
cats = {"fills_container": 0, "prop_container": 0, "prop_viewport": 0, "clamped_maxw": 0,
|
|
"shrink_recoverable": 0, "real_breakpoint": 0, "fixed": 0, "unknown": 0}
|
|
for i in range(n):
|
|
nd = {vp: F[vp][i] for vp in VPS}
|
|
if not all(nd[vp].get("visible") for vp in VPS): continue
|
|
w = {vp: (nd[vp].get("bbox") or {}).get("width", 0) for vp in VPS}
|
|
if max(w.values()) - min(w.values()) <= 2: continue # constant → no band
|
|
# container content width per vp
|
|
cw = {}
|
|
for vp in VPS:
|
|
p = PM[vp].get(id(nd[vp])); pb = (p or {}).get("bbox"); pcs = (p or {}).get("computed") or {}
|
|
base = pb["width"] if pb else vp
|
|
cw[vp] = base - pf(pcs.get("paddingLeft")) - pf(pcs.get("paddingRight"))
|
|
rc = [w[vp] / cw[vp] for vp in VPS if cw[vp] > 0]
|
|
rv = [w[vp] / vp for vp in VPS]
|
|
def cv(xs):
|
|
m = statistics.mean(xs); return statistics.pstdev(xs) / m if m else 9
|
|
wl = [w[vp] for vp in VPS]
|
|
if rc and cv(rc) < 0.02 and abs(statistics.mean(rc) - 1) < 0.02: cats["fills_container"] += 1
|
|
elif rc and cv(rc) < 0.03: cats["prop_container"] += 1
|
|
elif cv(rv) < 0.03: cats["prop_viewport"] += 1
|
|
elif wl[-1] == wl[-2] and wl[0] < wl[-1]: # plateau at the widest → clamp or recoverable shrink
|
|
# constant above a knee, smaller below
|
|
cats["clamped_maxw"] += 1
|
|
elif wl[-1] < wl[-2]: # still shrinking even at the widest → natural beyond range
|
|
cats["shrink_recoverable"] += 1
|
|
else:
|
|
# piecewise? count distinct plateaus
|
|
cats["unknown"] += 1
|
|
print("\nwidth-varying nodes by inferred sizing law (dense):")
|
|
for k, v in cats.items(): print(f" {k:20} {v}")
|
|
print(f" TOTAL varying: {sum(cats.values())}")
|