ucsc-xena-client
Version:
UCSC Xena Client. Functional genomics visualizations.
199 lines (174 loc) • 5.82 kB
JavaScript
;
var _ = require('../underscore_ext');
var _require = require('./utils'),
compose = _require.compose,
make = _require.make,
mount = _require.mount;
var tiesQuery = require('../tiesQuery');
//var Rx = require('../rx');
var _require2 = require('./common'),
fetchSurvival = _require2.fetchSurvival;
var collateDocs = function collateDocs(patients) {
return function (docs) {
var idx = new Map();
docs.forEach(function (_ref) {
var patientId = _ref.patientId,
docs = _ref.docs;
idx.set(patientId, _.getIn(docs, [0, 'id']));
});
return patients.map(function (p) {
return { patient: p, doc: idx.get(p) };
});
};
};
function fetchDocs(serverBus, patients) {
serverBus.next(['ties-doc-list', tiesQuery.docs(patients).map(collateDocs(patients))]);
}
function fetchDoc(serverBus, state, newState) {
var showDoc = newState.showDoc,
docs = newState.docs;
if (showDoc != null) {
serverBus.next(['ties-doc', tiesQuery.doc(docs[showDoc].doc)]);
}
};
// XXX Make this transient. We don't need to save this data.
function fetchConcepts(serverBus) {
serverBus.next(['ties-concepts', tiesQuery.goodConcepts()]);
};
// underscore intersect sucks. Using a set, for O(n + m) performance.
var intersect = function intersect(c0, c1) {
var s = new Set(c0);
return c1.filter(function (v) {
return s.has(v);
});
};
var union = function union(c0, c1) {
var s = new Set(c0);
c1.forEach(function (v) {
return s.add(v);
});
return Array.from(s.values());
};
var unionOfHits = function unionOfHits(h0, h1) {
return union(_.pluck(h0, 'patientId'), _.pluck(h1, 'patientId'));
};
function fetchMatches(serverBus, state, newState, term) {
var patients = _.getIn(newState, ['survival', 'patient', 'data', 'codes']);
serverBus.next(['ties-matches',
// Running these sequentially because the backend falls over if we send them in parallel.
// This is super slow.
tiesQuery.conceptMatches(patients, term).flatMap(function (conceptHits) {
return tiesQuery.textMatches(patients, term).map(function (textHits) {
return { conceptHits: conceptHits, textHits: textHits };
});
}).map(function (_ref2) {
var conceptHits = _ref2.conceptHits,
textHits = _ref2.textHits;
return intersect(patients, unionOfHits(conceptHits, textHits));
}), term]);
}
function findIndexAfter(coll, i, pred) {
while (i < coll.length) {
if (pred(coll[i])) {
return i;
}
++i;
}
return -1;
}
var advanceDoc = function advanceDoc(state) {
var docs = state.docs,
showDoc = state.showDoc,
next = findIndexAfter(docs, showDoc + 1, function (_ref3) {
var doc = _ref3.doc;
return doc;
});
return next === -1 ? _.dissoc(state, 'showDoc') : _.assoc(state, 'showDoc', next);
};
var advancePage = function advancePage(state) {
var page = state.page,
showDoc = state.showDoc;
return showDoc < page.n * (page.i + 1) ? state : _.updateIn(state, ['page', 'i'], function (i) {
return i + 1;
});
};
var setKeep = function setKeep(state, index, keep) {
return _.assocIn(state, ['filter', index], keep);
};
var reset = function reset(state) {
return _.assoc(state, 'open', false, 'docs', undefined);
};
var tiesControls = {
'ties-open': function tiesOpen(state) {
return _.assoc(state, 'open', true, 'page', { i: 0, n: 10 }, 'terms', [], 'showDoc', undefined, 'matches', {}, 'filter', {});
}, // init the filter
'ties-dismiss': function tiesDismiss(state) {
return _.dissoc(state, 'open');
}, // XXX clean up doc list?
'ties-add-term': function tiesAddTerm(state, term) {
return _.assoc(state, 'terms', _.conj(state.terms || [], term));
},
'ties-keep-row': function tiesKeepRow(state, index, keep) {
return advancePage(advanceDoc(setKeep(state, index, keep)));
},
'ties-keep-row-post!': fetchDoc,
'ties-show-doc': function tiesShowDoc(state, index) {
return _.assoc(state, 'showDoc', index);
},
'ties-show-doc-post!': fetchDoc,
'ties-hide-doc': function tiesHideDoc(state) {
return _.dissoc(state, 'showDoc');
},
'ties-set-page': function tiesSetPage(state, page) {
return _.assoc(state, 'page', page);
},
'ties-doc-list': function tiesDocList(state, docs) {
return _.assoc(state, 'docs', docs);
},
'ties-concepts': function tiesConcepts(state, concepts) {
return _.assoc(state, 'concepts', concepts);
},
'ties-doc': function tiesDoc(state, doc) {
return _.assoc(state, 'doc', doc);
},
'ties-matches': function tiesMatches(state, matches, term) {
return _.assocIn(state, ['matches', term], { matches: matches });
},
'ties-matches-error': function tiesMatchesError(state, err, term) {
return _.updateIn(state, ['terms'], function (terms) {
return _.without(terms, term);
});
},
cohort: reset,
cohortReset: reset,
manifest: reset
};
var spreadsheetControls = {
'ties-add-term-post!': fetchMatches,
'km-survival-data-post!': function kmSurvivalDataPost(serverBus, state, newState) {
var patients = _.getIn(newState, ['survival', 'patient', 'data', 'codes']),
docs = _.getIn(newState, ['ties', 'docs']),
open = _.getIn(newState, ['ties', 'open']);
if (open && !docs) {
fetchDocs(serverBus, patients);
}
}
};
var controls = {
'ties-open-post!': function tiesOpenPost(serverBus, state, newState) {
var patients = _.getIn(newState, ['spreadsheet', 'survival', 'patient', 'data', 'codes']),
docs = _.getIn(newState, ['spreadsheet', 'ties', 'docs']),
concepts = _.getIn(newState, ['spreadsheet', 'ties', 'concepts']);
if (!concepts) {
fetchConcepts(serverBus);
}
if (patients) {
if (!docs) {
fetchDocs(serverBus, patients);
}
} else {
fetchSurvival(serverBus, newState);
}
}
};
module.exports = compose(make(controls), mount(make(spreadsheetControls), ['spreadsheet']), mount(make(tiesControls), ['spreadsheet', 'ties']));