static/js/calculate.js
/**
 * Calculate silhouette scores based on current binning plan.
 * @function calcSilhouette
 * @param {Object} mo - main object
 */
Calculate silhouette scores based on current binning plan.
@function calcSilhouette
@param {Object} mo - main object
Calculate silhouette scores based on current binning plan . @function calcSilhouette @param { Object } mo - main object
function calcSilhouette(mo) {
  byId('silh-calc-btn').classList.add('hidden');
  byId('silh-title').classList.add('hidden');
  byId('silh-progress').classList.remove('hidden');
  const data = mo.data,
        view = mo.view,
        binned = mo.binned,
        masked = mo.masked;
  const items = [], scale_data = [];
  let chk, idx, scale;
  for (let item of ['x', 'y', 'size', 'opacity', 'color']) {
    chk = byId(`${item}-calc-chk`);
    if (!chk.checked || chk.disabled) continue;
    idx = view[item].i;
    scale = view[item].scale;
    scale_data.push(scaleArr(data[idx], scale));
    items.push(item);
  }
  const num_item = items.length;
  console.log('Filtering data...');
  const n = mo.cache.nctg;
  let n_binned = 0,
      n_masked = 0,
      n_inval = 0;
  const filt_ctgs = [],
        filt_plan = [],
        filt_data = Array(num_item).fill().map(() => Array());
  let valid = true;
  let j;
  for (let i = 0; i < n; i++) {
    if (binned[i]) {
      n_binned++;
      if (masked[i]) {
        n_masked++;
      } else {
        valid = true;
        for (j = 0; j < num_item; j++) {
          if (!isFinite(scale_data[j][i])) {
            valid = false;
            break;
          }
        }
        if (valid) {
          filt_ctgs.push(i);
          filt_plan.push(binned[i]);
          for (let j in scale_data) {
            filt_data[j].push(scale_data[j][i]);
          }
        } else {
          n_inval++;
        }
      }
    }
  }
  const n_ctg = filt_ctgs.length;
  const [labels, bins] = factorize(filt_plan);
  const n_bin = bins.length;
  console.log(`The data set has ${n} contigs.`);
  console.log(`In which ${n_binned} contigs are currently binned.`);
  console.log(`Excluded ${n_masked} that are currently masked.`);
  console.log(`Excluded ${n_inval} contigs that have invalid values.`);
  console.log(`A total of ${n_ctg} contigs in ${n_bin} bins are used for ` +
    'this calculation.');
  setTimeout(function () {
    console.log('Performing min-max scaling...');
    for (let j = 0; j < num_item; j++) {
      arrMinMaxScale(filt_data[j]);
    }
    const vals = transpose(filt_data);
    console.log('Calculating pairwise Euclidean distances...');
    const use2d = n_ctg >= 20000;
    if (use2d) console.log('Switched to 2D calculation (slower but can ' +
      'handle more data points.');
    const dm = use2d ? pdist2d(vals) : pdist(vals);
    console.log('Calculating silhouette coefficients...');
    let scores = use2d ? silhouetteSample2D(vals, labels, dm) :
      silhouetteSample(vals, labels, dm);
    console.log('Calculation completed.');
    mo.cache.silhs = [filt_ctgs, labels, bins, scores];
    fillSilhTable(mo, byId('silh-tbody'));
    byId('silh-table-wrap').classList.remove('hidden');
    byId('silh-title').classList.remove('hidden');
    byId('silh-progress').classList.add('hidden');
    byId('silh-done-div').classList.remove('hidden');
    byId('silh-done-btn').classList.remove('hidden');
  }, 100); 
}
function calcSilhouette ( mo ) { byId ( 'silh-calc-btn' ) . classList . add ( 'hidden' ) ; byId ( 'silh-title' ) . classList . add ( 'hidden' ) ; byId ( 'silh-progress' ) . classList . remove ( 'hidden' ) ; const data = mo . data , view = mo . view , binned = mo . binned , masked = mo . masked ; const items = [ ] , scale_data = [ ] ; let chk , idx , scale ; for ( let item of [ 'x' , 'y' , 'size' , 'opacity' , 'color' ] ) { chk = byId ( ` ${ item } ` ) ; if ( ! chk . checked || chk . disabled ) continue ; idx = view [ item ] . i ; scale = view [ item ] . scale ; scale_data . push ( scaleArr ( data [ idx ] , scale ) ) ; items . push ( item ) ; } const num_item = items . length ; console . log ( 'Filtering data...' ) ; const n = mo . cache . nctg ; let n_binned = 0 , n_masked = 0 , n_inval = 0 ; const filt_ctgs = [ ] , filt_plan = [ ] , filt_data = Array ( num_item ) . fill ( ) . map ( ( ) => Array ( ) ) ; let valid = true ; let j ; for ( let i = 0 ; i < n ; i ++ ) { if ( binned [ i ] ) { n_binned ++ ; if ( masked [ i ] ) { n_masked ++ ; } else { valid = true ; for ( j = 0 ; j < num_item ; j ++ ) { if ( ! isFinite ( scale_data [ j ] [ i ] ) ) { valid = false ; break ; } } if ( valid ) { filt_ctgs . push ( i ) ; filt_plan . push ( binned [ i ] ) ; for ( let j in scale_data ) { filt_data [ j ] . push ( scale_data [ j ] [ i ] ) ; } } else { n_inval ++ ; } } } } const n_ctg = filt_ctgs . length ; const [ labels , bins ] = factorize ( filt_plan ) ; const n_bin = bins . length ; console . log ( ` ${ n } ` ) ; console . log ( ` ${ n_binned } ` ) ; console . log ( ` ${ n_masked } ` ) ; console . log ( ` ${ n_inval } ` ) ; console . log ( ` ${ n_ctg } ${ n_bin } ` + 'this calculation.' ) ; setTimeout ( function ( ) { console . log ( 'Performing min-max scaling...' ) ; for ( let j = 0 ; j < num_item ; j ++ ) { arrMinMaxScale ( filt_data [ j ] ) ; } const vals = transpose ( filt_data ) ; console . log ( 'Calculating pairwise Euclidean distances...' ) ; const use2d = n_ctg >= 20000 ; if ( use2d ) console . log ( 'Switched to 2D calculation (slower but can ' + 'handle more data points.' ) ; const dm = use2d ? pdist2d ( vals ) : pdist ( vals ) ; console . log ( 'Calculating silhouette coefficients...' ) ; let scores = use2d ? silhouetteSample2D ( vals , labels , dm ) : silhouetteSample ( vals , labels , dm ) ; console . log ( 'Calculation completed.' ) ; mo . cache . silhs = [ filt_ctgs , labels , bins , scores ] ; fillSilhTable ( mo , byId ( 'silh-tbody' ) ) ; byId ( 'silh-table-wrap' ) . classList . remove ( 'hidden' ) ; byId ( 'silh-title' ) . classList . remove ( 'hidden' ) ; byId ( 'silh-progress' ) . classList . add ( 'hidden' ) ; byId ( 'silh-done-div' ) . classList . remove ( 'hidden' ) ; byId ( 'silh-done-btn' ) . classList . remove ( 'hidden' ) ; } , 100 ) ; }
Calculate silhouette scores based on current binning plan.
Calculate silhouette scores based on current binning plan .
// const data = mo.data, // collect and scale data // filter data // convert binning plan into numbers // log sample selection // This is a heavy calculation so a progress bar is displayed prior to // starting the calculation. This can only be achieved through an async // operation. There is no good sync way to force the browser to "flush". // See: https://stackoverflow.com/questions/16876394/ // min-max scaling of each variable // transpose data matrix // calculate pairwise distance if not already // if (cache.pdist.length === 0) cache.pdist = pdist(vals); // note: can no longer use cache pdist // switch to 2D version if there are too many contigs // const t0 = performance.now(); // const t1 = performance.now(); // console.log(t1 - t0); // calculate silhouette scores // cache result // this 0.1 sec delay is to wait for loading dots to start blinking