Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from pydantic import BaseModel, Field | |
| from app.agents.d3.registry import D3Template, register | |
| class PieSlice(BaseModel): | |
| label: str | |
| value: float = Field(ge=0) | |
| class PieChartData(BaseModel): | |
| title: str = "" | |
| metric_label: str = "Value" | |
| data: list[PieSlice] = Field(min_length=2, max_length=16) | |
| _HTML = """<!DOCTYPE html><html><head><meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v7.min.js"></script> | |
| <style> | |
| html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#FAF7F2;color:#1A3557;font-family:Inter,system-ui,sans-serif}*{box-sizing:border-box} | |
| #root{width:100%;height:100%;position:relative}.title{position:absolute;left:24px;top:18px;font-family:Georgia,'Libre Caslon Text',serif;font-size:20px;font-weight:700;z-index:2} | |
| svg{width:100%;height:100%}.slice{stroke:#FAF7F2;stroke-width:3;cursor:pointer;transition:opacity .15s}.slice:hover{opacity:.78}.label{font-size:13px;font-weight:650;fill:#1A3557}.value{font-size:11px;fill:#58708A}.leader{fill:none;stroke:#8DA4BA;stroke-width:1.2} | |
| .tip{position:absolute;pointer-events:none;opacity:0;background:#fff;border:1px solid #C8D5E1;border-radius:8px;padding:8px 10px;box-shadow:0 8px 24px #1A355722;font-size:12px}.legend{position:absolute;right:18px;bottom:16px;display:flex;flex-wrap:wrap;justify-content:flex-end;gap:7px;max-width:42%;font-size:11px}.legend span{display:flex;align-items:center;gap:5px}.dot{width:9px;height:9px;border-radius:50%} | |
| </style></head><body><div id="root"><div class="title"></div><div class="tip"></div><div class="legend"></div></div><script> | |
| const spec=__DATA__,root=d3.select('#root'),tip=root.select('.tip');root.select('.title').text(spec.title); | |
| const W=960,H=600,cx=400,cy=315,r=220,total=d3.sum(spec.data,d=>d.value),colors=['#1A3557','#D77932','#4A8C74','#8A5C9B','#D2A84A','#4A7FB5','#B95555','#6F879D','#A87652','#617A45']; | |
| const color=d3.scaleOrdinal().domain(spec.data.map(d=>d.label)).range(colors),svg=root.append('svg').attr('viewBox',`0 0 ${W} ${H}`),g=svg.append('g').attr('transform',`translate(${cx},${cy})`),arc=d3.arc().innerRadius(0).outerRadius(r),outer=d3.arc().innerRadius(r*1.08).outerRadius(r*1.08),pie=d3.pie().sort(null).value(d=>d.value); | |
| const arcs=pie(spec.data);g.selectAll('path.slice').data(arcs).join('path').attr('class','slice').attr('d',arc).attr('fill',d=>color(d.data.label)).on('mousemove',(e,d)=>tip.style('opacity',1).style('left',`${e.offsetX+14}px`).style('top',`${e.offsetY-10}px`).html(`<strong>${d.data.label}</strong><br>${spec.metric_label}: ${d3.format(',.4~g')(d.data.value)}<br>${d3.format('.1%')(d.data.value/total)}`)).on('mouseleave',()=>tip.style('opacity',0)); | |
| const side=d=>((d.startAngle+d.endAngle)/2)<Math.PI?1:-1;g.selectAll('path.leader').data(arcs).join('path').attr('class','leader').attr('d',d=>{const p=outer.centroid(d),q=[side(d)*295,p[1]];return `M${arc.centroid(d)}L${p}L${q}`}); | |
| const labels=g.selectAll('g.lab').data(arcs).join('g').attr('class','lab').attr('transform',d=>{const p=outer.centroid(d);return `translate(${side(d)*305},${p[1]})`}).attr('text-anchor',d=>side(d)>0?'start':'end');labels.append('text').attr('class','label').text(d=>d.data.label);labels.append('text').attr('class','value').attr('dy','1.35em').text(d=>`${d3.format(',.4~g')(d.data.value)} · ${d3.format('.1%')(d.data.value/total)}`); | |
| root.select('.legend').selectAll('span').data(spec.data).join('span').html(d=>`<i class="dot" style="background:${color(d.label)}"></i>${d.label}`); | |
| </script></body></html>""" | |
| register(D3Template(id="pie_chart", family="chart", title="Pie chart", when_to_use="Show part-to-whole proportions for one explicitly selected metric.", data_requirements="Two to sixteen named non-negative values that form one meaningful whole.", schema=PieChartData, html_template=_HTML, golden_sample=PieChartData(title="Share by model", metric_label="Average score", data=[PieSlice(label="Qwen", value=22.6), PieSlice(label="DeepSeek", value=21.7), PieSlice(label="Base", value=15.0), PieSlice(label="SFT", value=23.1)]))) | |