maxidl commited on
Commit
08afb86
Β·
verified Β·
1 Parent(s): 2c80f80

Upload index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +242 -49
index.html CHANGED
@@ -50,36 +50,29 @@
50
  .btn-danger { color: #e63946; border-color: #e6394640; }
51
  .btn-danger:hover { background: #e6394610; }
52
 
 
 
 
 
 
 
 
53
  /* ── Panel ───────────────────────────────────── */
54
  .panel {
55
  background: #fff;
56
  border: 1px solid #dee2e6;
57
  border-radius: 8px;
58
- margin-bottom: 20px;
59
  overflow: hidden;
60
  }
61
- .panel-header {
62
  display: flex;
63
  align-items: center;
64
- gap: 12px;
65
- padding: 12px 16px;
 
66
  border-bottom: 1px solid #dee2e6;
67
  background: #f8f9fa;
68
  }
69
- .panel-title {
70
- flex: 1;
71
- font-size: 0.875rem;
72
- font-weight: 600;
73
- color: #1a1a2e;
74
- white-space: nowrap;
75
- overflow: hidden;
76
- text-overflow: ellipsis;
77
- }
78
- .panel-info {
79
- font-size: 0.7rem;
80
- color: #6c757d;
81
- font-weight: 400;
82
- }
83
  .panel-controls {
84
  padding: 16px;
85
  border-bottom: 1px solid #dee2e6;
@@ -162,8 +155,58 @@
162
  }
163
 
164
  /* ── Chart ───────────────────────────────────── */
 
 
 
165
  .panel-chart {
166
  min-height: 100px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
  .loading {
169
  display: flex;
@@ -178,16 +221,23 @@
178
  .custom-tooltip {
179
  position: fixed;
180
  pointer-events: none;
181
- background: rgba(0, 0, 0, 0.8);
182
  color: #fff;
183
- padding: 6px 10px;
184
  border-radius: 4px;
185
- font-size: 12px;
186
- line-height: 1.4;
187
  z-index: 9999;
188
  display: none;
189
  white-space: nowrap;
190
  }
 
 
 
 
 
 
 
191
 
192
  /* ── Add panel button ────────────────────────── */
193
  .add-panel-row {
@@ -381,9 +431,7 @@
381
  panel.id = `panel-${this.id}`;
382
 
383
  panel.innerHTML = `
384
- <div class="panel-header">
385
- <span class="panel-title" id="ptitle-${this.id}">New Panel</span>
386
- <span class="panel-info" id="pinfo-${this.id}"></span>
387
  <button class="btn btn-sm" id="ptoggle-${this.id}">Collapse</button>
388
  <button class="btn btn-sm" id="pexport-png-${this.id}">PNG</button>
389
  <button class="btn btn-sm" id="pexport-svg-${this.id}">SVG</button>
@@ -437,15 +485,17 @@
437
  <div class="checkbox-grid" id="pmodels-${this.id}"></div>
438
  </div>
439
  </div>
440
- <div class="panel-chart" id="pchart-${this.id}"></div>
 
 
 
 
441
  `;
442
 
443
  container.appendChild(panel);
444
 
445
  // Cache refs
446
  this.el.panel = panel;
447
- this.el.title = panel.querySelector(`#ptitle-${this.id}`);
448
- this.el.info = panel.querySelector(`#pinfo-${this.id}`);
449
  this.el.controls = panel.querySelector(`#pcontrols-${this.id}`);
450
  this.el.suite = panel.querySelector(`#psuite-${this.id}`);
451
  this.el.group = panel.querySelector(`#pgroup-${this.id}`);
@@ -455,6 +505,9 @@
455
  this.el.chartType = panel.querySelector(`#pchart-type-${this.id}`);
456
  this.el.models = panel.querySelector(`#pmodels-${this.id}`);
457
  this.el.chart = panel.querySelector(`#pchart-${this.id}`);
 
 
 
458
 
459
  // Events
460
  panel.querySelector(`#ptoggle-${this.id}`).addEventListener('click', () => this.toggleControls());
@@ -474,6 +527,9 @@
474
  panel.querySelector(`#pmodels-ckpt-${this.id}`).addEventListener('click', () => this.setModelsByType(true));
475
  panel.querySelector(`#pmodels-base-${this.id}`).addEventListener('click', () => this.setModelsByType(false));
476
 
 
 
 
477
  this.buildModelCheckboxes();
478
  }
479
 
@@ -632,7 +688,6 @@
632
 
633
  if (!task || !metric || models.length === 0) {
634
  this.el.chart.innerHTML = '';
635
- this.updateTitle(task, metric);
636
  return;
637
  }
638
 
@@ -649,7 +704,6 @@
649
 
650
  if (rows.length === 0) {
651
  this.el.chart.innerHTML = '<div class="loading">No data for this selection</div>';
652
- this.updateTitle(task, metric);
653
  return;
654
  }
655
 
@@ -657,13 +711,27 @@
657
  const chartType = this.resolveChartType(rows);
658
  const higherIsBetter = rows[0]?.higher_is_better;
659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
  if (chartType === 'bar') {
661
- this.drawBarChart(rows, task, metric, higherIsBetter);
662
  } else {
663
- this.drawLineChart(rows, task, metric, higherIsBetter);
664
  }
665
-
666
- this.updateTitle(task, metric, higherIsBetter);
667
  }
668
 
669
  resolveChartType(rows) {
@@ -685,11 +753,112 @@
685
  return `${task} \u2014 ${metric}${arrow}`;
686
  }
687
 
688
- updateTitle(task, metric, higherIsBetter) {
689
- const w = this.getSmoothing();
690
- const smooth = w > 1 ? ` (smooth=${w})` : '';
691
- const arrow = higherIsBetter === true ? ' \u2191' : higherIsBetter === false ? ' \u2193' : '';
692
- this.el.title.textContent = `${task || '...'} \u2014 ${metric || '...'}${arrow}${smooth}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
  }
694
 
695
  cleanupTooltip() {
@@ -706,9 +875,24 @@
706
  chart.removeEventListener('mouseleave', this._tooltipMouseLeave);
707
  this._tooltipMouseLeave = null;
708
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
  }
710
 
711
- drawLineChart(rows, task, metric, higherIsBetter) {
712
  this.cleanupTooltip();
713
  const w = this.getSmoothing();
714
 
@@ -774,11 +958,13 @@
774
  margin: { t: 80, r: 20, b: 70, l: 50 },
775
  plot_bgcolor: '#fff', paper_bgcolor: '#fff',
776
  font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
777
- height: 500,
778
  }, { responsive: true });
 
 
779
  }
780
 
781
- drawBarChart(rows, task, metric, higherIsBetter) {
782
  this.cleanupTooltip();
783
  // For bar chart, use latest checkpoint per model
784
  const byModel = {};
@@ -840,7 +1026,7 @@
840
  margin: { t: 60, r: 80, b: 60, l: 10 },
841
  plot_bgcolor: '#fff', paper_bgcolor: '#fff',
842
  font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
843
- height: Math.max(300, names.length * 40 + 100),
844
  showlegend: false,
845
  }, { responsive: true });
846
 
@@ -848,24 +1034,30 @@
848
  const tooltip = document.getElementById('custom-tooltip');
849
  const chart = this.el.chart;
850
  chart.on('plotly_hover', (data) => {
 
851
  const pt = data.points[0];
852
  tooltip.innerHTML = pt.customdata;
853
  tooltip.style.display = 'block';
854
  });
855
  chart.on('plotly_unhover', () => {
 
856
  tooltip.style.display = 'none';
857
  });
858
  this._tooltipMouseMove = (e) => {
 
859
  if (tooltip.style.display === 'block') {
860
  tooltip.style.left = (e.clientX + 12) + 'px';
861
  tooltip.style.top = (e.clientY - 10) + 'px';
862
  }
863
  };
864
  this._tooltipMouseLeave = () => {
 
865
  tooltip.style.display = 'none';
866
  };
867
  chart.addEventListener('mousemove', this._tooltipMouseMove);
868
  chart.addEventListener('mouseleave', this._tooltipMouseLeave);
 
 
869
  }
870
 
871
  export(format) {
@@ -906,12 +1098,13 @@
906
  elInitLoading.style.display = 'none';
907
  elAddPanelRow.style.display = '';
908
 
909
- // Create default panel: deu_base_easy, aggregate, bits_per_byte, bar chart
910
- await addPanel({
911
- suite: 'deu_base_easy',
912
- metric: 'bits_per_byte',
913
- chartType: 'bar',
914
- });
 
915
  } catch (err) {
916
  elInitLoading.innerHTML = `<span style="color:#e63946">
917
  Error: ${err.message}<br>
 
50
  .btn-danger { color: #e63946; border-color: #e6394640; }
51
  .btn-danger:hover { background: #e6394610; }
52
 
53
+ /* ── Panels grid ────────────────────────────── */
54
+ #panels-container {
55
+ display: grid;
56
+ grid-template-columns: repeat(2, 1fr);
57
+ gap: 20px;
58
+ }
59
+
60
  /* ── Panel ───────────────────────────────────── */
61
  .panel {
62
  background: #fff;
63
  border: 1px solid #dee2e6;
64
  border-radius: 8px;
 
65
  overflow: hidden;
66
  }
67
+ .panel-toolbar {
68
  display: flex;
69
  align-items: center;
70
+ justify-content: flex-end;
71
+ gap: 6px;
72
+ padding: 6px 10px;
73
  border-bottom: 1px solid #dee2e6;
74
  background: #f8f9fa;
75
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  .panel-controls {
77
  padding: 16px;
78
  border-bottom: 1px solid #dee2e6;
 
155
  }
156
 
157
  /* ── Chart ───────────────────────────────────── */
158
+ .panel-chart-wrapper {
159
+ position: relative;
160
+ }
161
  .panel-chart {
162
  min-height: 100px;
163
+ overflow: hidden;
164
+ }
165
+ .title-hover-zone {
166
+ position: absolute;
167
+ top: 0;
168
+ left: 50px;
169
+ right: 50px;
170
+ height: 40px;
171
+ cursor: pointer;
172
+ z-index: 10;
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ }
177
+ .title-info-icon {
178
+ position: absolute;
179
+ top: 50%;
180
+ transform: translateY(-50%);
181
+ width: 18px;
182
+ height: 18px;
183
+ border-radius: 50%;
184
+ background: #e9ecef;
185
+ color: #495057;
186
+ font-size: 11px;
187
+ font-weight: 600;
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ opacity: 0.6;
192
+ transition: opacity 0.15s;
193
+ }
194
+ .title-hover-zone:hover .title-info-icon {
195
+ opacity: 1;
196
+ }
197
+
198
+ /* ── Resize handle ──────────────────────────── */
199
+ .panel-resize-handle {
200
+ height: 6px;
201
+ cursor: ns-resize;
202
+ background: linear-gradient(to bottom, #dee2e6 1px, transparent 1px, transparent 3px, #dee2e6 3px);
203
+ background-size: 100% 4px;
204
+ background-position: center;
205
+ transition: background-color 0.15s;
206
+ }
207
+ .panel-resize-handle:hover,
208
+ .panel-resize-handle.active {
209
+ background-color: #e9ecef;
210
  }
211
  .loading {
212
  display: flex;
 
221
  .custom-tooltip {
222
  position: fixed;
223
  pointer-events: none;
224
+ background: rgba(0, 0, 0, 0.85);
225
  color: #fff;
226
+ padding: 8px 12px 12px;
227
  border-radius: 4px;
228
+ font-size: 11px;
229
+ line-height: 1.5;
230
  z-index: 9999;
231
  display: none;
232
  white-space: nowrap;
233
  }
234
+ .custom-tooltip.scrollable {
235
+ pointer-events: auto;
236
+ overflow-y: auto;
237
+ white-space: normal;
238
+ min-width: 200px;
239
+ max-width: 400px;
240
+ }
241
 
242
  /* ── Add panel button ────────────────────────── */
243
  .add-panel-row {
 
431
  panel.id = `panel-${this.id}`;
432
 
433
  panel.innerHTML = `
434
+ <div class="panel-toolbar">
 
 
435
  <button class="btn btn-sm" id="ptoggle-${this.id}">Collapse</button>
436
  <button class="btn btn-sm" id="pexport-png-${this.id}">PNG</button>
437
  <button class="btn btn-sm" id="pexport-svg-${this.id}">SVG</button>
 
485
  <div class="checkbox-grid" id="pmodels-${this.id}"></div>
486
  </div>
487
  </div>
488
+ <div class="panel-chart-wrapper">
489
+ <div class="title-hover-zone" id="ptitle-hover-${this.id}" style="display:none"></div>
490
+ <div class="panel-chart" id="pchart-${this.id}"></div>
491
+ </div>
492
+ <div class="panel-resize-handle" id="presize-${this.id}"></div>
493
  `;
494
 
495
  container.appendChild(panel);
496
 
497
  // Cache refs
498
  this.el.panel = panel;
 
 
499
  this.el.controls = panel.querySelector(`#pcontrols-${this.id}`);
500
  this.el.suite = panel.querySelector(`#psuite-${this.id}`);
501
  this.el.group = panel.querySelector(`#pgroup-${this.id}`);
 
505
  this.el.chartType = panel.querySelector(`#pchart-type-${this.id}`);
506
  this.el.models = panel.querySelector(`#pmodels-${this.id}`);
507
  this.el.chart = panel.querySelector(`#pchart-${this.id}`);
508
+ this.el.titleHover = panel.querySelector(`#ptitle-hover-${this.id}`);
509
+ this.el.resize = panel.querySelector(`#presize-${this.id}`);
510
+ this.chartHeight = null; // null = use default
511
 
512
  // Events
513
  panel.querySelector(`#ptoggle-${this.id}`).addEventListener('click', () => this.toggleControls());
 
527
  panel.querySelector(`#pmodels-ckpt-${this.id}`).addEventListener('click', () => this.setModelsByType(true));
528
  panel.querySelector(`#pmodels-base-${this.id}`).addEventListener('click', () => this.setModelsByType(false));
529
 
530
+ // Resize handle drag
531
+ this.el.resize.addEventListener('mousedown', (e) => this.startResize(e));
532
+
533
  this.buildModelCheckboxes();
534
  }
535
 
 
688
 
689
  if (!task || !metric || models.length === 0) {
690
  this.el.chart.innerHTML = '';
 
691
  return;
692
  }
693
 
 
704
 
705
  if (rows.length === 0) {
706
  this.el.chart.innerHTML = '<div class="loading">No data for this selection</div>';
 
707
  return;
708
  }
709
 
 
711
  const chartType = this.resolveChartType(rows);
712
  const higherIsBetter = rows[0]?.higher_is_better;
713
 
714
+ // Fetch subtask tree JSON from the data
715
+ let subtaskTree = null;
716
+ try {
717
+ const stRows = await query(`
718
+ SELECT subtask_tree FROM scores
719
+ WHERE task = '${esc(task)}' AND metric = '${esc(metric)}'
720
+ AND subtask_tree IS NOT NULL
721
+ LIMIT 1
722
+ `);
723
+ if (stRows.length > 0 && stRows[0].subtask_tree) {
724
+ subtaskTree = JSON.parse(stRows[0].subtask_tree);
725
+ }
726
+ } catch (e) {
727
+ // ignore
728
+ }
729
+
730
  if (chartType === 'bar') {
731
+ this.drawBarChart(rows, task, metric, higherIsBetter, subtaskTree);
732
  } else {
733
+ this.drawLineChart(rows, task, metric, higherIsBetter, subtaskTree);
734
  }
 
 
735
  }
736
 
737
  resolveChartType(rows) {
 
753
  return `${task} \u2014 ${metric}${arrow}`;
754
  }
755
 
756
+ renderSubtaskTree(map, keys, depth = 0) {
757
+ if (!keys || keys.length === 0) return '';
758
+ const indent = depth * 16;
759
+ return keys.map(key => {
760
+ const children = map[key];
761
+ let html = `<div style="padding-left:${indent}px">${key}</div>`;
762
+ if (children) {
763
+ html += this.renderSubtaskTree(map, children, depth + 1);
764
+ }
765
+ return html;
766
+ }).join('');
767
+ }
768
+
769
+ setupTitleTooltip(subtaskTree) {
770
+ const hoverZone = this.el.titleHover;
771
+ hoverZone.innerHTML = '';
772
+ if (!subtaskTree || typeof subtaskTree !== 'object' || Object.keys(subtaskTree).length === 0) {
773
+ hoverZone.style.display = 'none';
774
+ return;
775
+ }
776
+ hoverZone.style.display = '';
777
+
778
+ // Position icon right before the title text
779
+ const icon = document.createElement('span');
780
+ icon.className = 'title-info-icon';
781
+ icon.textContent = 'i';
782
+ hoverZone.appendChild(icon);
783
+ const titleEl = this.el.chart.querySelector('.gtitle');
784
+ if (titleEl) {
785
+ const wrapperRect = this.el.chart.closest('.panel-chart-wrapper').getBoundingClientRect();
786
+ const titleRect = titleEl.getBoundingClientRect();
787
+ icon.style.left = (titleRect.right - wrapperRect.left - 50 + 6) + 'px'; // 50 = hover zone left offset, 6 = gap
788
+ } else {
789
+ icon.style.right = '0px';
790
+ }
791
+ const tooltip = document.getElementById('custom-tooltip');
792
+ // Find true roots: keys that never appear as a child value
793
+ const allChildren = new Set(Object.values(subtaskTree).flat());
794
+ const rootKeys = Object.keys(subtaskTree).filter(k => !allChildren.has(k));
795
+ const html = this.renderSubtaskTree(subtaskTree, rootKeys);
796
+
797
+ this._titleClick = (e) => {
798
+ // Toggle: if already visible for this panel, hide it
799
+ if (tooltip.style.display === 'block' && tooltip._panelId === this.id) {
800
+ tooltip.style.display = 'none';
801
+ tooltip.classList.remove('scrollable');
802
+ tooltip._panelId = null;
803
+ return;
804
+ }
805
+ tooltip.innerHTML = html;
806
+ tooltip.classList.add('scrollable');
807
+ tooltip.style.display = 'block';
808
+ tooltip._panelId = this.id;
809
+ // Position: top-left of tooltip below bottom-left of title text
810
+ const titleEl = this.el.chart.querySelector('.gtitle');
811
+ const chartRect = this.el.chart.getBoundingClientRect();
812
+ const tw = tooltip.offsetWidth;
813
+ if (titleEl) {
814
+ const titleRect = titleEl.getBoundingClientRect();
815
+ const titleCenter = (titleRect.left + titleRect.right) / 2;
816
+ tooltip.style.left = (titleCenter - tw / 2) + 'px';
817
+ tooltip.style.top = (titleRect.bottom + 4) + 'px';
818
+ } else {
819
+ tooltip.style.left = (chartRect.left + chartRect.width / 2 - tw / 2) + 'px';
820
+ tooltip.style.top = (chartRect.top + 40) + 'px';
821
+ }
822
+ tooltip.style.maxHeight = chartRect.height + 'px';
823
+ };
824
+
825
+ this._titleOutsideClick = (e) => {
826
+ if (tooltip._panelId !== this.id) return;
827
+ if (tooltip.contains(e.target) || hoverZone.contains(e.target)) return;
828
+ tooltip.style.display = 'none';
829
+ tooltip.classList.remove('scrollable');
830
+ tooltip._panelId = null;
831
+ };
832
+
833
+ hoverZone.addEventListener('click', this._titleClick);
834
+ document.addEventListener('mousedown', this._titleOutsideClick);
835
+ }
836
+
837
+ startResize(e) {
838
+ e.preventDefault();
839
+ const startY = e.clientY;
840
+ const startH = this.el.chart.offsetHeight;
841
+ this.el.resize.classList.add('active');
842
+
843
+ const onMove = (ev) => {
844
+ const delta = ev.clientY - startY;
845
+ const newH = Math.max(200, startH + delta);
846
+ this.chartHeight = newH;
847
+ Plotly.relayout(this.el.chart, { height: newH });
848
+ };
849
+
850
+ const onUp = () => {
851
+ this.el.resize.classList.remove('active');
852
+ document.removeEventListener('mousemove', onMove);
853
+ document.removeEventListener('mouseup', onUp);
854
+ };
855
+
856
+ document.addEventListener('mousemove', onMove);
857
+ document.addEventListener('mouseup', onUp);
858
+ }
859
+
860
+ getChartHeight(fallback) {
861
+ return this.chartHeight || fallback;
862
  }
863
 
864
  cleanupTooltip() {
 
875
  chart.removeEventListener('mouseleave', this._tooltipMouseLeave);
876
  this._tooltipMouseLeave = null;
877
  }
878
+ // Clean up title click popup
879
+ if (this._titleClick) {
880
+ const hz = this.el.titleHover;
881
+ hz.removeEventListener('click', this._titleClick);
882
+ hz.style.display = 'none';
883
+ this._titleClick = null;
884
+ }
885
+ if (this._titleOutsideClick) {
886
+ document.removeEventListener('mousedown', this._titleOutsideClick);
887
+ this._titleOutsideClick = null;
888
+ }
889
+ if (tooltip._panelId === this.id) {
890
+ tooltip.classList.remove('scrollable');
891
+ tooltip._panelId = null;
892
+ }
893
  }
894
 
895
+ drawLineChart(rows, task, metric, higherIsBetter, subtasks) {
896
  this.cleanupTooltip();
897
  const w = this.getSmoothing();
898
 
 
958
  margin: { t: 80, r: 20, b: 70, l: 50 },
959
  plot_bgcolor: '#fff', paper_bgcolor: '#fff',
960
  font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
961
+ height: this.getChartHeight(600),
962
  }, { responsive: true });
963
+
964
+ this.setupTitleTooltip(subtasks);
965
  }
966
 
967
+ drawBarChart(rows, task, metric, higherIsBetter, subtasks) {
968
  this.cleanupTooltip();
969
  // For bar chart, use latest checkpoint per model
970
  const byModel = {};
 
1026
  margin: { t: 60, r: 80, b: 60, l: 10 },
1027
  plot_bgcolor: '#fff', paper_bgcolor: '#fff',
1028
  font: { family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' },
1029
+ height: this.getChartHeight(Math.max(400, names.length * 40 + 100)),
1030
  showlegend: false,
1031
  }, { responsive: true });
1032
 
 
1034
  const tooltip = document.getElementById('custom-tooltip');
1035
  const chart = this.el.chart;
1036
  chart.on('plotly_hover', (data) => {
1037
+ if (tooltip.classList.contains('scrollable')) return;
1038
  const pt = data.points[0];
1039
  tooltip.innerHTML = pt.customdata;
1040
  tooltip.style.display = 'block';
1041
  });
1042
  chart.on('plotly_unhover', () => {
1043
+ if (tooltip.classList.contains('scrollable')) return;
1044
  tooltip.style.display = 'none';
1045
  });
1046
  this._tooltipMouseMove = (e) => {
1047
+ if (tooltip.classList.contains('scrollable')) return;
1048
  if (tooltip.style.display === 'block') {
1049
  tooltip.style.left = (e.clientX + 12) + 'px';
1050
  tooltip.style.top = (e.clientY - 10) + 'px';
1051
  }
1052
  };
1053
  this._tooltipMouseLeave = () => {
1054
+ if (tooltip.classList.contains('scrollable')) return;
1055
  tooltip.style.display = 'none';
1056
  };
1057
  chart.addEventListener('mousemove', this._tooltipMouseMove);
1058
  chart.addEventListener('mouseleave', this._tooltipMouseLeave);
1059
+
1060
+ this.setupTitleTooltip(subtasks);
1061
  }
1062
 
1063
  export(format) {
 
1098
  elInitLoading.style.display = 'none';
1099
  elAddPanelRow.style.display = '';
1100
 
1101
+ // Create 2x2 default panels
1102
+ await Promise.all([
1103
+ addPanel({ suite: 'eng_base_easy', group: 'eng_base_easy_bpb', metric: 'bits_per_byte', chartType: 'bar' }),
1104
+ addPanel({ suite: 'deu_base_easy', group: 'deu_base_easy_bpb', metric: 'bits_per_byte', chartType: 'bar' }),
1105
+ addPanel({ suite: 'eng_base_easy', group: 'eng_base_easy_rc', metric: 'acc_norm', chartType: 'bar' }),
1106
+ addPanel({ suite: 'deu_base_easy', group: 'deu_base_easy_rc', metric: 'acc_norm', chartType: 'bar' }),
1107
+ ]);
1108
  } catch (err) {
1109
  elInitLoading.innerHTML = `<span style="color:#e63946">
1110
  Error: ${err.message}<br>