Spaces:
Sleeping
Sleeping
consistent palette (blue=focus, red=past only); tooltip shows % + raw mean attn value
Browse files- app.py +3 -2
- reveal_widget.html +3 -3
- tree_widget.html +3 -3
app.py
CHANGED
|
@@ -84,8 +84,9 @@ def build_tree(image):
|
|
| 84 |
tree = {"g": g, "nleaves": nleaves, "maxdepth": maxdepth,
|
| 85 |
"nodes": [{"id": i, "x": round(xpos[i], 3), "depth": n["depth"], "parent": n["parent"],
|
| 86 |
"leaf": len(n["children"]) == 0, "n": len(n["leaves"]),
|
| 87 |
-
"att": round(float(att_pct[n["leaves"]].sum()), 1),
|
| 88 |
-
"attm": round(float(att_pct[n["leaves"]].mean()), 4),
|
|
|
|
| 89 |
"tau": n["split_tau"], "patches": n["leaves"]} for i, n in enumerate(nodes)]}
|
| 90 |
buf = io.BytesIO(); img.save(buf, "PNG")
|
| 91 |
return tree, base64.b64encode(buf.getvalue()).decode()
|
|
|
|
| 84 |
tree = {"g": g, "nleaves": nleaves, "maxdepth": maxdepth,
|
| 85 |
"nodes": [{"id": i, "x": round(xpos[i], 3), "depth": n["depth"], "parent": n["parent"],
|
| 86 |
"leaf": len(n["children"]) == 0, "n": len(n["leaves"]),
|
| 87 |
+
"att": round(float(att_pct[n["leaves"]].sum()), 1), # % of total attention
|
| 88 |
+
"attm": round(float(att_pct[n["leaves"]].mean()), 4), # mean attention % per patch (reveal order)
|
| 89 |
+
"attmv": round(float(att[n["leaves"]].mean()), 5), # raw mean attention value per patch
|
| 90 |
"tau": n["split_tau"], "patches": n["leaves"]} for i, n in enumerate(nodes)]}
|
| 91 |
buf = io.BytesIO(); img.save(buf, "PNG")
|
| 92 |
return tree, base64.b64encode(buf.getvalue()).decode()
|
reveal_widget.html
CHANGED
|
@@ -79,11 +79,11 @@ function renderImage(f){
|
|
| 79 |
ctx.font=Math.round(cell*0.46)+'px monospace'; ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.lineWidth=2;
|
| 80 |
for(let p=0;p<P;p++){ const x=(p%G)*cell+cell/2, y=(Math.floor(p/G))*cell+cell/2;
|
| 81 |
ctx.strokeStyle='rgba(0,0,0,0.85)'; ctx.strokeText(pd[p],x,y);
|
| 82 |
-
ctx.fillStyle=pcl[p]?'#ffffff':'#
|
| 83 |
-
//
|
| 84 |
const present=(f>=1&&f<=N)?ORDER[f-1]:null;
|
| 85 |
if(present!=null){ const ps=NODES[present].patches, set=new Set(ps);
|
| 86 |
-
ctx.strokeStyle='rgba(
|
| 87 |
ps.forEach(p=>{ const r=Math.floor(p/G),c=p%G;
|
| 88 |
[[r-1,c],[r+1,c],[r,c-1],[r,c+1]].forEach(([rr,cc])=>{
|
| 89 |
if(rr<0||rr>=G||cc<0||cc>=G||!set.has(rr*G+cc)){
|
|
|
|
| 79 |
ctx.font=Math.round(cell*0.46)+'px monospace'; ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.lineWidth=2;
|
| 80 |
for(let p=0;p<P;p++){ const x=(p%G)*cell+cell/2, y=(Math.floor(p/G))*cell+cell/2;
|
| 81 |
ctx.strokeStyle='rgba(0,0,0,0.85)'; ctx.strokeText(pd[p],x,y);
|
| 82 |
+
ctx.fillStyle=pcl[p]?'#ffffff':'#cfd4e0'; ctx.fillText(pd[p],x,y); }
|
| 83 |
+
// blue outline of the segment currently being looked at (matches the "present" node)
|
| 84 |
const present=(f>=1&&f<=N)?ORDER[f-1]:null;
|
| 85 |
if(present!=null){ const ps=NODES[present].patches, set=new Set(ps);
|
| 86 |
+
ctx.strokeStyle='rgba(91,156,246,0.95)'; ctx.lineWidth=2;
|
| 87 |
ps.forEach(p=>{ const r=Math.floor(p/G),c=p%G;
|
| 88 |
[[r-1,c],[r+1,c],[r,c-1],[r,c+1]].forEach(([rr,cc])=>{
|
| 89 |
if(rr<0||rr>=G||cc<0||cc>=G||!set.has(rr*G+cc)){
|
tree_widget.html
CHANGED
|
@@ -47,7 +47,7 @@ function sizeImage(){
|
|
| 47 |
// attention color (low=blue, high=orange)
|
| 48 |
function attColor(a){
|
| 49 |
const t=Math.min(1, a/25); // 25% saturates
|
| 50 |
-
const c1=[
|
| 51 |
return `rgb(${Math.round(c1[0]+(c2[0]-c1[0])*t)},${Math.round(c1[1]+(c2[1]-c1[1])*t)},${Math.round(c1[2]+(c2[2]-c1[2])*t)})`;
|
| 52 |
}
|
| 53 |
function highlight(node){
|
|
@@ -56,7 +56,7 @@ function highlight(node){
|
|
| 56 |
ctx.fillStyle='rgba(8,10,18,0.72)'; ctx.fillRect(0,0,S,S);
|
| 57 |
const set=new Set(node.patches);
|
| 58 |
node.patches.forEach(p=>{ const r=Math.floor(p/G), c=p%G; ctx.clearRect(c*cell,r*cell,cell,cell); });
|
| 59 |
-
ctx.strokeStyle='rgba(
|
| 60 |
// outline boundary of the lit region
|
| 61 |
node.patches.forEach(p=>{ const r=Math.floor(p/G), c=p%G;
|
| 62 |
const nb=[[r-1,c],[r+1,c],[r,c-1],[r,c+1]];
|
|
@@ -89,7 +89,7 @@ function drawTree(){
|
|
| 89 |
circles.forEach(el=>{
|
| 90 |
const n=NODES[+el.dataset.id];
|
| 91 |
el.addEventListener('mouseenter',e=>{ highlight(n);
|
| 92 |
-
tip.style.opacity=1; tip.innerHTML=`level ${n.depth} 路 ${n.n} patches 路 ${n.att}%
|
| 93 |
});
|
| 94 |
el.addEventListener('mousemove',e=>{ const b=right.getBoundingClientRect();
|
| 95 |
tip.style.left=(e.clientX-b.left-tip.offsetWidth-12)+'px'; tip.style.top=(e.clientY-b.top+12)+'px'; });
|
|
|
|
| 47 |
// attention color (low=blue, high=orange)
|
| 48 |
function attColor(a){
|
| 49 |
const t=Math.min(1, a/25); // 25% saturates
|
| 50 |
+
const c1=[150,158,176], c2=[244,162,97]; // attention heat: grey(low) -> orange(high)
|
| 51 |
return `rgb(${Math.round(c1[0]+(c2[0]-c1[0])*t)},${Math.round(c1[1]+(c2[1]-c1[1])*t)},${Math.round(c1[2]+(c2[2]-c1[2])*t)})`;
|
| 52 |
}
|
| 53 |
function highlight(node){
|
|
|
|
| 56 |
ctx.fillStyle='rgba(8,10,18,0.72)'; ctx.fillRect(0,0,S,S);
|
| 57 |
const set=new Set(node.patches);
|
| 58 |
node.patches.forEach(p=>{ const r=Math.floor(p/G), c=p%G; ctx.clearRect(c*cell,r*cell,cell,cell); });
|
| 59 |
+
ctx.strokeStyle='rgba(91,156,246,0.95)'; ctx.lineWidth=1.5; // blue = "focused" region
|
| 60 |
// outline boundary of the lit region
|
| 61 |
node.patches.forEach(p=>{ const r=Math.floor(p/G), c=p%G;
|
| 62 |
const nb=[[r-1,c],[r+1,c],[r,c-1],[r,c+1]];
|
|
|
|
| 89 |
circles.forEach(el=>{
|
| 90 |
const n=NODES[+el.dataset.id];
|
| 91 |
el.addEventListener('mouseenter',e=>{ highlight(n);
|
| 92 |
+
tip.style.opacity=1; tip.innerHTML=`level ${n.depth} 路 ${n.n} patches 路 ${n.att}% of attention 路 mean attn ${n.attmv}`+(n.tau!=null?` 路 splits at 蟿=${n.tau}`:' 路 leaf');
|
| 93 |
});
|
| 94 |
el.addEventListener('mousemove',e=>{ const b=right.getBoundingClientRect();
|
| 95 |
tip.style.left=(e.clientX-b.left-tip.offsetWidth-12)+'px'; tip.style.top=(e.clientY-b.top+12)+'px'; });
|