@@ -15,6 +15,21 @@ import '../stylesheets/panels/metadataPlot.styl';
1515
1616const sessionId = uuidv4 ( ) ;
1717
18+ function mean ( arr ) {
19+ if ( ! arr . length ) {
20+ return 0 ;
21+ }
22+ return arr . reduce ( ( a , b ) => a + b ) / arr . length ;
23+ }
24+
25+ function stddev ( arr ) {
26+ if ( arr . length <= 1 ) {
27+ return 0 ;
28+ }
29+ const m = mean ( arr ) ;
30+ return Math . sqrt ( arr . map ( ( x ) => Math . pow ( x - m , 2 ) ) . reduce ( ( a , b ) => a + b ) / arr . length ) ;
31+ }
32+
1833var MetadataPlot = Panel . extend ( {
1934 events : _ . extend ( Panel . prototype . events , {
2035 'click .g-widget-metadata-plot-settings' : function ( event ) {
@@ -457,7 +472,7 @@ var MetadataPlot = Panel.extend({
457472 colorScale = window . d3 . scale . linear ( ) . domain ( viridis . map ( ( _ , i ) => i / ( viridis . length - 1 ) * ( ( plotData . series . c . max - plotData . series . c . min ) || 0 ) + plotData . series . c . min ) ) . range ( viridis ) ;
458473 }
459474 const plotlyData = {
460- x : plotData . data . map ( ( d ) => d [ plotData . series . x . index ] ) ,
475+ x : plotData . series . x ? plotData . data . map ( ( d ) => d [ plotData . series . x . index ] ) : 0 ,
461476 y : plotData . data . map ( ( d ) => d [ plotData . series . y . index ] ) ,
462477 hovertext : plotData . data . map ( ( d ) => this . _hoverText ( d , plotData ) ) ,
463478 hoverinfo : 'text' ,
@@ -518,6 +533,86 @@ var MetadataPlot = Panel.extend({
518533 } ] ;
519534 }
520535 }
536+ if ( plotData . format === 'distrib' ) {
537+ const maxs = plotData . series . s && plotData . series . s . distinct ? plotData . series . s . distinctcount : 1 ;
538+ const pv = {
539+ x : [ ] ,
540+ y : [ ] ,
541+ c : [ ] ,
542+ r : [ ] ,
543+ xe : [ ] ,
544+ ye : [ ] ,
545+ dd : Array ( maxs ) ,
546+ xd : Array . from ( Array ( maxs ) , ( ) => [ ] ) ,
547+ yd : Array . from ( Array ( maxs ) , ( ) => [ ] ) ,
548+ cd : Array . from ( Array ( maxs ) , ( ) => [ ] ) ,
549+ rd : Array . from ( Array ( maxs ) , ( ) => [ ] )
550+ } ;
551+ plotData . data . forEach ( ( d ) => {
552+ const s = plotData . series . s && plotData . series . s . distinct ? plotData . series . s . distinct . indexOf ( d [ plotData . series . s . index ] ) : 0 ;
553+ if ( pv . dd [ s ] === undefined ) {
554+ pv . dd [ s ] = d ;
555+ }
556+ if ( plotData . series . x ) {
557+ pv . xd [ s ] . push ( d [ plotData . series . x . index ] ) ;
558+ }
559+ pv . yd [ s ] . push ( d [ plotData . series . y . index ] ) ;
560+ if ( plotData . series . c ) {
561+ pv . cd [ s ] . push ( d [ plotData . series . c . index ] ) ;
562+ }
563+ if ( plotData . series . r ) {
564+ pv . rd [ s ] . push ( d [ plotData . series . r . index ] ) ;
565+ }
566+ } ) ;
567+ for ( let s = 0 ; s < maxs ; s += 1 ) {
568+ pv . x [ s ] = mean ( pv . xd [ s ] ) ;
569+ pv . xe [ s ] = stddev ( pv . xd [ s ] ) ;
570+ pv . y [ s ] = mean ( pv . yd [ s ] ) ;
571+ pv . ye [ s ] = stddev ( pv . yd [ s ] ) ;
572+ pv . r [ s ] = plotData . series . r && plotData . series . r !== 'number' && pv . rd [ s ] . length ? pv . rd [ s ] [ 0 ] : mean ( pv . rd [ s ] ) ;
573+ pv . c [ s ] = plotData . series . c && plotData . series . c !== 'number' && pv . cd [ s ] . length ? pv . cd [ s ] [ 0 ] : mean ( pv . cd [ s ] ) ;
574+ }
575+ plotlyData . x = [ ...Array ( maxs ) . keys ( ) ] ;
576+ if ( plotData . series . x ) {
577+ plotlyData . error_x = {
578+ type : 'data' ,
579+ array : pv . xe . map ( ( v ) => v / Math . max . apply ( Math , pv . xe ) ) ,
580+ color : '#0000C0' ,
581+ // width: 0,
582+ visible : true
583+ } ;
584+ }
585+ plotlyData . y = pv . y ;
586+ plotlyData . mode = 'lines+markers' ;
587+ plotlyData . error_y = {
588+ type : 'data' ,
589+ array : pv . ye ,
590+ color : '#C00000' ,
591+ // width: 0,
592+ visible : true
593+ } ;
594+ plotlyData . hovertext = pv . dd . map ( ( d ) => this . _hoverText ( d , plotData ) ) ;
595+ plotlyData . marker . symbol = 0 ;
596+ if ( plotData . series . r ) {
597+ plotlyData . marker . size = plotData . series . r && ( plotData . series . r . type === 'number' || plotData . series . r . distinctcount )
598+ ? (
599+ plotData . series . r . type === 'number'
600+ ? pv . r . map ( ( r ) => ( r - plotData . series . r . min ) / ( plotData . series . r . max - plotData . series . r . min ) * 10 + 5 )
601+ : pv . dd . map ( ( d ) => plotData . series . r . distinct . indexOf ( d [ plotData . series . r . index ] ) / plotData . series . r . distinctcount * 10 + 5 )
602+ )
603+ : 10 ;
604+ }
605+ if ( plotData . series . c ) {
606+ plotlyData . marker . color = plotData . series . c
607+ ? (
608+ ! plotData . series . c . distinctcount
609+ ? pv . c . map ( ( c ) => colorScale ( c ) )
610+ : pv . dd . map ( ( d ) => colorBrewerPaired12 [ plotData . series . c . distinct . indexOf ( d [ plotData . series . c . index ] ) ] || '#000000' )
611+ )
612+ : '#000000' ;
613+ }
614+ plotlyData . type = 'scatter' ;
615+ }
521616 return [ plotlyData ] ;
522617 } ,
523618
@@ -548,7 +643,7 @@ var MetadataPlot = Panel.extend({
548643 this . lastPlotData = plotData ;
549644 this . $el . html ( metadataPlotTemplate ( { } ) ) ;
550645 const elem = this . $el . find ( '.h-metadata-plot-area' ) ;
551- if ( ! plotData || ( plotData . format !== 'violin' && ! plotData . series . x ) || ! plotData . series . y || plotData . data . length < 2 ) {
646+ if ( ! plotData || ( plotData . format !== 'violin' && plotData . format !== 'distrib' && ! plotData . series . x ) || ! plotData . series . y || plotData . data . length < 2 ) {
552647 elem . html ( '' ) ;
553648 return ;
554649 }
@@ -560,7 +655,7 @@ var MetadataPlot = Panel.extend({
560655 if ( maximized ) {
561656 plotOptions . margin . l += 20 ;
562657 plotOptions . margin . b += 40 ;
563- plotOptions . xaxis = { title : { text : plotData . format !== 'violin' ? `${ plotData . series . x . title } ` : `${ plotData . series . s ? plotData . series . s . title : '' } ` } } ;
658+ plotOptions . xaxis = { title : { text : plotData . format !== 'violin' && plotData . format !== 'distrib' ? `${ plotData . series . x . title } ` : `${ plotData . series . s ? plotData . series . s . title : '' } ` } } ;
564659 plotOptions . yaxis = { title : { text : `${ plotData . series . y . title } ` } } ;
565660 }
566661 this . _plotlyNode = elem ;
0 commit comments