Spaces:
Running
Running
Say what each board measures; link entrants to their profile
Browse filesA board name and a target symbol only read to specialists. Each board now carries a one-line description in both languages, shown on the leader table, the board cards and the board header. Entrant names link to their Hugging Face profile.
- app.py +14 -0
- board_meta.json +29 -0
- index.html +14 -3
app.py
CHANGED
|
@@ -87,7 +87,17 @@ def _sha(path):
|
|
| 87 |
return h.hexdigest()[:16]
|
| 88 |
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
def _load_boards():
|
|
|
|
| 91 |
out = {}
|
| 92 |
for p in sorted(glob.glob(os.path.join(DATA, "*_card.json"))):
|
| 93 |
try:
|
|
@@ -120,6 +130,9 @@ def _load_boards():
|
|
| 120 |
d["beats_constant"] = base["Morgan+LightGBM"]["mae"] < base["μμ μμΈ‘"]["mae"]
|
| 121 |
if d.get("n_test"):
|
| 122 |
d["near_pct"] = round(100.0 * d.get("near_threshold", 0) / d["n_test"], 1)
|
|
|
|
|
|
|
|
|
|
| 123 |
d["open"] = True
|
| 124 |
out[d["board"]] = d
|
| 125 |
return out
|
|
@@ -254,6 +267,7 @@ def api_leaders():
|
|
| 254 |
nf = (b.get("noise_floor") or {}).get("sd_single")
|
| 255 |
base = b.get("baselines") or {}
|
| 256 |
row = {"board": name, "n_test": b.get("n_test"),
|
|
|
|
| 257 |
"split_grade": b.get("split_grade"), "answer_grade": b.get("answer_grade"),
|
| 258 |
"noise_floor": nf, "entries": len(ent),
|
| 259 |
"baseline_best": (min((v["mae"] for v in base.values() if v.get("mae") is not None),
|
|
|
|
| 87 |
return h.hexdigest()[:16]
|
| 88 |
|
| 89 |
|
| 90 |
+
def _board_meta():
|
| 91 |
+
"""λΆλ¬Έ ν μ€ μ€λͺ
. μ΄λ¦κ³Ό νμ κΈ°νΈλ§μΌλ‘λ 무μμ μ¬λμ§ μ μ μλ€."""
|
| 92 |
+
p = os.path.join(HERE, "board_meta.json")
|
| 93 |
+
try:
|
| 94 |
+
return json.load(io.open(p, encoding="utf-8")).get("boards", {})
|
| 95 |
+
except Exception:
|
| 96 |
+
return {}
|
| 97 |
+
|
| 98 |
+
|
| 99 |
def _load_boards():
|
| 100 |
+
meta = _board_meta()
|
| 101 |
out = {}
|
| 102 |
for p in sorted(glob.glob(os.path.join(DATA, "*_card.json"))):
|
| 103 |
try:
|
|
|
|
| 130 |
d["beats_constant"] = base["Morgan+LightGBM"]["mae"] < base["μμ μμΈ‘"]["mae"]
|
| 131 |
if d.get("n_test"):
|
| 132 |
d["near_pct"] = round(100.0 * d.get("near_threshold", 0) / d["n_test"], 1)
|
| 133 |
+
m = meta.get(d["board"]) or {}
|
| 134 |
+
d["blurb"] = m.get("ko", "")
|
| 135 |
+
d["blurb_en"] = m.get("en", "")
|
| 136 |
d["open"] = True
|
| 137 |
out[d["board"]] = d
|
| 138 |
return out
|
|
|
|
| 267 |
nf = (b.get("noise_floor") or {}).get("sd_single")
|
| 268 |
base = b.get("baselines") or {}
|
| 269 |
row = {"board": name, "n_test": b.get("n_test"),
|
| 270 |
+
"blurb": b.get("blurb"), "blurb_en": b.get("blurb_en"),
|
| 271 |
"split_grade": b.get("split_grade"), "answer_grade": b.get("answer_grade"),
|
| 272 |
"noise_floor": nf, "entries": len(ent),
|
| 273 |
"baseline_best": (min((v["mae"] for v in base.values() if v.get("mae") is not None),
|
board_meta.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"note": "λΆλ¬Έ μ΄λ¦λ§μΌλ‘λ 무μμ μ¬λμ§ μ μ μλ€. νμ κΈ°νΈλ μ΄ λΆμΌ μ¬λμκ²λ§ μ½νλ€.",
|
| 3 |
+
"boards": {
|
| 4 |
+
"hERG": {"ko": "μ¬μ₯λ
μ± β μΉΌλ₯¨μ±λ μ°¨λ¨", "en": "Cardiotoxicity β hERG channel block"},
|
| 5 |
+
"Solubility": {"ko": "μμ©ν΄λ β λ¬Όμ λ
Ήλ μ λ", "en": "Aqueous solubility"},
|
| 6 |
+
"Withdrawal": {"ko": "μν ν ν΄μΆ νμ ", "en": "Post-marketing withdrawal"},
|
| 7 |
+
"Phenotype": {"ko": "μΈν¬ νν λ³ν μμΈ‘", "en": "Cell morphology response"},
|
| 8 |
+
|
| 9 |
+
"CYP3A4": {"ko": "λμ¬ μ ν΄ β μ½λ¬Ό μνΈμμ© μ΅λ μμΈ", "en": "CYP3A4 inhibition β main cause of drug interaction"},
|
| 10 |
+
"CYP2D6": {"ko": "λμ¬ μ ν΄ β κ°μΈμ°¨κ° ν° ν¨μ", "en": "CYP2D6 inhibition β highly polymorphic enzyme"},
|
| 11 |
+
"CYP2C9": {"ko": "λμ¬ μ ν΄ β μνλ¦° κ³μ΄", "en": "CYP2C9 inhibition β warfarin class"},
|
| 12 |
+
|
| 13 |
+
"EGFR": {"ko": "νμ νμ β μνΌμ±μ₯μΈμ μμ©μ²΄", "en": "Lung cancer target β EGF receptor"},
|
| 14 |
+
"JAK2": {"ko": "골μμ¦μμ§ν νμ ", "en": "Myeloproliferative disease target"},
|
| 15 |
+
"PI3Ka": {"ko": "μ’
μ μ νΈμ λ¬ νμ ", "en": "Tumour signalling target"},
|
| 16 |
+
"FLT3": {"ko": "κΈμ±κ³¨μλ°±νλ³ νμ ", "en": "Acute myeloid leukaemia target"},
|
| 17 |
+
"VEGFR2": {"ko": "νκ΄μ μ νμ β μ’
μ νκ΄ μ°¨λ¨", "en": "Angiogenesis target"},
|
| 18 |
+
"CDK2": {"ko": "μΈν¬μ£ΌκΈ° νμ ", "en": "Cell cycle target"},
|
| 19 |
+
"HER2": {"ko": "μ λ°©μ νμ ", "en": "Breast cancer target"},
|
| 20 |
+
"ABL1": {"ko": "λ§μ±κ³¨μλ°±νλ³ νμ ", "en": "Chronic myeloid leukaemia target"},
|
| 21 |
+
"BRAF": {"ko": "νμμ’
νμ ", "en": "Melanoma target"},
|
| 22 |
+
"KIT": {"ko": "μμ₯κ΄κΈ°μ§μ’
μ νμ ", "en": "GIST target"},
|
| 23 |
+
"ALK": {"ko": "νμ μ΅ν© νμ ", "en": "Lung cancer fusion target"},
|
| 24 |
+
|
| 25 |
+
"AChE": {"ko": "μμΈ νμ΄λ¨Έ νμ β μμΈνΈμ½λ¦° λΆν΄ν¨μ", "en": "Alzheimer target β acetylcholinesterase"},
|
| 26 |
+
"MAOB": {"ko": "νν¨μ¨ νμ β λͺ¨λ
Έμλ―Ό μ°νν¨μ B", "en": "Parkinson target β monoamine oxidase B"},
|
| 27 |
+
"COX2": {"ko": "μμΌμ§ν΅ νμ ", "en": "Anti-inflammatory target"}
|
| 28 |
+
}
|
| 29 |
+
}
|
index.html
CHANGED
|
@@ -173,6 +173,9 @@
|
|
| 173 |
.rk.g3{background:#c9885526;color:#95612f}
|
| 174 |
.gain{color:var(--good);font-weight:700}
|
| 175 |
.loss{color:var(--bad);font-weight:700}
|
|
|
|
|
|
|
|
|
|
| 176 |
.mini{display:inline-block;height:6px;border-radius:3px;background:var(--acc);opacity:.5;
|
| 177 |
vertical-align:middle;margin-right:7px}
|
| 178 |
|
|
@@ -239,6 +242,10 @@ const $=s=>document.querySelector(s), app=$("#app");
|
|
| 239 |
const f=(x,d=3)=>(x==null||isNaN(x))?"β":Number(x).toFixed(d);
|
| 240 |
const esc=s=>String(s??"").replace(/[&<>"]/g,c=>({"&":"&","<":"<",">":">",'"':"""}[c]));
|
| 241 |
const W=h=>`<div class="wrap">${h}</div>`;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
let CATS=null, ME={user:null}, BOARDS={}, L=null, t=null;
|
| 243 |
|
| 244 |
/* μΈμ΄ κ²°μ μμ: μ μ₯λ μ ν β λΈλΌμ°μ μ€μ β μμ΄.
|
|
@@ -290,6 +297,7 @@ function terrain(items,link){
|
|
| 290 |
}
|
| 291 |
/* λΆλ₯ μ μ© λΆλ¬Έμ MAE κΈ°μ€μ μ΄ μλ€. κ·Έλ° λΆλ¬Έμ 0 μΌλ‘ μ²λ¦¬νλ©΄ μ§νλ 맨 μΌμͺ½μ
|
| 292 |
λΆμ΄ "μΈ‘μ νκ³μ λλ¬νλ€"λ‘ λ³΄μΈλ€. μ¬μ§ λͺ»ν κ²κ³Ό μ¬μ μμ κ²μ λ€λ₯΄λ―λ‘ λΉμ΄λ€. */
|
|
|
|
| 293 |
const ratioOf=b=>{
|
| 294 |
const nf=(b.noise_floor||{}).sd_single;
|
| 295 |
const maes=Object.values(b.baselines||{}).map(v=>v.mae).filter(v=>v!=null);
|
|
@@ -408,9 +416,10 @@ async function paintLeaders(){
|
|
| 408 |
}
|
| 409 |
return `<tr>
|
| 410 |
<td style="text-align:left"><a href="#/b/${encodeURIComponent(r.board)}">${esc(r.board)}</a>
|
| 411 |
-
<span class="chip g" style="margin-left:6px">${r.split_grade}/${r.answer_grade}</span>
|
|
|
|
| 412 |
<td style="text-align:left">${L?esc(L.method):`<span class="dim">${t.noLeader}</span>`}</td>
|
| 413 |
-
<td style="text-align:left">${L?
|
| 414 |
<td>${score!=null?f(score):"β"}</td>
|
| 415 |
<td>${vs}</td>
|
| 416 |
<td>${(r.n_test||0).toLocaleString()}</td></tr>`;}).join("");
|
|
@@ -459,6 +468,7 @@ function boardMini(b){
|
|
| 459 |
const bl=b.baselines[b.best_baseline]||{};
|
| 460 |
return `<a class="cc" href="#/b/${encodeURIComponent(b.board)}">
|
| 461 |
<div class="nm">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></div>
|
|
|
|
| 462 |
<div class="ds">${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} ${f((b.noise_floor||{}).sd_single)}<br>
|
| 463 |
${esc(b.best_baseline)} ${bl.mae!=null?f(bl.mae):f(bl.auroc)}</div>
|
| 464 |
<div class="mt"><span>${esc(b.source)}</span><span>${ratioOf(b)==null?"β":f(ratioOf(b),2)+"Γ"}</span></div></a>`;
|
|
@@ -473,6 +483,7 @@ async function board(name,tab){
|
|
| 473 |
app.innerHTML=W(`
|
| 474 |
<div class="crumb"><a href="#/">${t.all}</a> βΊ <a href="#/c/${cat?cat.id:""}">${esc(cn)}</a> βΊ ${esc(b.board)}</div>
|
| 475 |
<h1 class="ttl">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></h1>
|
|
|
|
| 476 |
<p class="lede">${esc(b.source)} Β· ${esc(b.type)} Β·
|
| 477 |
${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} <b>${f(b.noise_floor.sd_single)}</b></p>
|
| 478 |
<div class="pills">${TT.map(([k,l])=>
|
|
@@ -495,7 +506,7 @@ async function paneRank(b){
|
|
| 495 |
const w=Math.max(4,58*(r.mae||0)/worst);
|
| 496 |
return `<tr class="${r.kind!=="entry"?"base":""}">
|
| 497 |
<td>${r.rank?`<span class="rk${g}">${r.rank}</span>`:"Β·"}</td>
|
| 498 |
-
<td>${esc(r.method)}</td><td>${esc(r.user)}</td>
|
| 499 |
<td><span class="mini" style="width:${w}px"></span>${f(r.mae)}</td>
|
| 500 |
<td>${f(r.auroc)}</td><td>${f(r.prauc)}</td>
|
| 501 |
<td>${r.kind==="baseline"?`<span class="chip g">${t.baseline}</span>`:leak(r.leak)}</td>
|
|
|
|
| 173 |
.rk.g3{background:#c9885526;color:#95612f}
|
| 174 |
.gain{color:var(--good);font-weight:700}
|
| 175 |
.loss{color:var(--bad);font-weight:700}
|
| 176 |
+
.sub2{font-size:11.5px;color:var(--muted);font-family:inherit;font-weight:400;margin-top:3px}
|
| 177 |
+
.cc .bl{font-size:12.5px;color:var(--acc);font-weight:600;margin:-1px 0 6px}
|
| 178 |
+
.blurbig{font-size:17px;color:var(--ink2);font-weight:600;margin:2px 0 8px}
|
| 179 |
.mini{display:inline-block;height:6px;border-radius:3px;background:var(--acc);opacity:.5;
|
| 180 |
vertical-align:middle;margin-right:7px}
|
| 181 |
|
|
|
|
| 242 |
const f=(x,d=3)=>(x==null||isNaN(x))?"β":Number(x).toFixed(d);
|
| 243 |
const esc=s=>String(s??"").replace(/[&<>"]/g,c=>({"&":"&","<":"<",">":">",'"':"""}[c]));
|
| 244 |
const W=h=>`<div class="wrap">${h}</div>`;
|
| 245 |
+
/* μ μΆμλ νκΉ
νμ΄μ€ κ³μ μ΄λ€. μ΄λ¦λ§ μ μΌλ©΄ λꡬμΈμ§ νμΈν κΈΈμ΄ μλ€. */
|
| 246 |
+
const hfUser=u=>u&&u!=="β"
|
| 247 |
+
?`<a href="https://huggingface.co/${encodeURIComponent(u)}" target="_blank" rel="noopener">${esc(u)}</a>`
|
| 248 |
+
:"β";
|
| 249 |
let CATS=null, ME={user:null}, BOARDS={}, L=null, t=null;
|
| 250 |
|
| 251 |
/* μΈμ΄ κ²°μ μμ: μ μ₯λ μ ν β λΈλΌμ°μ μ€μ β μμ΄.
|
|
|
|
| 297 |
}
|
| 298 |
/* λΆλ₯ μ μ© λΆλ¬Έμ MAE κΈ°μ€μ μ΄ μλ€. κ·Έλ° λΆλ¬Έμ 0 μΌλ‘ μ²λ¦¬νλ©΄ μ§νλ 맨 μΌμͺ½μ
|
| 299 |
λΆμ΄ "μΈ‘μ νκ³μ λλ¬νλ€"λ‘ λ³΄μΈλ€. μ¬μ§ λͺ»ν κ²κ³Ό μ¬μ μμ κ²μ λ€λ₯΄λ―λ‘ λΉμ΄λ€. */
|
| 300 |
+
const blurb=b=>esc(L==="ko"?(b.blurb||""):(b.blurb_en||b.blurb||""));
|
| 301 |
const ratioOf=b=>{
|
| 302 |
const nf=(b.noise_floor||{}).sd_single;
|
| 303 |
const maes=Object.values(b.baselines||{}).map(v=>v.mae).filter(v=>v!=null);
|
|
|
|
| 416 |
}
|
| 417 |
return `<tr>
|
| 418 |
<td style="text-align:left"><a href="#/b/${encodeURIComponent(r.board)}">${esc(r.board)}</a>
|
| 419 |
+
<span class="chip g" style="margin-left:6px">${r.split_grade}/${r.answer_grade}</span>
|
| 420 |
+
<div class="sub2">${esc(L==="ko"?(r.blurb||""):(r.blurb_en||r.blurb||""))}</div></td>
|
| 421 |
<td style="text-align:left">${L?esc(L.method):`<span class="dim">${t.noLeader}</span>`}</td>
|
| 422 |
+
<td style="text-align:left">${L?hfUser(L.user):"β"}</td>
|
| 423 |
<td>${score!=null?f(score):"β"}</td>
|
| 424 |
<td>${vs}</td>
|
| 425 |
<td>${(r.n_test||0).toLocaleString()}</td></tr>`;}).join("");
|
|
|
|
| 468 |
const bl=b.baselines[b.best_baseline]||{};
|
| 469 |
return `<a class="cc" href="#/b/${encodeURIComponent(b.board)}">
|
| 470 |
<div class="nm">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></div>
|
| 471 |
+
<div class="bl">${blurb(b)}</div>
|
| 472 |
<div class="ds">${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} ${f((b.noise_floor||{}).sd_single)}<br>
|
| 473 |
${esc(b.best_baseline)} ${bl.mae!=null?f(bl.mae):f(bl.auroc)}</div>
|
| 474 |
<div class="mt"><span>${esc(b.source)}</span><span>${ratioOf(b)==null?"β":f(ratioOf(b),2)+"Γ"}</span></div></a>`;
|
|
|
|
| 483 |
app.innerHTML=W(`
|
| 484 |
<div class="crumb"><a href="#/">${t.all}</a> βΊ <a href="#/c/${cat?cat.id:""}">${esc(cn)}</a> βΊ ${esc(b.board)}</div>
|
| 485 |
<h1 class="ttl">${esc(b.board)}<span class="chip">${b.split_grade}/${b.answer_grade}</span></h1>
|
| 486 |
+
<p class="blurbig">${blurb(b)}</p>
|
| 487 |
<p class="lede">${esc(b.source)} Β· ${esc(b.type)} Β·
|
| 488 |
${t.cardCompounds(b.n_test.toLocaleString())} Β· ${t.noiseH} <b>${f(b.noise_floor.sd_single)}</b></p>
|
| 489 |
<div class="pills">${TT.map(([k,l])=>
|
|
|
|
| 506 |
const w=Math.max(4,58*(r.mae||0)/worst);
|
| 507 |
return `<tr class="${r.kind!=="entry"?"base":""}">
|
| 508 |
<td>${r.rank?`<span class="rk${g}">${r.rank}</span>`:"Β·"}</td>
|
| 509 |
+
<td>${esc(r.method)}</td><td>${r.kind==="entry"?hfUser(r.user):esc(r.user)}</td>
|
| 510 |
<td><span class="mini" style="width:${w}px"></span>${f(r.mae)}</td>
|
| 511 |
<td>${f(r.auroc)}</td><td>${f(r.prauc)}</td>
|
| 512 |
<td>${r.kind==="baseline"?`<span class="chip g">${t.baseline}</span>`:leak(r.leak)}</td>
|