joelniklaus HF Staff commited on
Commit
3ee1064
1 Parent(s): 6b845f3

made various improvements to the banner

Browse files
Files changed (1) hide show
  1. app/src/content/embeds/banner.html +70 -20
app/src/content/embeds/banner.html CHANGED
@@ -53,6 +53,11 @@
53
  'guided_rewrite_original': 'Guided Rewrite'
54
  };
55
 
 
 
 
 
 
56
  function parseEntry(d, i) {
57
  const [cat, promptFile] = d.prompt.split('/');
58
  const promptKey = promptFile.replace('.md', '');
@@ -67,7 +72,10 @@
67
  model: modelShort,
68
  family,
69
  compB: d.output_tokens / 1e9,
70
- promptB: d.input_tokens / 1e9,
 
 
 
71
  docsM: d.num_documents / 1e6,
72
  dclm: d.dclm_score_difference,
73
  edu: d.edu_score_difference,
@@ -106,7 +114,7 @@
106
 
107
  const cx = W / 2;
108
  const packR = Math.min(W * 0.28, H * 0.34);
109
- const maxR = Math.min(packR * 0.37, 56);
110
  const minR = Math.max(4, W * 0.005);
111
  const rScale = d3.scaleSqrt()
112
  .domain([0, d3.max(data, d => d.compB)])
@@ -156,23 +164,26 @@
156
  drift();
157
  });
158
 
 
 
 
159
  // Mega number
160
- canvas.append('text')
161
  .attr('x', cx).attr('y', megaY)
162
  .attr('text-anchor', 'middle').attr('dominant-baseline', 'middle')
163
  .attr('fill', '#1a1a1a')
164
  .attr('font-size', megaFS).attr('font-weight', 900)
165
  .attr('letter-spacing', '-0.04em')
166
- .text(formatTokens(totalOutputB));
167
 
168
  const labelFS = Math.max(10, megaFS * 0.15);
169
- canvas.append('text')
170
  .attr('x', cx).attr('y', megaY + megaFS * 0.44)
171
  .attr('text-anchor', 'middle').attr('dominant-baseline', 'middle')
172
  .attr('fill', '#999')
173
  .attr('font-size', labelFS).attr('font-weight', 600)
174
  .attr('letter-spacing', '0.18em')
175
- .text('TOKENS GENERATED');
176
 
177
  // Bottom stats
178
  const totalDocsB = (totalDocsM / 1000).toFixed(2);
@@ -184,9 +195,10 @@
184
  .attr('font-size', subFS).attr('font-weight', 500)
185
  .attr('letter-spacing', '0.14em')
186
  .text(subText);
 
187
 
188
  // Legend
189
- const legFS = Math.max(7, subFS * 0.95);
190
  const dotR = Math.max(2.5, legFS * 0.38);
191
  const legY = subY + subFS * 2.6;
192
  const familyCounts = {};
@@ -201,30 +213,66 @@
201
  tw -= 12;
202
  let lx = cx - tw / 2;
203
  families.forEach(it => {
204
- legG.append('circle')
 
205
  .attr('cx', lx + dotR).attr('cy', legY)
206
  .attr('r', dotR).attr('fill', col[it.n]).attr('fill-opacity', 0.5);
207
- const t = legG.append('text')
208
  .attr('x', lx + dotR * 2 + 4).attr('y', legY)
209
  .attr('dominant-baseline', 'middle')
210
  .attr('fill', '#555').attr('font-size', legFS).attr('font-weight', 500)
211
  .text(`${it.n} (${it.c})`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  lx += dotR * 2 + 4 + t.node().getComputedTextLength() + 12;
213
  });
214
 
215
- // Background pills
216
  const subBBox = subEl.node().getBBox();
217
- canvas.insert('rect', 'text:first-of-type')
218
  .attr('x', subBBox.x - 8).attr('y', subBBox.y - 3)
219
  .attr('width', subBBox.width + 16).attr('height', subBBox.height + 6)
220
  .attr('rx', 4).attr('ry', 4)
221
- .attr('fill', 'white').attr('fill-opacity', 0.75);
222
  const legBBox = legG.node().getBBox();
223
- canvas.insert('rect', 'text:first-of-type')
224
  .attr('x', legBBox.x - 8).attr('y', legBBox.y - 3)
225
  .attr('width', legBBox.width + 16).attr('height', legBBox.height + 6)
226
  .attr('rx', 4).attr('ry', 4)
227
- .attr('fill', 'white').attr('fill-opacity', 0.75);
228
 
229
  // Tooltip
230
  const tip = d3.select(container).append('div')
@@ -234,7 +282,7 @@
234
  .style('color', '#2c3e50')
235
  .style('border', '1px solid rgba(0,0,0,0.08)')
236
  .style('border-radius', '10px').style('padding', '12px 16px')
237
- .style('font-size', Math.max(10, W * 0.011) + 'px')
238
  .style('font-family', "'Inter', system-ui, sans-serif")
239
  .style('line-height', '1.55').style('white-space', 'nowrap')
240
  .style('opacity', 0).style('transition', 'opacity .1s ease')
@@ -247,7 +295,7 @@
247
  .attr('fill-opacity', 0.55).attr('stroke-opacity', 0.5).attr('stroke-width', 1.5);
248
  gB.selectAll('circle').filter(o => o.id !== d.id)
249
  .transition().duration(80)
250
- .attr('fill-opacity', 0.06).attr('stroke-opacity', 0.03);
251
  const c = col[d.family];
252
  const dc = d.dclm >= 0 ? '#16a34a' : '#dc2626';
253
  const ec = d.edu >= 0 ? '#16a34a' : '#dc2626';
@@ -257,8 +305,9 @@
257
  `<span style="font-weight:700;font-size:1.05em;color:#111">${d.model}</span></div>` +
258
  `<div style="opacity:.4;font-size:.88em;margin-bottom:7px">${d.prompt} 路 ${d.cat} 路 ${d.source}</div>` +
259
  `<div style="display:grid;grid-template-columns:auto 1fr;gap:3px 14px;font-size:.9em">` +
260
- `<span style="opacity:.35">Output</span><span style="font-weight:600;color:#111">${d.compB.toFixed(2)}B tokens</span>` +
261
- `<span style="opacity:.35">Input</span><span>${d.promptB.toFixed(2)}B</span>` +
 
262
  `<span style="opacity:.35">Docs</span><span>${d.docsM.toFixed(1)}M</span>` +
263
  `<span style="opacity:.35">DCLM</span><span style="color:${dc}">${d.dclm >= 0 ? '+' : ''}${d.dclm.toFixed(3)}</span>` +
264
  `<span style="opacity:.35">Edu</span><span style="color:${ec}">${d.edu >= 0 ? '+' : ''}${d.edu.toFixed(3)}</span></div>`
@@ -270,12 +319,13 @@
270
  let ty = event.clientY - r.top - 10;
271
  if (tx + 260 > W) tx = event.clientX - r.left - 270;
272
  if (ty < 8) ty = 8;
273
- tip.style('left', tx + 'px').style('top', ty + 'px');
 
274
  })
275
  .on('mouseleave', function() {
276
  gB.selectAll('circle').transition().duration(160)
277
  .attr('fill-opacity', fillAlpha).attr('stroke-opacity', 0.12).attr('stroke-width', 0.7);
278
- tip.style('opacity', 0);
279
  });
280
  };
281
 
 
53
  'guided_rewrite_original': 'Guided Rewrite'
54
  };
55
 
56
+ function gpuDays(seconds) {
57
+ const d = Math.round(seconds / 86400);
58
+ return d.toLocaleString() + ' days';
59
+ }
60
+
61
  function parseEntry(d, i) {
62
  const [cat, promptFile] = d.prompt.split('/');
63
  const promptKey = promptFile.replace('.md', '');
 
72
  model: modelShort,
73
  family,
74
  compB: d.output_tokens / 1e9,
75
+ outputHuman: d.output_tokens_human,
76
+ inputHuman: d.input_tokens_human,
77
+ gpuSeconds: d.gpu_time_seconds,
78
+ gpuTime: gpuDays(d.gpu_time_seconds),
79
  docsM: d.num_documents / 1e6,
80
  dclm: d.dclm_score_difference,
81
  edu: d.edu_score_difference,
 
114
 
115
  const cx = W / 2;
116
  const packR = Math.min(W * 0.28, H * 0.34);
117
+ const maxR = Math.min(packR * 0.30, 44);
118
  const minR = Math.max(4, W * 0.005);
119
  const rScale = d3.scaleSqrt()
120
  .domain([0, d3.max(data, d => d.compB)])
 
164
  drift();
165
  });
166
 
167
+ // All overlay elements pass pointer events through to circles
168
+ const noPtr = el => el.style('pointer-events', 'none');
169
+
170
  // Mega number
171
+ noPtr(canvas.append('text')
172
  .attr('x', cx).attr('y', megaY)
173
  .attr('text-anchor', 'middle').attr('dominant-baseline', 'middle')
174
  .attr('fill', '#1a1a1a')
175
  .attr('font-size', megaFS).attr('font-weight', 900)
176
  .attr('letter-spacing', '-0.04em')
177
+ .text(formatTokens(totalOutputB)));
178
 
179
  const labelFS = Math.max(10, megaFS * 0.15);
180
+ noPtr(canvas.append('text')
181
  .attr('x', cx).attr('y', megaY + megaFS * 0.44)
182
  .attr('text-anchor', 'middle').attr('dominant-baseline', 'middle')
183
  .attr('fill', '#999')
184
  .attr('font-size', labelFS).attr('font-weight', 600)
185
  .attr('letter-spacing', '0.18em')
186
+ .text('TOKENS GENERATED'));
187
 
188
  // Bottom stats
189
  const totalDocsB = (totalDocsM / 1000).toFixed(2);
 
195
  .attr('font-size', subFS).attr('font-weight', 500)
196
  .attr('letter-spacing', '0.14em')
197
  .text(subText);
198
+ noPtr(subEl);
199
 
200
  // Legend
201
+ const legFS = Math.max(11, subFS * 1.5);
202
  const dotR = Math.max(2.5, legFS * 0.38);
203
  const legY = subY + subFS * 2.6;
204
  const familyCounts = {};
 
213
  tw -= 12;
214
  let lx = cx - tw / 2;
215
  families.forEach(it => {
216
+ const ig = legG.append('g').style('cursor', 'pointer');
217
+ ig.append('circle')
218
  .attr('cx', lx + dotR).attr('cy', legY)
219
  .attr('r', dotR).attr('fill', col[it.n]).attr('fill-opacity', 0.5);
220
+ const t = ig.append('text')
221
  .attr('x', lx + dotR * 2 + 4).attr('y', legY)
222
  .attr('dominant-baseline', 'middle')
223
  .attr('fill', '#555').attr('font-size', legFS).attr('font-weight', 500)
224
  .text(`${it.n} (${it.c})`);
225
+ // Precompute cumulative stats for this family
226
+ const fam = data.filter(d => d.family === it.n);
227
+ const famOutputB = fam.reduce((s, d) => s + d.compB, 0);
228
+ const famDocsM = fam.reduce((s, d) => s + d.docsM, 0);
229
+ const famGpu = gpuDays(fam.reduce((s, d) => s + d.gpuSeconds, 0));
230
+ const famModels = [...new Set(fam.map(d => d.model))];
231
+
232
+ ig.on('mouseenter', function(event) {
233
+ circles.transition().duration(80)
234
+ .attr('fill-opacity', d => d.family === it.n ? 0.55 : 0.06)
235
+ .attr('stroke-opacity', d => d.family === it.n ? 0.5 : 0.03);
236
+ const c = col[it.n];
237
+ tip.html(
238
+ `<div style="display:flex;align-items:center;gap:6px;margin-bottom:4px">` +
239
+ `<span style="width:8px;height:8px;border-radius:50%;background:${c};opacity:.6;display:inline-block"></span>` +
240
+ `<span style="font-weight:700;font-size:1.05em;color:#111">${it.n}</span></div>` +
241
+ `<div style="display:grid;grid-template-columns:auto 1fr;gap:3px 14px;font-size:.9em">` +
242
+ `<span style="opacity:.35">Runs</span><span style="font-weight:600;color:#111">${it.c}</span>` +
243
+ `<span style="opacity:.35">Models</span><span>${famModels.join(', ')}</span>` +
244
+ `<span style="opacity:.35">Output</span><span>${formatTokens(famOutputB)} tokens</span>` +
245
+ `<span style="opacity:.35">GPU time</span><span>${famGpu}</span>` +
246
+ `<span style="opacity:.35">Docs</span><span>${famDocsM.toFixed(1)}M</span></div>`
247
+ ).style('opacity', 1);
248
+ const r = container.getBoundingClientRect();
249
+ const bbox = ig.node().getBBox();
250
+ const svgRect = canvas.node().getBoundingClientRect();
251
+ let tx = svgRect.left - r.left + bbox.x + bbox.width / 2;
252
+ let ty = svgRect.top - r.top + bbox.y + bbox.height + 8;
253
+ tip.style('left', tx + 'px').style('top', ty + 'px')
254
+ .style('transform', 'translate(-50%, 0)');
255
+ }).on('mouseleave', () => {
256
+ circles.transition().duration(160)
257
+ .attr('fill-opacity', fillAlpha).attr('stroke-opacity', 0.12);
258
+ tip.style('opacity', 0).style('transform', 'none');
259
+ });
260
  lx += dotR * 2 + 4 + t.node().getComputedTextLength() + 12;
261
  });
262
 
263
+ // Background pills (also pass through pointer events)
264
  const subBBox = subEl.node().getBBox();
265
+ noPtr(canvas.insert('rect', 'text:first-of-type')
266
  .attr('x', subBBox.x - 8).attr('y', subBBox.y - 3)
267
  .attr('width', subBBox.width + 16).attr('height', subBBox.height + 6)
268
  .attr('rx', 4).attr('ry', 4)
269
+ .attr('fill', 'white').attr('fill-opacity', 0.75));
270
  const legBBox = legG.node().getBBox();
271
+ noPtr(canvas.insert('rect', 'text:first-of-type')
272
  .attr('x', legBBox.x - 8).attr('y', legBBox.y - 3)
273
  .attr('width', legBBox.width + 16).attr('height', legBBox.height + 6)
274
  .attr('rx', 4).attr('ry', 4)
275
+ .attr('fill', 'white').attr('fill-opacity', 0.75));
276
 
277
  // Tooltip
278
  const tip = d3.select(container).append('div')
 
282
  .style('color', '#2c3e50')
283
  .style('border', '1px solid rgba(0,0,0,0.08)')
284
  .style('border-radius', '10px').style('padding', '12px 16px')
285
+ .style('font-size', Math.max(12, W * 0.014) + 'px')
286
  .style('font-family', "'Inter', system-ui, sans-serif")
287
  .style('line-height', '1.55').style('white-space', 'nowrap')
288
  .style('opacity', 0).style('transition', 'opacity .1s ease')
 
295
  .attr('fill-opacity', 0.55).attr('stroke-opacity', 0.5).attr('stroke-width', 1.5);
296
  gB.selectAll('circle').filter(o => o.id !== d.id)
297
  .transition().duration(80)
298
+ .attr('fill-opacity', 0.1).attr('stroke-opacity', 0.08);
299
  const c = col[d.family];
300
  const dc = d.dclm >= 0 ? '#16a34a' : '#dc2626';
301
  const ec = d.edu >= 0 ? '#16a34a' : '#dc2626';
 
305
  `<span style="font-weight:700;font-size:1.05em;color:#111">${d.model}</span></div>` +
306
  `<div style="opacity:.4;font-size:.88em;margin-bottom:7px">${d.prompt} 路 ${d.cat} 路 ${d.source}</div>` +
307
  `<div style="display:grid;grid-template-columns:auto 1fr;gap:3px 14px;font-size:.9em">` +
308
+ `<span style="opacity:.35">Output</span><span style="font-weight:600;color:#111">${d.outputHuman} tokens</span>` +
309
+ `<span style="opacity:.35">Input</span><span>${d.inputHuman}</span>` +
310
+ `<span style="opacity:.35">GPU time</span><span>${d.gpuTime}</span>` +
311
  `<span style="opacity:.35">Docs</span><span>${d.docsM.toFixed(1)}M</span>` +
312
  `<span style="opacity:.35">DCLM</span><span style="color:${dc}">${d.dclm >= 0 ? '+' : ''}${d.dclm.toFixed(3)}</span>` +
313
  `<span style="opacity:.35">Edu</span><span style="color:${ec}">${d.edu >= 0 ? '+' : ''}${d.edu.toFixed(3)}</span></div>`
 
319
  let ty = event.clientY - r.top - 10;
320
  if (tx + 260 > W) tx = event.clientX - r.left - 270;
321
  if (ty < 8) ty = 8;
322
+ tip.style('left', tx + 'px').style('top', ty + 'px')
323
+ .style('transform', 'none');
324
  })
325
  .on('mouseleave', function() {
326
  gB.selectAll('circle').transition().duration(160)
327
  .attr('fill-opacity', fillAlpha).attr('stroke-opacity', 0.12).attr('stroke-width', 0.7);
328
+ tip.style('opacity', 0).style('transform', 'none');
329
  });
330
  };
331