@@ -29,6 +29,32 @@ const AVERAGE_METRIC_PLOTS = [
2929 yMax : 0.868
3030 }
3131] ;
32+ const AVERAGE_METRIC_DATE_PLOTS = [
33+ {
34+ plotId : 'plot-date-avg-r50' ,
35+ metricKey : 'recall_50' ,
36+ yTitle : 'R@50 (Avg. 5)' ,
37+ hoverMetric : 'Recall@50' ,
38+ yMin : 0.15 ,
39+ yMax : 0.755
40+ } ,
41+ {
42+ plotId : 'plot-date-avg-alpha10' ,
43+ metricKey : 'alpha_ndcg_10' ,
44+ yTitle : 'α@10 (Avg. 5)' ,
45+ hoverMetric : 'α@10' ,
46+ yMin : 0.1 ,
47+ yMax : 0.541
48+ } ,
49+ {
50+ plotId : 'plot-date-avg-c20' ,
51+ metricKey : 'coverage_20' ,
52+ yTitle : 'C@20 (Avg. 5)' ,
53+ hoverMetric : 'C@20' ,
54+ yMin : 0.25 ,
55+ yMax : 0.868
56+ }
57+ ] ;
3258
3359const RECALL_TYPE_ORDER = [ 'upper_baseline' , 'open_source' , 'proprietary' ] ;
3460const RECALL_TYPE_LABELS = {
@@ -152,6 +178,12 @@ function parseSizeToBillions(sizeStr) {
152178 return null ;
153179}
154180
181+ function parseReleaseDate ( dateStr ) {
182+ if ( ! dateStr ) return null ;
183+ const d = new Date ( dateStr ) ;
184+ return Number . isNaN ( d . getTime ( ) ) ? null : d ;
185+ }
186+
155187function renderRecallPlots ( dataToRender ) {
156188 if ( typeof Plotly === 'undefined' ) return ;
157189
@@ -336,6 +368,195 @@ function resizeRecallPlots() {
336368 } ) ;
337369}
338370
371+ function renderReleaseDatePlots ( dataToRender ) {
372+ if ( typeof Plotly === 'undefined' ) return ;
373+
374+ const emptyMsg = document . getElementById ( 'date-plots-empty' ) ;
375+ const hasAnyDates = dataToRender . some ( row => parseReleaseDate ( row . info ?. date ) !== null ) ;
376+
377+ if ( emptyMsg ) {
378+ if ( ! hasAnyDates ) {
379+ emptyMsg . textContent =
380+ 'No models in the current filter have a valid release date; adjust filters or refer to the table.' ;
381+ emptyMsg . classList . remove ( 'is-hidden' ) ;
382+ } else {
383+ emptyMsg . textContent = '' ;
384+ emptyMsg . classList . add ( 'is-hidden' ) ;
385+ }
386+ }
387+
388+ const plotConfig = { responsive : true , displayModeBar : true , displaylogo : false } ;
389+ const familyColors = buildFamilyColorMap ( dataToRender ) ;
390+
391+ AVERAGE_METRIC_DATE_PLOTS . forEach ( ( { plotId, metricKey, yTitle, hoverMetric, yMin, yMax } ) => {
392+ const el = document . getElementById ( plotId ) ;
393+ if ( ! el ) return ;
394+
395+ const grouped = { } ;
396+ dataToRender . forEach ( row => {
397+ const typeKey = row . info ?. type ;
398+ const x = parseReleaseDate ( row . info ?. date ) ;
399+ const y = row . datasets ?. average ?. [ metricKey ] ;
400+ if ( x === null || y === undefined || y === null || Number . isNaN ( Number ( y ) ) ) return ;
401+
402+ const family = inferModelFamily ( row . info ?. name ) ;
403+ if ( ! grouped [ family ] ) {
404+ grouped [ family ] = { x : [ ] , y : [ ] , symbols : [ ] , hovertext : [ ] } ;
405+ }
406+ grouped [ family ] . x . push ( x ) ;
407+ grouped [ family ] . y . push ( Number ( y ) ) ;
408+ const modelName = row . info ?. name ?? '' ;
409+ const typeLabel = RECALL_TYPE_LABELS [ typeKey ] || typeKey || '' ;
410+ const dateLabel = row . info ?. date || '-' ;
411+ grouped [ family ] . hovertext . push (
412+ `<b>${ modelName } </b><br>Family: ${ family } <br>Type: ${ typeLabel } <br>Release date: ${ dateLabel } `
413+ ) ;
414+ grouped [ family ] . symbols . push ( TYPE_SYMBOLS [ typeKey ] || 'circle' ) ;
415+ } ) ;
416+
417+ const traces = Object . keys ( grouped )
418+ . sort ( ( a , b ) => a . localeCompare ( b ) )
419+ . map ( family => ( {
420+ type : 'scatter' ,
421+ mode : 'markers' ,
422+ name : family ,
423+ x : grouped [ family ] . x ,
424+ y : grouped [ family ] . y ,
425+ hovertext : grouped [ family ] . hovertext ,
426+ marker : {
427+ color : familyColors [ family ] || '#666' ,
428+ symbol : grouped [ family ] . symbols ,
429+ size : 12 ,
430+ opacity : 0.95 ,
431+ line : { width : 1 , color : '#fff' }
432+ } ,
433+ hovertemplate :
434+ '%{hovertext}<br>' +
435+ hoverMetric +
436+ ': %{y:.3f}<extra></extra>'
437+ } ) ) ;
438+
439+ const xValues = traces . flatMap ( t => t . x || [ ] ) ;
440+ const xMin = xValues . length ? new Date ( Math . min ( ...xValues . map ( d => d . getTime ( ) ) ) ) : null ;
441+ const xMax = xValues . length ? new Date ( Math . max ( ...xValues . map ( d => d . getTime ( ) ) ) ) : null ;
442+ const xMinMonthStart = xMin ? new Date ( xMin . getFullYear ( ) , xMin . getMonth ( ) , 1 ) : null ;
443+ const baselineData = fullLeaderboardData || dataToRender ;
444+ const bm25Score = getModelAverageMetric (
445+ baselineData ,
446+ name => name === 'bm25' ,
447+ metricKey
448+ ) ;
449+ const fusionScore = getModelAverageMetric (
450+ baselineData ,
451+ name => name === 'fusion (bm25, bge, e5, voyage)' ,
452+ metricKey
453+ ) ;
454+
455+ if ( xMin !== null && xMax !== null ) {
456+ if ( bm25Score !== null ) {
457+ traces . push ( {
458+ type : 'scatter' ,
459+ mode : 'lines' ,
460+ name : 'BM25' ,
461+ x : [ xMin , xMax ] ,
462+ y : [ bm25Score , bm25Score ] ,
463+ line : { color : 'rgba(97,97,97,0.55)' , width : 1.1 , dash : 'dash' } ,
464+ hovertemplate : `BM25<br>${ hoverMetric } : ${ bm25Score . toFixed ( 3 ) } <extra></extra>`
465+ } ) ;
466+ }
467+ if ( fusionScore !== null ) {
468+ traces . push ( {
469+ type : 'scatter' ,
470+ mode : 'lines' ,
471+ name : 'Fusion' ,
472+ x : [ xMin , xMax ] ,
473+ y : [ fusionScore , fusionScore ] ,
474+ line : { color : 'rgba(106,27,154,0.55)' , width : 1.1 , dash : 'dot' } ,
475+ hovertemplate : `Fusion<br>${ hoverMetric } : ${ fusionScore . toFixed ( 3 ) } <extra></extra>`
476+ } ) ;
477+ }
478+ }
479+
480+ const totalPoints = traces . reduce ( ( acc , t ) => acc + ( t . x ?. length || 0 ) , 0 ) ;
481+
482+ if ( totalPoints === 0 ) {
483+ const emptyLayout = {
484+ annotations : [
485+ {
486+ text : hasAnyDates
487+ ? 'No data for this view.'
488+ : 'No models with valid release dates.' ,
489+ xref : 'paper' ,
490+ yref : 'paper' ,
491+ x : 0.5 ,
492+ y : 0.5 ,
493+ showarrow : false ,
494+ font : { size : 14 , color : '#666' }
495+ }
496+ ] ,
497+ xaxis : { visible : false } ,
498+ yaxis : { visible : false } ,
499+ margin : { t : 20 , r : 20 , b : 20 , l : 20 }
500+ } ;
501+ if ( el . data && el . layout ) {
502+ Plotly . react ( el , [ ] , emptyLayout , plotConfig ) ;
503+ } else {
504+ Plotly . newPlot ( el , [ ] , emptyLayout , plotConfig ) ;
505+ }
506+ return ;
507+ }
508+
509+ const layout = {
510+ margin : { t : 28 , r : 12 , b : 88 , l : 56 } ,
511+ xaxis : {
512+ title : { text : 'Model Release Date' , standoff : 18 } ,
513+ type : 'date' ,
514+ tickmode : 'linear' ,
515+ tick0 : xMinMonthStart ? xMinMonthStart . toISOString ( ) . slice ( 0 , 10 ) : undefined ,
516+ dtick : 'M1' ,
517+ tickformat : '%b %Y' ,
518+ showgrid : true ,
519+ zeroline : false ,
520+ tickfont : { size : 11 }
521+ } ,
522+ yaxis : {
523+ title : { text : yTitle } ,
524+ range : [ yMin , yMax ] ,
525+ tickformat : '.2f' ,
526+ showgrid : true
527+ } ,
528+ legend : {
529+ orientation : 'h' ,
530+ yanchor : 'top' ,
531+ y : - 0.28 ,
532+ xanchor : 'center' ,
533+ x : 0.5
534+ } ,
535+ hovermode : 'closest' ,
536+ dragmode : 'zoom'
537+ } ;
538+
539+ if ( el . data && el . layout ) {
540+ Plotly . react ( el , traces , layout , plotConfig ) ;
541+ } else {
542+ Plotly . newPlot ( el , traces , layout , plotConfig ) ;
543+ }
544+ } ) ;
545+ }
546+
547+ function resizeReleaseDatePlots ( ) {
548+ if ( typeof Plotly === 'undefined' ) return ;
549+ AVERAGE_METRIC_DATE_PLOTS . forEach ( ( { plotId } ) => {
550+ const el = document . getElementById ( plotId ) ;
551+ if ( ! el ) return ;
552+ try {
553+ Plotly . Plots . resize ( el ) ;
554+ } catch ( _ ) {
555+ /* no plot yet */
556+ }
557+ } ) ;
558+ }
559+
339560$ ( document ) . ready ( function ( ) {
340561 var options = {
341562 slidesToScroll : 1 ,
@@ -355,6 +576,7 @@ document.addEventListener('DOMContentLoaded', function () {
355576 window . addEventListener ( 'resize' , function ( ) {
356577 adjustNameColumnWidth ( ) ;
357578 resizeRecallPlots ( ) ;
579+ resizeReleaseDatePlots ( ) ;
358580 } ) ;
359581} ) ;
360582
@@ -444,6 +666,7 @@ function renderTableData(dataToRender) {
444666 setTimeout ( adjustNameColumnWidth , 0 ) ;
445667 initializeSorting ( ) ;
446668 renderRecallPlots ( dataToRender ) ;
669+ renderReleaseDatePlots ( dataToRender ) ;
447670}
448671
449672function setupEventListeners ( ) {
0 commit comments