Spaces:
Running
Running
Add radial locus bars and Genome Atlas node silhouettes
Browse files- app.js +1 -1
- carbon-a-strand-poc.png +2 -2
- carbon-a-strand-source.zip +2 -2
- export_still.py +2 -2
- index.html +1 -1
- overview.png +2 -2
app.js
CHANGED
|
@@ -58,7 +58,7 @@ function draw(){if(!gl)return;let dpr=canvas.width/W;gl.viewport(0,0,canvas.widt
|
|
| 58 |
ctx.setTransform(dpr,0,0,dpr,0,0);ctx.clearRect(0,0,W,H);drawLoci();
|
| 59 |
if(zoom<2){let c=screen([0,0]);ctx.textAlign='center';ctx.fillStyle='#14221c';ctx.font='700 17px Manrope';ctx.fillText(fmt(leaves.length),c[0],c[1]+1);ctx.fillStyle='#748078';ctx.font='9px Inter';ctx.fillText('assembly strands',c[0],c[1]+18);}
|
| 60 |
const labels=zoom<2.5?groups:[...nodes.values()].filter(n=>['family','order','genus'].includes(n.rank)&&n.count>10&&n.count<leaves.length/zoom*.6);
|
| 61 |
-
let placed=[];for(const n of labels){let angle=START+SPAN*(n.mid+.5)/leaves.length;let [x,y]=screen(polar(R+BAR_HEIGHT+42,angle));if(x<35||x>W-35||y<25||y>H-25)continue;let name=n.common||n.name;if(name.length>27)name=n.name;ctx.font=(zoom<2.5?'500 13px':'500 12px')+' Inter';let tw=ctx.measureText(name).width,anchor=Math.cos(angle)>.25?'left':Math.cos(angle)<-.25?'right':'center';let bx=anchor==='left'?x:anchor==='right'?x-tw:x-tw/2;if(bx<8){x+=8-bx;bx=8}if(bx+tw>W-8){x-=bx+tw-W+8;bx=W-8-tw}if(placed.some(b=>bx<b.x+b.w+8&&bx+tw>b.x-8&&Math.abs(y-b.y)<32))continue;placed.push({x:bx,y,w:tw});ctx.textAlign=anchor;ctx.fillStyle='#273b30';ctx.strokeStyle='#fff';ctx.lineWidth=4;ctx.strokeText(name,x,y);ctx.fillText(name,x,y);ctx.font='10px Inter';ctx.fillStyle='#7a857f';ctx.strokeText(fmt(n.count)+' assemblies',x,y+15);ctx.fillText(fmt(n.count)+' assemblies',x,y+15);}
|
| 62 |
drawAtlasIcons();
|
| 63 |
if(selected){const a=selected;ctx.strokeStyle='#15392c';ctx.lineWidth=1.8;ctx.beginPath();let p=screen(a.points[0]);ctx.moveTo(...p);for(let j=1;j<a.points.length;j++){let [c,d]=controls(a.points[j-1],a.points[j]);ctx.bezierCurveTo(...screen(c),...screen(d),...screen(a.points[j]));}ctx.stroke();let q=screen(a.tip);ctx.fillStyle='#15392c';ctx.beginPath();ctx.arc(...q,4,0,TAU);ctx.fill();}
|
| 64 |
$('#zoom-readout').textContent=zoom.toFixed(1)+'脳';$('#zoomout').disabled=zoom<=1;$('#zoomin').disabled=zoom>=320;
|
|
|
|
| 58 |
ctx.setTransform(dpr,0,0,dpr,0,0);ctx.clearRect(0,0,W,H);drawLoci();
|
| 59 |
if(zoom<2){let c=screen([0,0]);ctx.textAlign='center';ctx.fillStyle='#14221c';ctx.font='700 17px Manrope';ctx.fillText(fmt(leaves.length),c[0],c[1]+1);ctx.fillStyle='#748078';ctx.font='9px Inter';ctx.fillText('assembly strands',c[0],c[1]+18);}
|
| 60 |
const labels=zoom<2.5?groups:[...nodes.values()].filter(n=>['family','order','genus'].includes(n.rank)&&n.count>10&&n.count<leaves.length/zoom*.6);
|
| 61 |
+
let placed=locusMode!=='off'&&zoom<1.6?[{x:W/2+pan.x-36,y:screen(polar(R+BAR_GAP+BAR_HEIGHT,START))[1]-14,w:72}]:[];for(const n of labels){let angle=START+SPAN*(n.mid+.5)/leaves.length;let [x,y]=screen(polar(R+BAR_HEIGHT+42,angle));if(x<35||x>W-35||y<25||y>H-25)continue;let name=n.common||n.name;if(name.length>27)name=n.name;ctx.font=(zoom<2.5?'500 13px':'500 12px')+' Inter';ctx.save();ctx.font='10px Inter';let cw=ctx.measureText(fmt(n.count)+' assemblies').width;ctx.restore();let tw=Math.max(ctx.measureText(name).width,cw),anchor=Math.cos(angle)>.25?'left':Math.cos(angle)<-.25?'right':'center';let bx=anchor==='left'?x:anchor==='right'?x-tw:x-tw/2;if(bx<8){x+=8-bx;bx=8}if(bx+tw>W-8){x-=bx+tw-W+8;bx=W-8-tw}if(placed.some(b=>bx<b.x+b.w+8&&bx+tw>b.x-8&&Math.abs(y-b.y)<32))continue;placed.push({x:bx,y,w:tw});ctx.textAlign=anchor;ctx.fillStyle='#273b30';ctx.strokeStyle='#fff';ctx.lineWidth=4;ctx.strokeText(name,x,y);ctx.fillText(name,x,y);ctx.font='10px Inter';ctx.fillStyle='#7a857f';ctx.strokeText(fmt(n.count)+' assemblies',x,y+15);ctx.fillText(fmt(n.count)+' assemblies',x,y+15);}
|
| 62 |
drawAtlasIcons();
|
| 63 |
if(selected){const a=selected;ctx.strokeStyle='#15392c';ctx.lineWidth=1.8;ctx.beginPath();let p=screen(a.points[0]);ctx.moveTo(...p);for(let j=1;j<a.points.length;j++){let [c,d]=controls(a.points[j-1],a.points[j]);ctx.bezierCurveTo(...screen(c),...screen(d),...screen(a.points[j]));}ctx.stroke();let q=screen(a.tip);ctx.fillStyle='#15392c';ctx.beginPath();ctx.arc(...q,4,0,TAU);ctx.fill();}
|
| 64 |
$('#zoom-readout').textContent=zoom.toFixed(1)+'脳';$('#zoomout').disabled=zoom<=1;$('#zoomin').disabled=zoom>=320;
|
carbon-a-strand-poc.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
carbon-a-strand-source.zip
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e48117ae3d5d95dd78e08ac29ad37d431d0429095b423bf4d6c10d56e9afadf0
|
| 3 |
+
size 15045655
|
export_still.py
CHANGED
|
@@ -8,6 +8,6 @@ with sync_playwright() as p:
|
|
| 8 |
page=b.new_page(viewport={'width':1200,'height':1420},device_scale_factor=2)
|
| 9 |
page.goto((R/'index.html').as_uri());page.wait_for_function('window.POC && !document.querySelector("#loading")')
|
| 10 |
page.add_style_tag(content='''header{height:90px;padding:0 50px}.brand{font-size:29px}.header-right button{display:none}main{display:block;height:1330px;min-height:1330px}aside,.topbar,.controls,.help,#selection{display:none!important}.stage-wrap{height:100%}#stage{inset:132px 22px 120px}.poster-heading{position:absolute;left:50px;top:35px}.poster-heading h1{font-size:39px;letter-spacing:-1.5px;margin-bottom:11px}.poster-heading p{font-size:15px;color:#6e7b73;margin:0}.poster-footer{position:absolute;bottom:20px;left:50px;right:50px;border-top:1px solid #e6ece8;padding-top:22px}.poster-key{display:flex;justify-content:space-between;font-size:16px;font-weight:500}.poster-key span{display:flex;align-items:center;gap:12px}.poster-key i{width:34px;height:2px;background:#00b86b;display:inline-block}.poster-key i.blue{background:#4167ec}.poster-footer p{font-size:11px;line-height:1.7;color:#6e7b73;margin-top:18px}''')
|
| 11 |
-
page.evaluate('''() => {document.querySelector('.stage-wrap').insertAdjacentHTML('beforeend',`<div class="poster-heading"><h1>One assembly. One strand.</h1><p>33,588 assemblies 路 outer bars sum predicted coding loci across 50 adjacent strands.</p></div><div class="poster-footer"><div class="poster-key"><span><i></i>29,350 with no annotation record listed</span><span><i class="blue"></i>4,238 with existing annotation records</span></div><p>Proof of concept: 33,588 of the release鈥檚 48,167 assemblies. Colours reflect GenBank annotation records in the 7 October 2026 snapshot.<br>
|
| 12 |
-
page.evaluate("document.querySelector('.poster-heading p').textContent='33,588 assemblies 路 '+shortCount(POC.locusTotal)+' loci across '+fmt(POC.locusAvailable)+' assemblies with counts.'");page.wait_for_timeout(800);page.screenshot(path=str(R/'carbon-a-strand-poc.png'));b.close()
|
| 13 |
print(R/'carbon-a-strand-poc.png')
|
|
|
|
| 8 |
page=b.new_page(viewport={'width':1200,'height':1420},device_scale_factor=2)
|
| 9 |
page.goto((R/'index.html').as_uri());page.wait_for_function('window.POC && !document.querySelector("#loading")')
|
| 10 |
page.add_style_tag(content='''header{height:90px;padding:0 50px}.brand{font-size:29px}.header-right button{display:none}main{display:block;height:1330px;min-height:1330px}aside,.topbar,.controls,.help,#selection{display:none!important}.stage-wrap{height:100%}#stage{inset:132px 22px 120px}.poster-heading{position:absolute;left:50px;top:35px}.poster-heading h1{font-size:39px;letter-spacing:-1.5px;margin-bottom:11px}.poster-heading p{font-size:15px;color:#6e7b73;margin:0}.poster-footer{position:absolute;bottom:20px;left:50px;right:50px;border-top:1px solid #e6ece8;padding-top:22px}.poster-key{display:flex;justify-content:space-between;font-size:16px;font-weight:500}.poster-key span{display:flex;align-items:center;gap:12px}.poster-key i{width:34px;height:2px;background:#00b86b;display:inline-block}.poster-key i.blue{background:#4167ec}.poster-footer p{font-size:11px;line-height:1.7;color:#6e7b73;margin-top:18px}''')
|
| 11 |
+
page.evaluate('''() => {document.querySelector('.stage-wrap').insertAdjacentHTML('beforeend',`<div class="poster-heading"><h1>One assembly. One strand.</h1><p>33,588 assemblies 路 outer bars sum predicted coding loci across 50 adjacent strands.</p></div><div class="poster-footer"><div class="poster-key"><span><i></i>29,350 with no annotation record listed</span><span><i class="blue"></i>4,238 with existing annotation records</span></div><p>Proof of concept: 33,588 of the release鈥檚 48,167 assemblies. Colours reflect GenBank annotation records in the 7 October 2026 snapshot.<br>Outer bars sum available loci across up to 50 assembly strands; grey base marks show missing counts. Branch length is not evolutionary time.<br>Genome Atlas silhouettes: PhyloPic. Original image credits and licences are included in the interactive preview.</p></div>`)}''')
|
| 12 |
+
page.evaluate("document.querySelector('.poster-heading p').textContent='33,588 assemblies 路 '+shortCount(POC.locusTotal)+' predicted loci across '+fmt(POC.locusAvailable)+' assemblies with counts.'");page.wait_for_timeout(800);page.screenshot(path=str(R/'carbon-a-strand-poc.png'));b.close()
|
| 13 |
print(R/'carbon-a-strand-poc.png')
|
index.html
CHANGED
|
@@ -141,7 +141,7 @@ function draw(){if(!gl)return;let dpr=canvas.width/W;gl.viewport(0,0,canvas.widt
|
|
| 141 |
ctx.setTransform(dpr,0,0,dpr,0,0);ctx.clearRect(0,0,W,H);drawLoci();
|
| 142 |
if(zoom<2){let c=screen([0,0]);ctx.textAlign='center';ctx.fillStyle='#14221c';ctx.font='700 17px Manrope';ctx.fillText(fmt(leaves.length),c[0],c[1]+1);ctx.fillStyle='#748078';ctx.font='9px Inter';ctx.fillText('assembly strands',c[0],c[1]+18);}
|
| 143 |
const labels=zoom<2.5?groups:[...nodes.values()].filter(n=>['family','order','genus'].includes(n.rank)&&n.count>10&&n.count<leaves.length/zoom*.6);
|
| 144 |
-
let placed=[];for(const n of labels){let angle=START+SPAN*(n.mid+.5)/leaves.length;let [x,y]=screen(polar(R+BAR_HEIGHT+42,angle));if(x<35||x>W-35||y<25||y>H-25)continue;let name=n.common||n.name;if(name.length>27)name=n.name;ctx.font=(zoom<2.5?'500 13px':'500 12px')+' Inter';let tw=ctx.measureText(name).width,anchor=Math.cos(angle)>.25?'left':Math.cos(angle)<-.25?'right':'center';let bx=anchor==='left'?x:anchor==='right'?x-tw:x-tw/2;if(bx<8){x+=8-bx;bx=8}if(bx+tw>W-8){x-=bx+tw-W+8;bx=W-8-tw}if(placed.some(b=>bx<b.x+b.w+8&&bx+tw>b.x-8&&Math.abs(y-b.y)<32))continue;placed.push({x:bx,y,w:tw});ctx.textAlign=anchor;ctx.fillStyle='#273b30';ctx.strokeStyle='#fff';ctx.lineWidth=4;ctx.strokeText(name,x,y);ctx.fillText(name,x,y);ctx.font='10px Inter';ctx.fillStyle='#7a857f';ctx.strokeText(fmt(n.count)+' assemblies',x,y+15);ctx.fillText(fmt(n.count)+' assemblies',x,y+15);}
|
| 145 |
drawAtlasIcons();
|
| 146 |
if(selected){const a=selected;ctx.strokeStyle='#15392c';ctx.lineWidth=1.8;ctx.beginPath();let p=screen(a.points[0]);ctx.moveTo(...p);for(let j=1;j<a.points.length;j++){let [c,d]=controls(a.points[j-1],a.points[j]);ctx.bezierCurveTo(...screen(c),...screen(d),...screen(a.points[j]));}ctx.stroke();let q=screen(a.tip);ctx.fillStyle='#15392c';ctx.beginPath();ctx.arc(...q,4,0,TAU);ctx.fill();}
|
| 147 |
$('#zoom-readout').textContent=zoom.toFixed(1)+'脳';$('#zoomout').disabled=zoom<=1;$('#zoomin').disabled=zoom>=320;
|
|
|
|
| 141 |
ctx.setTransform(dpr,0,0,dpr,0,0);ctx.clearRect(0,0,W,H);drawLoci();
|
| 142 |
if(zoom<2){let c=screen([0,0]);ctx.textAlign='center';ctx.fillStyle='#14221c';ctx.font='700 17px Manrope';ctx.fillText(fmt(leaves.length),c[0],c[1]+1);ctx.fillStyle='#748078';ctx.font='9px Inter';ctx.fillText('assembly strands',c[0],c[1]+18);}
|
| 143 |
const labels=zoom<2.5?groups:[...nodes.values()].filter(n=>['family','order','genus'].includes(n.rank)&&n.count>10&&n.count<leaves.length/zoom*.6);
|
| 144 |
+
let placed=locusMode!=='off'&&zoom<1.6?[{x:W/2+pan.x-36,y:screen(polar(R+BAR_GAP+BAR_HEIGHT,START))[1]-14,w:72}]:[];for(const n of labels){let angle=START+SPAN*(n.mid+.5)/leaves.length;let [x,y]=screen(polar(R+BAR_HEIGHT+42,angle));if(x<35||x>W-35||y<25||y>H-25)continue;let name=n.common||n.name;if(name.length>27)name=n.name;ctx.font=(zoom<2.5?'500 13px':'500 12px')+' Inter';ctx.save();ctx.font='10px Inter';let cw=ctx.measureText(fmt(n.count)+' assemblies').width;ctx.restore();let tw=Math.max(ctx.measureText(name).width,cw),anchor=Math.cos(angle)>.25?'left':Math.cos(angle)<-.25?'right':'center';let bx=anchor==='left'?x:anchor==='right'?x-tw:x-tw/2;if(bx<8){x+=8-bx;bx=8}if(bx+tw>W-8){x-=bx+tw-W+8;bx=W-8-tw}if(placed.some(b=>bx<b.x+b.w+8&&bx+tw>b.x-8&&Math.abs(y-b.y)<32))continue;placed.push({x:bx,y,w:tw});ctx.textAlign=anchor;ctx.fillStyle='#273b30';ctx.strokeStyle='#fff';ctx.lineWidth=4;ctx.strokeText(name,x,y);ctx.fillText(name,x,y);ctx.font='10px Inter';ctx.fillStyle='#7a857f';ctx.strokeText(fmt(n.count)+' assemblies',x,y+15);ctx.fillText(fmt(n.count)+' assemblies',x,y+15);}
|
| 145 |
drawAtlasIcons();
|
| 146 |
if(selected){const a=selected;ctx.strokeStyle='#15392c';ctx.lineWidth=1.8;ctx.beginPath();let p=screen(a.points[0]);ctx.moveTo(...p);for(let j=1;j<a.points.length;j++){let [c,d]=controls(a.points[j-1],a.points[j]);ctx.bezierCurveTo(...screen(c),...screen(d),...screen(a.points[j]));}ctx.stroke();let q=screen(a.tip);ctx.fillStyle='#15392c';ctx.beginPath();ctx.arc(...q,4,0,TAU);ctx.fill();}
|
| 147 |
$('#zoom-readout').textContent=zoom.toFixed(1)+'脳';$('#zoomout').disabled=zoom<=1;$('#zoomin').disabled=zoom>=320;
|
overview.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|