emsesc commited on
Commit
fe024d4
·
1 Parent(s): cede300
Files changed (3) hide show
  1. app.py +66 -225
  2. assets/styles.css +198 -5
  3. graphs/leaderboard.py +7 -4
app.py CHANGED
@@ -6,7 +6,7 @@ import time
6
  from graphs.leaderboard import (
7
  button_style,
8
  get_top_n_leaderboard,
9
- render_table_content,
10
  )
11
  from dash_iconify import DashIconify
12
 
@@ -58,9 +58,9 @@ def load_parquet_to_duckdb(con, parquet_url, view_name):
58
  con = duckdb.connect(database=":memory:", read_only=False)
59
 
60
  # Load parquet files from Hugging Face using DuckDB
61
- HF_DATASET_ID = "emsesc/open_model_evolution_data"
62
- hf_parquet_url_1 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/all_downloads_with_annotations.parquet"
63
- hf_parquet_url_2 = "https://huggingface.co/datasets/emsesc/open_model_evolution_data/resolve/main/one_year_rolling.parquet"
64
 
65
  print(f"Attempting to connect to dataset from Hugging Face Hub: {HF_DATASET_ID}")
66
  try:
@@ -196,71 +196,32 @@ app.layout = dmc.MantineProvider(
196
  },
197
  children=[
198
  dcc.Store(id="selected-view", data="all_downloads"),
199
- dcc.Store(
200
- id="model-attribution-type", data="uploader"
201
- ),
202
  html.Div(
203
  [
204
  # Header
205
  html.Div(
206
  [
207
- # --- Replace title/subtitle with LIVE button and last updated ---
208
  html.Div(
209
  [
210
  html.Span(
211
  [
212
  html.Span(
213
- style={
214
- "display": "inline-block",
215
- "width": "14px",
216
- "height": "14px",
217
- "borderRadius": "50%",
218
- "backgroundColor": "#AC482A",
219
- "marginRight": "8px",
220
- "verticalAlign": "middle",
221
- "boxShadow": "0 0 6px #AC482A",
222
- },
223
  ),
224
  html.Span(
225
  "LIVE",
226
- style={
227
- "backgroundColor": "transparent",
228
- "color": "#fff",
229
- "fontWeight": "700",
230
- "fontSize": "18px",
231
- "letterSpacing": "1px",
232
- "verticalAlign": "middle",
233
- "display": "inline-block",
234
- },
235
  ),
236
  ],
237
- style={
238
- "display": "inline-flex",
239
- "alignItems": "center",
240
- "marginRight": "16px",
241
- },
242
  ),
243
  html.Span(
244
  f"Last updated: {get_last_updated()}",
245
- style={
246
- "backgroundColor": "#1B344D",
247
- "color": "#FFFFFF",
248
- "fontWeight": "500",
249
- "fontSize": "15px",
250
- "verticalAlign": "middle",
251
- "display": "inline-block",
252
- "borderRadius": "8px",
253
- "padding": "4px 14px",
254
- "boxShadow": "0 1px 4px rgba(8,32,48,0.10)",
255
- "marginLeft": "0px",
256
- },
257
  ),
258
  ],
259
- style={
260
- "display": "flex",
261
- "alignItems": "center",
262
- "gap": "12px",
263
- },
264
  ),
265
  html.Div(
266
  [
@@ -268,36 +229,19 @@ app.layout = dmc.MantineProvider(
268
  children=[
269
  html.Img(
270
  src="assets/images/dpi.svg",
271
- style={
272
- "height": "28px",
273
- "verticalAlign": "middle",
274
- "paddingRight": "8px",
275
- },
276
  ),
277
  "Data Provenance Initiative",
278
  ],
279
  href="https://www.dataprovenance.org/",
280
  target="_blank",
281
  className="no-bg-link header-link",
282
- style={
283
- "display": "inline-block",
284
- "padding": "6px 14px",
285
- "fontSize": 13,
286
- "color": "#FFFFFF", # white on dark header
287
- "borderRadius": "18px",
288
- "fontWeight": "700",
289
- "textDecoration": "none",
290
- "marginRight": "12px",
291
- },
292
  ),
293
  html.A(
294
  children=[
295
  html.Img(
296
  src="assets/images/hf.svg",
297
- style={
298
- "height": "30px",
299
- "verticalAlign": "middle",
300
- },
301
  ),
302
  html.Span(
303
  "Hugging Face",
@@ -307,15 +251,6 @@ app.layout = dmc.MantineProvider(
307
  href="https://huggingface.co/",
308
  target="_blank",
309
  className="no-bg-link header-link",
310
- style={
311
- "display": "inline-flex",
312
- "padding": "6px 14px",
313
- "alignItems": "center",
314
- "color": "#FFFFFF",
315
- "borderRadius": "18px",
316
- "textDecoration": "none",
317
- "marginRight": "12px",
318
- },
319
  ),
320
  html.A(
321
  children=[
@@ -327,21 +262,9 @@ app.layout = dmc.MantineProvider(
327
  href="https://www.google.com/",
328
  target="_blank",
329
  className="no-bg-link header-link paper-link",
330
- style={
331
- "display": "inline-flex",
332
- "alignItems": "center",
333
- "padding": "6px 12px",
334
- "fontSize": 14,
335
- "margin": "0 auto",
336
- "backgroundColor": "#AC482A",
337
- "color": "#FFFFFF",
338
- "borderRadius": "5px",
339
- "textDecoration": "none",
340
- "fontWeight": "700",
341
- },
342
  ),
343
  ],
344
- style={"display": "flex", "alignItems": "center"},
345
  ),
346
  ],
347
  style={
@@ -354,7 +277,6 @@ app.layout = dmc.MantineProvider(
354
  },
355
  className="responsive-header", # <-- add class
356
  ),
357
- # Title row with "live" button
358
  html.Div(
359
  [
360
  html.Span(
@@ -378,13 +300,12 @@ app.layout = dmc.MantineProvider(
378
  },
379
  className="responsive-title-row", # <-- add class
380
  ),
381
- # Intro / description below header (kept but styled to match layout)
382
  html.Div(
383
  children=[
384
  "This leaderboard assesses concentrations of power in the open model ecosystem through ranking user downloads across three groups: countries, developers, and models. Explore how user downloads of models are distributed among these groups and identify key players shaping the open model ecosystem on Hugging Face. This dashboard accompanies the paper titled ",
385
  html.A(
386
  "Economies of Open Intelligence: Tracing Power & Participation in the Model Ecosystem.",
387
- href="https://www.google.com/", # <-- update to actual paper link if available
388
  target="_blank",
389
  style={
390
  "color": "#AC482A",
@@ -403,7 +324,6 @@ app.layout = dmc.MantineProvider(
403
  },
404
  className="responsive-intro", # <-- add class
405
  ),
406
- # Main content (filters + tabs)
407
  html.Div(
408
  children=[
409
  html.Div(
@@ -442,18 +362,9 @@ app.layout = dmc.MantineProvider(
442
  ],
443
  ),
444
  ],
445
- style={
446
- "display": "inline-flex",
447
- "alignItems": "center",
448
- },
449
  ),
450
- style={
451
- "fontWeight": "700",
452
- "marginBottom": 8,
453
- "fontSize": 14,
454
- "display": "flex",
455
- "alignItems": "center",
456
- },
457
  ),
458
  html.Div(
459
  [
@@ -463,42 +374,23 @@ app.layout = dmc.MantineProvider(
463
  color="#AC482A",
464
  transitionDuration=200,
465
  data=[
466
- {
467
- "value": "all-downloads",
468
- "label": "All Downloads",
469
- },
470
- {
471
- "value": "filtered-downloads",
472
- "label": html.Span(
473
- [
474
- "Filtered Downloads",
475
- ]
476
- ),
477
- },
478
  ],
479
  mb=10,
480
  ),
481
  ],
482
- style={"display": "flex", "alignItems": "center"},
483
  ),
484
  html.Div(
485
  "Choose whether to count all downloads, or only downloads up to one year from model creation.",
486
- style={
487
- "fontSize": 13,
488
- "color": "#555",
489
- "marginBottom": "12px",
490
- },
491
  ),
492
- # New segmented control below the first one
493
  html.Div(
494
  [
495
  html.Div(
496
  "Model Attribution",
497
- style={
498
- "fontWeight": "700",
499
- "marginBottom": 8,
500
- "fontSize": 14,
501
- },
502
  ),
503
  dmc.SegmentedControl(
504
  id="model-attribution-segmented",
@@ -506,59 +398,36 @@ app.layout = dmc.MantineProvider(
506
  color="#AC482A",
507
  transitionDuration=200,
508
  data=[
509
- {
510
- "value": "uploader",
511
- "label": "Model Uploader",
512
- },
513
- {
514
- "value": "original_creator",
515
- "label": "Original Model Creator",
516
- },
517
  ],
518
  mb=10,
519
  ),
520
  html.Div(
521
  "Toggle between having downloads attributed to the account that uploaded the model, or the account that uploaded the model that this was originally derived from.",
522
- style={
523
- "fontSize": 13,
524
- "color": "#555",
525
- "marginBottom": "12px",
526
- },
527
  ),
528
  ],
529
  style={"marginTop": "10px"},
530
  ),
531
  html.Span(
532
  id="global-toggle-status",
533
- style={
534
- "marginLeft": "8px",
535
- "display": "inline-block",
536
- "marginTop": 6,
537
- },
538
  ),
539
  ],
540
- style={"flex": 1, "minWidth": "220px"},
541
  ),
542
  html.Div(
543
  [
544
  html.Div(
545
  "Download Date Range",
546
- style={
547
- "fontWeight": "700",
548
- "marginBottom": 8,
549
- "fontSize": 14,
550
- },
551
  ),
552
  time_slider,
553
  html.Div(
554
  "Adjust the time range to filter leaderboard results by when models were downloaded by users.",
555
- style={
556
- "fontSize": 13,
557
- "color": "#555",
558
- "marginTop": "32px", # increased from 24px
559
- },
560
  ),
561
- # Tip section
562
  html.Div(
563
  [
564
  html.Div(
@@ -574,77 +443,40 @@ app.layout = dmc.MantineProvider(
574
  ),
575
  html.Span("Tip"),
576
  ],
577
- style={
578
- "fontWeight": "700",
579
- "fontSize": 15,
580
- "marginBottom": "6px",
581
- "color": "#082030",
582
- "display": "flex",
583
- "alignItems": "center",
584
- },
585
  ),
586
  html.Div(
587
  [
588
  "Try switching between ",
589
  html.Span(
590
  "All Downloads",
591
- style={
592
- "fontWeight": "600",
593
- "color": "#AC482A",
594
- },
595
  ),
596
  " and ",
597
  html.Span(
598
  "Filtered Downloads",
599
- style={
600
- "fontWeight": "600",
601
- "color": "#AC482A",
602
- },
603
  ),
604
  " to compare net popularity (but many duplicate, unused downloads) versus more immediate interest as models are released. ",
605
  "You can also toggle between ",
606
  html.Span(
607
  "Model Uploader",
608
- style={
609
- "fontWeight": "600",
610
- "color": "#AC482A",
611
- },
612
  ),
613
  " and ",
614
  html.Span(
615
  "Original Model Creator",
616
- style={
617
- "fontWeight": "600",
618
- "color": "#AC482A",
619
- },
620
  ),
621
  " to see how attribution affects perceived popularity.",
622
  ],
623
- style={
624
- "fontSize": 13,
625
- "color": "#082030",
626
- "lineHeight": "1.6",
627
- },
628
  ),
629
  ],
630
- style={
631
- "backgroundColor": "#F5ECE6",
632
- "borderRadius": "14px",
633
- "padding": "18px 20px",
634
- "marginTop": "28px",
635
- "boxShadow": "0 1px 4px rgba(8,32,48,0.04)",
636
- "border": "1px solid #f0e3d6",
637
- },
638
  ),
639
  ],
640
- style={
641
- "flex": 2,
642
- "minWidth": "320px",
643
- "display": "flex",
644
- "flexDirection": "column",
645
- "justifyContent": "center",
646
- "height": "100%",
647
- },
648
  ),
649
  ],
650
  style={
@@ -684,13 +516,14 @@ app.layout = dmc.MantineProvider(
684
  },
685
  children=[
686
  html.Div(
687
- children="The country leaderboard shows how downloads are distributed across different nations, highlighting which countries are leading in model usage and adoption.",
688
- style={
689
- "fontSize": 14,
690
- "marginTop": 18,
691
- "marginBottom": 12,
692
- "textAlign": "left",
693
- },
 
694
  ),
695
  html.Div(
696
  dcc.Loading(
@@ -728,13 +561,16 @@ app.layout = dmc.MantineProvider(
728
  },
729
  children=[
730
  html.Div(
731
- children="The developer leaderboard highlights the most influential model creators on Hugging Face, showcasing which developers have garnered the highest download counts for their models.",
732
- style={
733
- "fontSize": 14,
734
- "marginTop": 18,
735
- "marginBottom": 12,
736
- "textAlign": "left",
737
- },
 
 
 
738
  ),
739
  html.Div(
740
  dcc.Loading(
@@ -774,13 +610,18 @@ app.layout = dmc.MantineProvider(
774
  },
775
  children=[
776
  html.Div(
777
- children="The model leaderboard showcases the most popular models on Hugging Face based on download counts, highlighting which models are driving adoption in the open model ecosystem.",
778
- style={
779
- "fontSize": 14,
780
- "marginTop": 18,
781
- "marginBottom": 12,
782
- "textAlign": "left",
783
- },
 
 
 
 
 
784
  ),
785
  html.Div(
786
  dcc.Loading(
 
6
  from graphs.leaderboard import (
7
  button_style,
8
  get_top_n_leaderboard,
9
+ render_table_content
10
  )
11
  from dash_iconify import DashIconify
12
 
 
58
  con = duckdb.connect(database=":memory:", read_only=False)
59
 
60
  # Load parquet files from Hugging Face using DuckDB
61
+ HF_DATASET_ID = "mmpr/open_model_evolution_data"
62
+ hf_parquet_url_1 = "https://huggingface.co/datasets/mmpr/open_model_evolution_data/resolve/main/all_downloads_with_annotations.parquet"
63
+ hf_parquet_url_2 = "https://huggingface.co/datasets/mmpr/open_model_evolution_data/resolve/main/one_year_rolling.parquet"
64
 
65
  print(f"Attempting to connect to dataset from Hugging Face Hub: {HF_DATASET_ID}")
66
  try:
 
196
  },
197
  children=[
198
  dcc.Store(id="selected-view", data="all_downloads"),
199
+ dcc.Store(id="model-attribution-type", data="uploader"),
 
 
200
  html.Div(
201
  [
202
  # Header
203
  html.Div(
204
  [
 
205
  html.Div(
206
  [
207
  html.Span(
208
  [
209
  html.Span(
210
+ className="live-dot",
 
 
 
 
 
 
 
 
 
211
  ),
212
  html.Span(
213
  "LIVE",
214
+ className="live-label",
 
 
 
 
 
 
 
 
215
  ),
216
  ],
217
+ className="live-row",
 
 
 
 
218
  ),
219
  html.Span(
220
  f"Last updated: {get_last_updated()}",
221
+ className="last-updated",
 
 
 
 
 
 
 
 
 
 
 
222
  ),
223
  ],
224
+ className="header-status-row",
 
 
 
 
225
  ),
226
  html.Div(
227
  [
 
229
  children=[
230
  html.Img(
231
  src="assets/images/dpi.svg",
232
+ className="header-logo-img",
 
 
 
 
233
  ),
234
  "Data Provenance Initiative",
235
  ],
236
  href="https://www.dataprovenance.org/",
237
  target="_blank",
238
  className="no-bg-link header-link",
 
 
 
 
 
 
 
 
 
 
239
  ),
240
  html.A(
241
  children=[
242
  html.Img(
243
  src="assets/images/hf.svg",
244
+ className="header-logo-img",
 
 
 
245
  ),
246
  html.Span(
247
  "Hugging Face",
 
251
  href="https://huggingface.co/",
252
  target="_blank",
253
  className="no-bg-link header-link",
 
 
 
 
 
 
 
 
 
254
  ),
255
  html.A(
256
  children=[
 
262
  href="https://www.google.com/",
263
  target="_blank",
264
  className="no-bg-link header-link paper-link",
 
 
 
 
 
 
 
 
 
 
 
 
265
  ),
266
  ],
267
+ className="header-links-row",
268
  ),
269
  ],
270
  style={
 
277
  },
278
  className="responsive-header", # <-- add class
279
  ),
 
280
  html.Div(
281
  [
282
  html.Span(
 
300
  },
301
  className="responsive-title-row", # <-- add class
302
  ),
 
303
  html.Div(
304
  children=[
305
  "This leaderboard assesses concentrations of power in the open model ecosystem through ranking user downloads across three groups: countries, developers, and models. Explore how user downloads of models are distributed among these groups and identify key players shaping the open model ecosystem on Hugging Face. This dashboard accompanies the paper titled ",
306
  html.A(
307
  "Economies of Open Intelligence: Tracing Power & Participation in the Model Ecosystem.",
308
+ href="https://www.google.com/",
309
  target="_blank",
310
  style={
311
  "color": "#AC482A",
 
324
  },
325
  className="responsive-intro", # <-- add class
326
  ),
 
327
  html.Div(
328
  children=[
329
  html.Div(
 
362
  ],
363
  ),
364
  ],
365
+ className="filter-label-row",
 
 
 
366
  ),
367
+ className="filter-label-container",
 
 
 
 
 
 
368
  ),
369
  html.Div(
370
  [
 
374
  color="#AC482A",
375
  transitionDuration=200,
376
  data=[
377
+ {"value": "all-downloads", "label": "All Downloads"},
378
+ {"value": "filtered-downloads", "label": html.Span(["Filtered Downloads"])},
 
 
 
 
 
 
 
 
 
 
379
  ],
380
  mb=10,
381
  ),
382
  ],
383
+ className="filter-segmented-row",
384
  ),
385
  html.Div(
386
  "Choose whether to count all downloads, or only downloads up to one year from model creation.",
387
+ className="filter-description",
 
 
 
 
388
  ),
 
389
  html.Div(
390
  [
391
  html.Div(
392
  "Model Attribution",
393
+ className="filter-label",
 
 
 
 
394
  ),
395
  dmc.SegmentedControl(
396
  id="model-attribution-segmented",
 
398
  color="#AC482A",
399
  transitionDuration=200,
400
  data=[
401
+ {"value": "uploader", "label": "Model Uploader"},
402
+ {"value": "original_creator", "label": "Original Model Creator"},
 
 
 
 
 
 
403
  ],
404
  mb=10,
405
  ),
406
  html.Div(
407
  "Toggle between having downloads attributed to the account that uploaded the model, or the account that uploaded the model that this was originally derived from.",
408
+ className="filter-description",
 
 
 
 
409
  ),
410
  ],
411
  style={"marginTop": "10px"},
412
  ),
413
  html.Span(
414
  id="global-toggle-status",
415
+ className="global-toggle-status",
 
 
 
 
416
  ),
417
  ],
418
+ className="main-content-left",
419
  ),
420
  html.Div(
421
  [
422
  html.Div(
423
  "Download Date Range",
424
+ className="filter-label",
 
 
 
 
425
  ),
426
  time_slider,
427
  html.Div(
428
  "Adjust the time range to filter leaderboard results by when models were downloaded by users.",
429
+ className="filter-description filter-description-margin",
 
 
 
 
430
  ),
 
431
  html.Div(
432
  [
433
  html.Div(
 
443
  ),
444
  html.Span("Tip"),
445
  ],
446
+ className="tip-title",
 
 
 
 
 
 
 
447
  ),
448
  html.Div(
449
  [
450
  "Try switching between ",
451
  html.Span(
452
  "All Downloads",
453
+ className="tip-highlight",
 
 
 
454
  ),
455
  " and ",
456
  html.Span(
457
  "Filtered Downloads",
458
+ className="tip-highlight",
 
 
 
459
  ),
460
  " to compare net popularity (but many duplicate, unused downloads) versus more immediate interest as models are released. ",
461
  "You can also toggle between ",
462
  html.Span(
463
  "Model Uploader",
464
+ className="tip-highlight",
 
 
 
465
  ),
466
  " and ",
467
  html.Span(
468
  "Original Model Creator",
469
+ className="tip-highlight",
 
 
 
470
  ),
471
  " to see how attribution affects perceived popularity.",
472
  ],
473
+ className="tip-description",
 
 
 
 
474
  ),
475
  ],
476
+ className="tip-section",
 
 
 
 
 
 
 
477
  ),
478
  ],
479
+ className="main-content-right",
 
 
 
 
 
 
 
480
  ),
481
  ],
482
  style={
 
516
  },
517
  children=[
518
  html.Div(
519
+ children=[
520
+ "The country leaderboard shows how downloads are distributed across different nations, highlighting which countries are leading in model usage and adoption. The metadata includes the ",
521
+ html.Span("country", className="meta-var"),
522
+ " and ",
523
+ html.Span("number of user downloads", className="meta-var"),
524
+ ".",
525
+ ],
526
+ className="tab-description",
527
  ),
528
  html.Div(
529
  dcc.Loading(
 
561
  },
562
  children=[
563
  html.Div(
564
+ children=[
565
+ "The developer leaderboard highlights the most influential model creators on Hugging Face, showcasing which developers have garnered the highest download counts for their models. The metadata includes the ",
566
+ html.Span("developer name", className="meta-var"),
567
+ ", ",
568
+ html.Span("number of user downloads", className="meta-var"),
569
+ ", and the ",
570
+ html.Span("country", className="meta-var"),
571
+ ".",
572
+ ],
573
+ className="tab-description",
574
  ),
575
  html.Div(
576
  dcc.Loading(
 
610
  },
611
  children=[
612
  html.Div(
613
+ children=[
614
+ "The model leaderboard ranks individual models based on their download counts, revealing which models are most popular among users on Hugging Face. The metadata includes the ",
615
+ html.Span("model name", className="meta-var"),
616
+ ", ",
617
+ html.Span("number of user downloads", className="meta-var"),
618
+ ", the ",
619
+ html.Span("developer", className="meta-var"),
620
+ ", and ",
621
+ html.Span("modality", className="meta-var"),
622
+ " (the input and output types of the model).",
623
+ ],
624
+ className="tab-description",
625
  ),
626
  html.Div(
627
  dcc.Loading(
assets/styles.css CHANGED
@@ -51,15 +51,21 @@
51
  .paper-link {
52
  position: relative; /* needed for positioning the arrow */
53
  overflow: visible;
 
 
 
 
 
54
  background-color: #AC482A !important; /* restore previous button color */
55
  color: #FFFFFF !important;
56
- padding: 10px 20px; /* ensure spacing matches inline styles */
57
- border-radius: 5px;
58
- font-weight: 700;
59
- display: inline-flex;
60
- align-items: center;
61
  text-decoration: none !important;
 
62
  transition: transform var(--default-transition-duration, .15s) var(--default-transition-timing-function, cubic-bezier(.4,0,.2,1)), background-color var(--default-transition-duration, .15s);
 
 
 
 
63
  }
64
 
65
  /* Small arrow placed inline to the right of the text */
@@ -124,6 +130,169 @@ button[id^="download-"]:focus {
124
  outline: none;
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  @media (max-width: 1150px) {
128
  .responsive-main-content {
129
  flex-direction: column !important;
@@ -140,6 +309,30 @@ button[id^="download-"]:focus {
140
  flex-direction: column !important;
141
  gap: 12px !important;
142
  padding: 12px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
  .responsive-title-row {
145
  margin-left: 0 !important;
 
51
  .paper-link {
52
  position: relative; /* needed for positioning the arrow */
53
  overflow: visible;
54
+ display: inline-flex !important;
55
+ align-items: center !important;
56
+ padding: 6px 12px !important;
57
+ font-size: 14px !important;
58
+ margin: 0 auto !important;
59
  background-color: #AC482A !important; /* restore previous button color */
60
  color: #FFFFFF !important;
61
+ border-radius: 5px !important;
 
 
 
 
62
  text-decoration: none !important;
63
+ font-weight: 700 !important;
64
  transition: transform var(--default-transition-duration, .15s) var(--default-transition-timing-function, cubic-bezier(.4,0,.2,1)), background-color var(--default-transition-duration, .15s);
65
+ max-width: 220px;
66
+ white-space: nowrap;
67
+ overflow: hidden;
68
+ text-overflow: ellipsis;
69
  }
70
 
71
  /* Small arrow placed inline to the right of the text */
 
130
  outline: none;
131
  }
132
 
133
+ .chip-hover-darken {
134
+ transition: background-color 0.15s;
135
+ }
136
+ .chip-hover-darken:hover,
137
+ .chip-hover-darken:focus {
138
+ background-color: #e1f2fd !important; /* slightly darker than #F0F0F0 */
139
+ }
140
+
141
+ /* Header status row */
142
+ .header-status-row {
143
+ display: flex;
144
+ align-items: center;
145
+ gap: 12px;
146
+ }
147
+ .live-row {
148
+ display: inline-flex;
149
+ align-items: center;
150
+ margin-right: 16px;
151
+ }
152
+ .live-dot {
153
+ display: inline-block;
154
+ width: 14px;
155
+ height: 14px;
156
+ border-radius: 50%;
157
+ background-color: #AC482A;
158
+ margin-right: 8px;
159
+ vertical-align: middle;
160
+ box-shadow: 0 0 6px #AC482A;
161
+ }
162
+ .live-label {
163
+ background-color: transparent;
164
+ color: #fff;
165
+ font-weight: 700;
166
+ font-size: 18px;
167
+ letter-spacing: 1px;
168
+ vertical-align: middle;
169
+ display: inline-block;
170
+ }
171
+ .last-updated {
172
+ background-color: #1B344D;
173
+ color: #FFFFFF;
174
+ font-weight: 500;
175
+ font-size: 15px;
176
+ vertical-align: middle;
177
+ display: inline-block;
178
+ border-radius: 8px;
179
+ padding: 4px 14px;
180
+ box-shadow: 0 1px 4px rgba(8,32,48,0.10);
181
+ margin-left: 0px;
182
+ }
183
+ .header-links-row {
184
+ display: flex;
185
+ align-items: center;
186
+ }
187
+ .header-link {
188
+ display: inline-flex !important;
189
+ padding: 6px 14px !important;
190
+ font-size: 13px !important;
191
+ color: #FFFFFF !important;
192
+ border-radius: 18px !important;
193
+ font-weight: 700 !important;
194
+ text-decoration: none !important;
195
+ margin-right: 12px !important;
196
+ align-items: center !important;
197
+ }
198
+ .header-logo-img {
199
+ height: 28px;
200
+ vertical-align: middle;
201
+ padding-right: 8px;
202
+ }
203
+ .main-title {
204
+ font-size: 40px;
205
+ font-weight: 700;
206
+ text-align: center;
207
+ margin-top: 20px;
208
+ margin-bottom: 20px;
209
+ }
210
+ .intro-paper-link {
211
+ color: #AC482A;
212
+ font-weight: 700;
213
+ text-decoration: underline;
214
+ }
215
+ .filter-label-row {
216
+ display: inline-flex;
217
+ align-items: center;
218
+ }
219
+ .filter-label-container {
220
+ font-weight: 700;
221
+ margin-bottom: 8px;
222
+ font-size: 14px;
223
+ display: flex;
224
+ align-items: center;
225
+ }
226
+ .filter-segmented-row {
227
+ display: flex;
228
+ align-items: center;
229
+ }
230
+ .filter-label {
231
+ font-weight: 700;
232
+ margin-bottom: 8px;
233
+ font-size: 14px;
234
+ }
235
+ .filter-description {
236
+ font-size: 13px;
237
+ color: #555;
238
+ margin-bottom: 12px;
239
+ }
240
+ .filter-description-margin {
241
+ margin-top: 32px !important;
242
+ }
243
+ .global-toggle-status {
244
+ margin-left: 8px;
245
+ display: inline-block;
246
+ margin-top: 6px;
247
+ }
248
+ .main-content-left {
249
+ flex: 1;
250
+ min-width: 220px;
251
+ }
252
+ .main-content-right {
253
+ flex: 2;
254
+ min-width: 320px;
255
+ display: flex;
256
+ flex-direction: column;
257
+ justify-content: center;
258
+ height: 100%;
259
+ }
260
+ .tip-section {
261
+ background-color: #F5ECE6;
262
+ border-radius: 14px;
263
+ padding: 18px 20px;
264
+ margin-top: 28px;
265
+ box-shadow: 0 1px 4px rgba(8,32,48,0.04);
266
+ border: 1px solid #f0e3d6;
267
+ }
268
+ .tip-title {
269
+ font-weight: 700;
270
+ font-size: 15px;
271
+ margin-bottom: 6px;
272
+ color: #082030;
273
+ display: flex;
274
+ align-items: center;
275
+ }
276
+ .tip-highlight {
277
+ font-weight: 600;
278
+ color: #AC482A;
279
+ }
280
+ .tip-description {
281
+ font-size: 13px;
282
+ color: #082030;
283
+ line-height: 1.6;
284
+ }
285
+ .tab-description {
286
+ font-size: 14px;
287
+ margin-top: 18px;
288
+ margin-bottom: 12px;
289
+ text-align: left;
290
+ }
291
+ .meta-var {
292
+ font-weight: bold;
293
+ color: #082030;
294
+ }
295
+
296
  @media (max-width: 1150px) {
297
  .responsive-main-content {
298
  flex-direction: column !important;
 
309
  flex-direction: column !important;
310
  gap: 12px !important;
311
  padding: 12px !important;
312
+ width: 100vw !important;
313
+ box-sizing: border-box !important;
314
+ }
315
+ /* Fix header link squishing: stack links vertically and center them */
316
+ .responsive-header .header-link {
317
+ display: flex !important;
318
+ flex-direction: row !important;
319
+ align-items: center !important;
320
+ justify-content: center !important;
321
+ margin-bottom: 8px !important;
322
+ width: 100% !important;
323
+ min-width: 0 !important;
324
+ font-size: 15px !important;
325
+ flex-wrap: wrap !important;
326
+ }
327
+ .responsive-header > div:last-child {
328
+ flex-direction: column !important;
329
+ align-items: center !important;
330
+ gap: 8px !important;
331
+ width: 100% !important;
332
+ }
333
+ .responsive-header .header-link img {
334
+ margin-bottom: 0 !important;
335
+ margin-right: 8px !important;
336
  }
337
  .responsive-title-row {
338
  margin-left: 0 !important;
graphs/leaderboard.py CHANGED
@@ -154,7 +154,7 @@ def get_metadata_popover_content(icon, name, meta_type):
154
  def chip_with_hovercard(text, bg_color="#F0F0F0", meta_type=None, icon=None):
155
  hovercard_content = get_metadata_popover_content(icon, text, meta_type)
156
  return dmc.HoverCard(
157
- width=220,
158
  shadow="md",
159
  position="top",
160
  children=[
@@ -170,7 +170,10 @@ def chip_with_hovercard(text, bg_color="#F0F0F0", meta_type=None, icon=None):
170
  "alignItems": "center",
171
  "fontSize": "14px",
172
  "cursor": "pointer",
 
173
  },
 
 
174
  )
175
  ),
176
  dmc.HoverCardDropdown(dmc.Text(hovercard_content, size="sm")),
@@ -330,9 +333,6 @@ def get_top_n_leaderboard(filtered_df, group_col, top_n=10, derived_author_toggl
330
  download_top["Total Value"] = download_top["Total Value"].astype(int)
331
  download_top["% of total"] = download_top["% of total"].round(2)
332
 
333
- # Replace "User" in names
334
- top["Name"] = top["Name"].replace("User", "user")
335
-
336
  # All relevant metadata columns
337
  meta_cols = meta_cols_map.get(group_col, [])
338
 
@@ -413,6 +413,9 @@ def get_top_n_leaderboard(filtered_df, group_col, top_n=10, derived_author_toggl
413
  # Apply metadata builder to top dataframe
414
  top["Metadata"] = top["Name"].astype(object).apply(build_metadata)
415
 
 
 
 
416
  # Build download dataframe with metadata
417
  download_info_list = [build_download_metadata(nm) for nm in download_top["Name"]]
418
  download_info_df = pd.DataFrame(download_info_list)
 
154
  def chip_with_hovercard(text, bg_color="#F0F0F0", meta_type=None, icon=None):
155
  hovercard_content = get_metadata_popover_content(icon, text, meta_type)
156
  return dmc.HoverCard(
157
+ width="auto",
158
  shadow="md",
159
  position="top",
160
  children=[
 
170
  "alignItems": "center",
171
  "fontSize": "14px",
172
  "cursor": "pointer",
173
+ "transition": "background-color 0.15s",
174
  },
175
+ # Add a class for hover effect
176
+ className="chip-hover-darken"
177
  )
178
  ),
179
  dmc.HoverCardDropdown(dmc.Text(hovercard_content, size="sm")),
 
333
  download_top["Total Value"] = download_top["Total Value"].astype(int)
334
  download_top["% of total"] = download_top["% of total"].round(2)
335
 
 
 
 
336
  # All relevant metadata columns
337
  meta_cols = meta_cols_map.get(group_col, [])
338
 
 
413
  # Apply metadata builder to top dataframe
414
  top["Metadata"] = top["Name"].astype(object).apply(build_metadata)
415
 
416
+ # Capitalize "user" back to "User" for display
417
+ top["Name"] = top["Name"].replace("user", "User")
418
+
419
  # Build download dataframe with metadata
420
  download_info_list = [build_download_metadata(nm) for nm in download_top["Name"]]
421
  download_info_df = pd.DataFrame(download_info_list)