davanstrien HF Staff commited on
Commit
22c5066
·
verified ·
1 Parent(s): 95cefed

ux: additive filter (click=narrow, more=add) + hub-link icons on every dataset row

Browse files
Files changed (1) hide show
  1. app.py +34 -7
app.py CHANGED
@@ -261,6 +261,8 @@ td.num{text-align:right;color:var(--muted);font-variant-numeric:tabular-nums;wid
261
  a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--rule);cursor:pointer}
262
  a:hover{border-color:var(--ink)}
263
  .meta a{border:0;color:var(--accent)}
 
 
264
  code{font-family:ui-monospace,monospace;font-size:12.5px;background:#f1f1e6;padding:1px 5px}
265
  .placeholder{color:var(--muted);font-style:italic}
266
  </style></head><body>
@@ -300,12 +302,13 @@ const LEGEND_TYPES=['exact_copy','filtered_subset','subset_modified','subset_ref
300
  'partial_overlap','combined','declared'];
301
  const ACTIVE_TYPES=new Set(LEGEND_TYPES);
302
  let currentNetwork=null;
303
- (function(){let h='<div style="font-style:italic;color:var(--muted);margin-bottom:3px">relationship · click to filter</div>';
304
  for(const t of LEGEND_TYPES)
305
  h+='<div class="lt" data-type="'+t+'"><span class="dot" style="background:'+(COLORS[t]||'#999')+'"></span>'+
306
  t.replace(/_/g,' ')+(t==='declared'?' (dashed)':'')+'</div>';
307
- h+='<div class="reset" data-reset="1">reset all</div>';
308
  document.getElementById('legend').innerHTML=h;})();
 
309
  function applyFilter(){
310
  if(!currentNetwork)return;
311
  const edgesDS=currentNetwork.body.data.edges, nodesDS=currentNetwork.body.data.nodes;
@@ -320,12 +323,28 @@ document.getElementById('legend').addEventListener('click',ev=>{
320
  const reset=ev.target.closest('[data-reset]');
321
  if(reset){LEGEND_TYPES.forEach(t=>ACTIVE_TYPES.add(t));
322
  document.querySelectorAll('#legend .lt').forEach(el=>el.classList.remove('off'));
323
- applyFilter();return;}
324
  const lt=ev.target.closest('.lt');
325
  if(!lt||!lt.dataset.type)return;
326
  const t=lt.dataset.type;
327
- if(ACTIVE_TYPES.has(t)){ACTIVE_TYPES.delete(t);lt.classList.add('off');}
328
- else{ACTIVE_TYPES.add(t);lt.classList.remove('off');}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  applyFilter();
330
  });
331
 
@@ -333,8 +352,15 @@ document.getElementById('legend').addEventListener('click',ev=>{
333
  function bars(rows,opts){
334
  opts=opts||{};const max=Math.max(...rows.map(r=>r.n),1);let h='<table class="bars">';
335
  for(const r of rows){const w=Math.round(100*r.n/max);
336
- const lbl=opts.type?('<span class="dot" style="background:'+(COLORS[r.t]||'#999')+'"></span>'+r.t.replace(/_/g,' '))
337
- :('<a data-ds="'+r.id+'">'+r.id+'</a>');
 
 
 
 
 
 
 
338
  const col=opts.type?(COLORS[r.t]||'#999'):'var(--bar)';
339
  h+='<tr><td class="lbl">'+lbl+'</td><td class="bar"><span style="width:'+w+'%;background:'+col+'"></span></td>'
340
  +'<td class="num">'+r.n.toLocaleString()+'</td></tr>';}
@@ -428,6 +454,7 @@ function lst(title,arr){
428
  let h='<h3>'+title+' · '+arr.length+'</h3>';
429
  for(const x of arr){const t=x.primary_type||'';
430
  h+='<div class="row">'+dot(t)+'<a data-ds="'+x.id+'">'+x.id+'</a>'+
 
431
  (t?'<span class="ty">'+t.replace(/_/g,' ')+(x.size_ratio?' ×'+x.size_ratio:'')+'</span>':'')+'</div>';}
432
  return h;
433
  }
 
261
  a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--rule);cursor:pointer}
262
  a:hover{border-color:var(--ink)}
263
  .meta a{border:0;color:var(--accent)}
264
+ a.hub{border:0;color:var(--accent);font-size:11px;margin-left:4px;padding:0 3px;opacity:.7}
265
+ a.hub:hover{opacity:1}
266
  code{font-family:ui-monospace,monospace;font-size:12.5px;background:#f1f1e6;padding:1px 5px}
267
  .placeholder{color:var(--muted);font-style:italic}
268
  </style></head><body>
 
302
  'partial_overlap','combined','declared'];
303
  const ACTIVE_TYPES=new Set(LEGEND_TYPES);
304
  let currentNetwork=null;
305
+ (function(){let h='<div style="font-style:italic;color:var(--muted);margin-bottom:3px">relationship · click to narrow</div>';
306
  for(const t of LEGEND_TYPES)
307
  h+='<div class="lt" data-type="'+t+'"><span class="dot" style="background:'+(COLORS[t]||'#999')+'"></span>'+
308
  t.replace(/_/g,' ')+(t==='declared'?' (dashed)':'')+'</div>';
309
+ h+='<div class="reset" data-reset="1">show all</div>';
310
  document.getElementById('legend').innerHTML=h;})();
311
+ let filterMode=false; // false=show-all default; flips after first click
312
  function applyFilter(){
313
  if(!currentNetwork)return;
314
  const edgesDS=currentNetwork.body.data.edges, nodesDS=currentNetwork.body.data.nodes;
 
323
  const reset=ev.target.closest('[data-reset]');
324
  if(reset){LEGEND_TYPES.forEach(t=>ACTIVE_TYPES.add(t));
325
  document.querySelectorAll('#legend .lt').forEach(el=>el.classList.remove('off'));
326
+ filterMode=false;applyFilter();return;}
327
  const lt=ev.target.closest('.lt');
328
  if(!lt||!lt.dataset.type)return;
329
  const t=lt.dataset.type;
330
+ if(!filterMode){
331
+ // first click → narrow to ONLY this type; subsequent clicks add more
332
+ ACTIVE_TYPES.clear();ACTIVE_TYPES.add(t);
333
+ document.querySelectorAll('#legend .lt').forEach(el=>el.classList.toggle('off', el.dataset.type!==t));
334
+ filterMode=true;
335
+ } else if(ACTIVE_TYPES.has(t)){
336
+ // already in view → remove
337
+ ACTIVE_TYPES.delete(t);lt.classList.add('off');
338
+ if(ACTIVE_TYPES.size===0){
339
+ // emptied → return to show-all
340
+ LEGEND_TYPES.forEach(x=>ACTIVE_TYPES.add(x));
341
+ document.querySelectorAll('#legend .lt').forEach(el=>el.classList.remove('off'));
342
+ filterMode=false;
343
+ }
344
+ } else {
345
+ // add to view
346
+ ACTIVE_TYPES.add(t);lt.classList.remove('off');
347
+ }
348
  applyFilter();
349
  });
350
 
 
352
  function bars(rows,opts){
353
  opts=opts||{};const max=Math.max(...rows.map(r=>r.n),1);let h='<table class="bars">';
354
  for(const r of rows){const w=Math.round(100*r.n/max);
355
+ let lbl;
356
+ if(opts.type){
357
+ lbl='<span class="dot" style="background:'+(COLORS[r.t]||'#999')+'"></span>'+r.t.replace(/_/g,' ');
358
+ } else {
359
+ const isDataset=r.id.includes('/');
360
+ const hubUrl='https://huggingface.co/'+(isDataset?'datasets/':'')+r.id;
361
+ lbl=(isDataset?'<a data-ds="'+r.id+'">'+r.id+'</a>':'<span>'+r.id+'</span>')+
362
+ '<a class="hub" href="'+hubUrl+'" target="_blank" rel="noopener" title="open on HF Hub">↗</a>';
363
+ }
364
  const col=opts.type?(COLORS[r.t]||'#999'):'var(--bar)';
365
  h+='<tr><td class="lbl">'+lbl+'</td><td class="bar"><span style="width:'+w+'%;background:'+col+'"></span></td>'
366
  +'<td class="num">'+r.n.toLocaleString()+'</td></tr>';}
 
454
  let h='<h3>'+title+' · '+arr.length+'</h3>';
455
  for(const x of arr){const t=x.primary_type||'';
456
  h+='<div class="row">'+dot(t)+'<a data-ds="'+x.id+'">'+x.id+'</a>'+
457
+ '<a class="hub" href="https://huggingface.co/datasets/'+x.id+'" target="_blank" rel="noopener" title="open on HF Hub">↗</a>'+
458
  (t?'<span class="ty">'+t.replace(/_/g,' ')+(x.size_ratio?' ×'+x.size_ratio:'')+'</span>':'')+'</div>';}
459
  return h;
460
  }