UNPKG

ucsc-xena-client

Version:

UCSC Xena Client. Functional genomics visualizations.

199 lines (174 loc) 5.82 kB
'use strict'; 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']));