PageSourceSearch

https://huthvincent-evo2-database.hf.space/static/gtex-descriptions.js

js huthvincent-evo2-database.hf.space collected 2026-10-03 16:56:54 UTC 8,137 bytes, 88 lines download raw bytes

1/* Frozen GTEx descriptions and intron identity mapping, for research/region views. */
2(() => {
3  'use strict';
4  const instances = new WeakMap();
5  const names = {eqtl_pip_overview:'eQTL continuous PIP overview',eqtl_absz_fdr_hits:'eQTL abs(Z) n20 FDR hits',
6    sqtl_tissue_overview:'sQTL intron n10 overview',sqtl_adjustment_transitions:'sQTL same-intron transitions',intron_identity:'sQTL intron identity map'};
7  const node=(tag,text)=>{const n=document.createElement(tag);if(text!=null)n.textContent=String(text);return n;};
8  function style(){
9    if(document.getElementById('gtex-description-style'))return;
10    const s=node('style');s.id='gtex-description-style';
11    s.textContent='.gtex-descriptions{min-width:0;border:1px solid #cbd5e1;border-radius:8px;padding:1rem;margin:1rem 0;background:#fff}.gtex-descriptions h3{font-size:1rem;margin:0 0 .5rem}.gtex-descriptions p,.gtex-descriptions summary{font-size:.82rem;line-height:1.5}.gtex-descriptions .gtex-controls{display:flex;flex-wrap:wrap;gap:.7rem;margin:.7rem 0;font-size:.8rem;align-items:center}.gtex-descriptions label{display:flex;flex-direction:column;gap:.2rem}.gtex-descriptions select{max-width:100%;min-width:100px}.gtex-descriptions .gtex-table{overflow:auto;max-width:100%}.gtex-descriptions table{border-collapse:collapse;font-size:.76rem;white-space:nowrap}.gtex-descriptions th,.gtex-descriptions td{padding:.4rem;border-bottom:1px solid #e2e8f0;text-align:left}.gtex-descriptions pre{font-size:.75rem;white-space:pre-wrap;overflow-wrap:anywhere}';
12    document.head.append(s);
13  }
14  function mount(target,context={}){
15    if(!target)return;
16    const old=instances.get(target);if(old)old.destroy();
17    let dead=false,generation=0;const controllers=new Set(),urls=[];
18    const args={source:context.source,gene:context.gene||'',kind:context.descriptionKind||'',page:1};
19    const instance={destroy(){dead=true;generation++;controllers.forEach(c=>c.abort());urls.forEach(u=>URL.revokeObjectURL(u));target.replaceChildren();target.classList.remove('gtex-descriptions');if(instances.get(target)===instance)instances.delete(target);}};
20    instances.set(target,instance);target.replaceChildren();
21    if(!['gtex_eqtl','gtex_sqtl'].includes(args.source))return instance;
22    style();target.classList.add('gtex-descriptions');
23    const heading=node('h3','GTEx: original source descriptions'),status=node('p'),body=node('div');target.append(heading,status,body);
24    const alive=token=>!dead&&generation===token;
25    async function request(extra={}){
26      const controller=new AbortController();controllers.add(controller);
27      try{
28        const response=await window.Evo2Request.fetch('/api/research/gtex/descriptions',{method:'POST',headers:{'content-type':'application/json'},
29          body:JSON.stringify({...args,...extra}),signal:controller.signal});
30        if(!response.ok){let d;try{d=await response.json();}catch(e){}throw Error(d&&d.error||'GTEx descriptions are unavailable (HTTP '+response.status+').');}
31        return response;
32      }finally{controllers.delete(controller);}
33    }
34    function download(text,extension){
35      const u=URL.createObjectURL(new Blob([text],{type:extension==='csv'?'text/csv':'application/json'}));urls.push(u);
36      const a=node('a');a.href=u;a.download='evo2_gtex_'+args.kind+'.'+extension;document.body.append(a);a.click();a.remove();
37    }
38    function selectControl(parent,title,key,values,current,all=true){
39      const label=node('label',title),select=node('select');select.setAttribute('aria-label',title);
40      if(all){const o=node('option','All original groups');o.value='';select.append(o);}
41      values.forEach(value=>{const o=node('option',key==='kind'?(names[value]||value):value);o.value=value;select.append(o);});
42      select.value=current||'';select.onchange=()=>{args[key]=select.value;args.page=1;if(key==='kind')for(const field of ['tissue','configuration','analysis','test','threshold'])delete args[field];load();};
43      label.append(select);parent.append(label);
44    }
45    function render(data,token){
46      body.replaceChildren();args.kind=data.query.kind;
47      const controls=node('div');controls.className='gtex-controls';
48      const kinds=data.kinds.length?data.kinds:Object.keys(names).filter(k=>args.source==='gtex_eqtl'?k.startsWith('eqtl'):!k.startsWith('eqtl'));
49      selectControl(controls,'Original result type','kind',kinds,args.kind,false);
50      for(const [key,values] of Object.entries(data.facets||{}))selectControl(controls,key,key,values,args[key],true);
51      body.append(controls);
52      const source=data.source||{};
53      heading.textContent=(source.name||'GTEx')+' · '+(source.release||'release unverified')+' · shared freeze '+(source.freeze||'unverified');
54      if(!data.file){status.textContent='These original descriptions are not integrated. This does not mean a negative result.';return;}
55      const d=data.definitions||{};
56      status.textContent=(d.label||names[args.kind])+' · '+data.n_total.toLocaleString('en-US')+' matching original rows.';
57      if(data.message)body.append(node('p',data.message));
58      for(const text of [d.unit,d.scope,d.sample_scope,d.coordinate_system])if(text)body.append(node('p',text));
59      if(args.kind!=='intron_identity'&&args.gene)body.append(node('p','Current gene: '+args.gene+'. The overview keeps its original source denominator; it is not recomputed for this gene or its selected windows.'));
60      if(d.before_stage)body.append(node('p','Before: '+d.before_stage+' / '+d.before_test+'. After: '+d.after_stage+' / '+d.after_test+'. Original pairwise transition counts; missing or untestable results remain distinct.'));
61      body.append(node('p','P: '+d.p_definition+'. FDR: '+d.fdr_family+'.'));
62      const box=node('div');box.className='gtex-table';const table=node('table'),head=node('thead'),tr=node('tr');
63      ['Source row',...data.file.columns].forEach(c=>tr.append(node('th',c)));head.append(tr);table.append(head);
64      const tbody=node('tbody');
65      data.results.forEach(r=>{const line=node('tr');line.append(node('td',r.source_row));data.file.columns.forEach(k=>{const v=r.original[k];line.append(node('td',v==null?'Not reported':typeof v==='object'?JSON.stringify(v):v===''?'Empty source cell':v));});tbody.append(line);});
66      table.append(tbody);box.append(table);body.append(box);
67      const nav=node('div');nav.className='gtex-controls';
68      for(const [label,step] of [['Previous page',-1],['Next page',1]]){
69        const b=node('button',label);b.type='button';b.disabled=step<0?data.page===1:data.page*data.page_size>=data.n_total;
70        b.onclick=()=>{if(alive(token)){args.page+=step;load();}};nav.append(b);
71      }
72      nav.append(node('span','Page '+data.page+' · '+data.results.length+' displayed / '+data.n_total+' original rows'));
73      for(const extension of ['json','csv']){
74        const b=node('button','Export all matching '+extension.toUpperCase());b.type='button';b.disabled=!data.n_total;
75        b.onclick=async()=>{b.disabled=true;try{const response=await request({format:extension});const text=await response.text();if(alive(token))download(text,extension);}catch(e){if(alive(token)&&e.name!=='AbortError')status.textContent=e.message;}finally{if(alive(token))b.disabled=false;}};nav.append(b);
76      }
77      body.append(nav);
78      const details=node('details');details.append(node('summary','Original source, definitions and file provenance'));
79      details.addEventListener('toggle',()=>{if(details.open&&details.children.length===1)details.append(node('pre',JSON.stringify({source:data.source,file:data.file,query:data.query,no_refit:data.no_refit},null,2)));});
79body.append(details);
80    }
81    async function load(){
82      generation++;controllers.forEach(c=>c.abort());const token=generation;status.textContent='Loading original GTEx records…';body.replaceChildren();
83      try{const response=await request();const data=await response.json();if(alive(token))render(data,token);}catch(e){if(alive(token)&&e.name!=='AbortError')status.textContent=e.message;}
84    }
85    load();return instance;
86  }
87  window.Evo2GTExDescriptions={mount};
88})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.