UNPKG

ucsc-xena-client

Version:

UCSC Xena Client. Functional genomics visualizations.

484 lines (403 loc) 17.9 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _require = require('../underscore_ext'), updateIn = _require.updateIn, dissoc = _require.dissoc, contains = _require.contains, pick = _require.pick, isEqual = _require.isEqual, get = _require.get, difference = _require.difference, uniq = _require.uniq, concat = _require.concat, pluck = _require.pluck, getIn = _require.getIn, assocIn = _require.assocIn, identity = _require.identity; var _require2 = require('./utils'), make = _require2.make, mount = _require2.mount, compose = _require2.compose; var _require3 = require('../xenaQuery'), cohortSummary = _require3.cohortSummary, datasetMetadata = _require3.datasetMetadata, datasetSamplesExamples = _require3.datasetSamplesExamples, datasetFieldN = _require3.datasetFieldN, datasetFieldExamples = _require3.datasetFieldExamples, fieldCodes = _require3.fieldCodes, datasetField = _require3.datasetField, datasetFetch = _require3.datasetFetch, datasetSamples = _require3.datasetSamples, sparseDataExamples = _require3.sparseDataExamples, segmentDataExamples = _require3.segmentDataExamples; var _require4 = require('../xenaAdmin'), deleteDataset = _require4.delete; var _require5 = require('./common'), userServers = _require5.userServers, datasetQuery = _require5.datasetQuery, updateWizard = _require5.updateWizard; var Rx = require('../rx'); var hubsToAdd = function hubsToAdd(_ref) { var hubs = _ref.hubs, addHub = _ref.addHub; return (hubs || []).concat(addHub || []); }; var hubsToRemove = function hubsToRemove(_ref2) { var removeHub = _ref2.removeHub; return removeHub || []; }; var removeHubs = function removeHubs(state, params) { return hubsToRemove(params).reduce(function (state, hub) { return assocIn(state, ['servers', hub, 'user'], false); }, state); }; var addHubs = function addHubs(state, params) { return hubsToAdd(params).reduce(function (state, hub) { return assocIn(state, ['servers', hub, 'user'], true); }, state); }; var setHubs = function setHubs(state, params) { return removeHubs(addHubs(state, params), params); }; var _Rx$Observable = Rx.Observable, ajax = _Rx$Observable.ajax, of = _Rx$Observable.of, zip = _Rx$Observable.zip, zipArray = _Rx$Observable.zipArray; var ajaxGet = function ajaxGet(url) { return ajax({ url: url, crossDomain: true, method: 'GET', responseType: 'text' }); }; var cohortMetaHost = 'https://rawgit.com/ucscXena/cohortMetaData/master'; var hostToGitURL = function hostToGitURL(host) { return cohortMetaHost + '/hub_' + host.replace(/https?:\/\//, '') + '/info.mdown'; }; var hubMeta = function hubMeta(host) { return ajaxGet(hostToGitURL(host)).catch(function () { return ajaxGet(host + '/download/meta/info.mdown'); }).map(function (r) { return r.response; }).catch(function () { return of(undefined); }); }; var cohortMeta = function cohortMeta(cohort) { return ajaxGet(cohortMetaHost + '/cohort_' + cohort + '/info.mdown').map(function (r) { return r.response; }).catch(function () { return of(undefined); }); }; var getMarkDown = function getMarkDown(url) { return ajaxGet(url).map(function (r) { return r.response; }).catch(function () { return of(undefined); }); }; var notGenomic = ["sampleMap", "probeMap", "genePred", "genePredExt"]; var genomicCohortSummary = function genomicCohortSummary(server) { return zipArray([cohortSummary(server, notGenomic), hubMeta(server)]).map(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), cohorts = _ref4[0], meta = _ref4[1]; return { server: server, meta: meta, cohorts: cohorts }; }).catch(function (err) { console.log(err);return of({ server: server, cohorts: [] }); }); }; function fetchCohortSummary(serverBus, servers) { var q = Rx.Observable.zipArray(servers.map(genomicCohortSummary)); serverBus.next(['cohort-summary', q]); } function fetchCohortData(serverBus, state) { var cohort = state.params.cohort, servers = userServers(state.spreadsheet); serverBus.next(['cohort-data', datasetQuery(servers, { name: cohort }), cohort]); serverBus.next(['cohort-data-meta', cohortMeta(cohort), cohort]); } function fetchMarkDown(serverBus, state) { var markdown = state.params.markdown; serverBus.next(['get-markdown', getMarkDown(markdown), markdown]); } // emit url if HEAD request succeeds var head = function head(url) { return ajax({ url: url, crossDomain: true, method: 'HEAD' }).map(function () { return url; }); }; // Check for dataset download link. If not there, try the link with '.gz' // suffix. If not there, return undefined. var checkDownload = function checkDownload(host, dataset) { var link = host + '/download/' + dataset, gzlink = link + '.gz', dl = head(link), gzdl = head(gzlink), nodl = of(undefined); return dl.catch(function () { return gzdl; }).catch(function () { return nodl; }); }; var noSnippets = function noSnippets() { return of(undefined); }; function fetchMatrixDataSnippets(host, dataset, meta) { var nProbes = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 10; var nSamples = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 10; var samplesQ = datasetSamplesExamples(host, dataset, nSamples).share(), fieldQ = datasetFieldExamples(host, dataset, nProbes).share(), codeQ = fieldQ.mergeMap(function (probes) { return fieldCodes(host, dataset, probes); }), dataQ = zipArray(samplesQ, fieldQ).mergeMap(function (_ref5) { var _ref6 = _slicedToArray(_ref5, 2), samples = _ref6[0], fields = _ref6[1]; return datasetFetch(host, dataset, samples, fields); }); return zipArray(samplesQ, fieldQ, codeQ, dataQ).map(function (_ref7) { var _ref8 = _slicedToArray(_ref7, 4), samples = _ref8[0], fields = _ref8[1], codes = _ref8[2], data = _ref8[3]; return { samples: samples, fields: fields, codes: codes, data: data }; }).catch(noSnippets); } var mutationAttrs = function mutationAttrs(_ref9) { var rows = _ref9.rows; return _extends({ chrom: pluck(rows.position, 'chrom'), chromstart: pluck(rows.position, 'chromstart'), chromend: pluck(rows.position, 'chromend') }, pick(rows, 'sampleID', 'ref', 'alt', 'effect', 'amino-acid', 'gene')); }; var fetchMutationDataSnippets = function fetchMutationDataSnippets(host, dataset) { var nProbes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; return sparseDataExamples(host, dataset, nProbes).map(mutationAttrs).catch(noSnippets); }; var segmentAttrs = function segmentAttrs(_ref10) { var rows = _ref10.rows; return _extends({ chrom: pluck(rows.position, 'chrom'), chromstart: pluck(rows.position, 'chromstart'), chromend: pluck(rows.position, 'chromend') }, pick(rows, 'sampleID', 'value')); }; var fetchSegmentedDataSnippets = function fetchSegmentedDataSnippets(host, dataset) { var nProbes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; return segmentDataExamples(host, dataset, nProbes).map(segmentAttrs).catch(noSnippets); }; var snippetMethod = function snippetMethod() { var _ref11 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref11$type = _ref11.type, type = _ref11$type === undefined ? 'genomicMatrix' : _ref11$type; return type === 'clinicalMatrix' ? fetchMatrixDataSnippets : type === 'genomicMatrix' ? fetchMatrixDataSnippets : type === 'mutationVector' ? fetchMutationDataSnippets : type === 'genomicSegment' ? fetchSegmentedDataSnippets : noSnippets; }; var noProbeCount = function noProbeCount() { return of(undefined); }; var probeCountMethod = function probeCountMethod() { var _ref12 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref12$type = _ref12.type, type = _ref12$type === undefined ? 'genomicMatrix' : _ref12$type; return type === 'clinicalMatrix' ? datasetFieldN : type === 'genomicMatrix' ? datasetFieldN : noProbeCount; }; var datasetMetaAndLinks = function datasetMetaAndLinks(host, dataset) { var metaQ = datasetMetadata(host, dataset).map(function (m) { return m[0]; }).share(), downloadQ = checkDownload(host, dataset), dataQ = metaQ.mergeMap(function (meta) { return snippetMethod(meta)(host, dataset); }), probeCountQ = metaQ.mergeMap(function (meta) { return probeCountMethod(meta)(host, dataset); }), probemapQ = metaQ.mergeMap(function (meta) { return get(meta, 'probeMap') ? checkDownload(host, meta.probeMap) : of(undefined); }); return zip(metaQ, dataQ, probeCountQ, downloadQ, probemapQ, function (meta, data, probeCount, downloadLink, probemapLink) { return { meta: meta, data: data, probeCount: probeCount, downloadLink: downloadLink, probemapLink: probemapLink }; }); }; function fetchDataset(serverBus, state) { var _state$params = state.params, host = _state$params.host, dataset = _state$params.dataset; serverBus.next(['dataset-meta', datasetMetaAndLinks(host, dataset), host, dataset]); } function fetchIdentifiers(serverBus, state) { var _state$params2 = state.params, host = _state$params2.host, dataset = _state$params2.dataset; serverBus.next(['dataset-identifiers', datasetField(host, dataset), host, dataset]); } function fetchSamples(serverBus, state) { var _state$params3 = state.params, host = _state$params3.host, dataset = _state$params3.dataset; serverBus.next(['dataset-samples', datasetSamples(host, dataset, null), host, dataset]); } // wrapper to discard extra params var hostUpdateWizard = function hostUpdateWizard(serverBus, state, newState) { return updateWizard(serverBus, state, newState); }; var spreadsheetControls = { 'init': function init(state) { var pathname = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '/'; var params = arguments[2]; return setHubs(state, params); }, 'add-host': function addHost(state, host) { return assocIn(state, ['servers', host], { user: true }); }, 'add-host-post!': hostUpdateWizard, 'remove-host': function removeHost(state, host) { return updateIn(state, ['servers'], function (s) { return dissoc(s, host); }); }, 'remove-host-post!': hostUpdateWizard, 'enable-host': function enableHost(state, host, list) { return assocIn(state, ['servers', host, list], true); }, 'enable-host-post!': hostUpdateWizard, 'disable-host': function disableHost(state, host, list) { return assocIn(state, ['servers', host, list], false); }, 'disable-host-post!': hostUpdateWizard }; var controls = { 'cohort-summary': function cohortSummary(state, cohorts) { return updateIn(state, ['datapages', 'cohorts'], function () { var list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; return concat(list, cohorts); }); }, 'cohort-data': function cohortData(state, datasets, cohort) { return assocIn(state, ['datapages', 'cohort', 'cohort'], cohort, ['datapages', 'cohort', 'datasets'], datasets); }, 'cohort-data-meta': function cohortDataMeta(state, meta) { return assocIn(state, ['datapages', 'cohort', 'meta'], meta); }, 'dataset-meta': function datasetMeta(state, metaAndLinks, host, dataset) { return assocIn(state, ['datapages', 'dataset'], _extends({ host: host, dataset: dataset }, metaAndLinks)); }, 'dataset-identifiers': function datasetIdentifiers(state, list, host, dataset) { return assocIn(state, ['datapages', 'identifiers'], { host: host, dataset: dataset, list: list }); }, 'dataset-samples': function datasetSamples(state, list, host, dataset) { return assocIn(state, ['datapages', 'samples'], { host: host, dataset: dataset, list: list }); }, 'delete-dataset-post!': function deleteDatasetPost(serverBus, state, newState, host, name) { return serverBus.next(['dataset-deleted', deleteDataset(host, name)]); }, 'get-markdown': function getMarkdown(state, markdownContent, markdownURL) { return assocIn(state, ['datapages', 'markdownContent'], markdownContent, ['datapages', 'markdownURL'], markdownURL); }, // Force page load after delete, to refresh all data. 'dataset-deleted-post!': function datasetDeletedPost() { return location.reload(); } }; var getSection = function getSection(_ref13) { var dataset = _ref13.dataset, host = _ref13.host, cohort = _ref13.cohort, allIdentifiers = _ref13.allIdentifiers, allSamples = _ref13.allSamples; return allSamples ? 'samples' : allIdentifiers ? 'identifiers' : dataset && host ? 'dataset' : host ? 'hub' : cohort ? 'cohort' : 'summary'; }; var linkedHub = function linkedHub(state) { return state.params.host ? [state.params.host] : []; }; var needCohortHubs = function needCohortHubs(state) { return state.page === 'datapages' && contains(['summary', 'hub'], getSection(state.params)) ? uniq(userServers(state.spreadsheet).concat(linkedHub(state))) : []; }; var hasCohortHubs = function hasCohortHubs(state) { return pluck(getIn(state, ['datapages', 'cohorts'], []), 'server'); }; var needACohort = function needACohort(state) { return state.page === 'datapages' && getSection(state.params) === 'cohort' && state.params.cohort; }; var hasACohort = function hasACohort(state, cohort) { return cohort === getIn(state, ['datapages', 'cohort', 'cohort']); }; var needDataset = function needDataset(state) { return state.page === 'datapages' && getSection(state.params) === 'dataset' && pick(state.params, 'dataset', 'host'); }; var hasDataset = function hasDataset(state, _ref14) { var dataset = _ref14.dataset, host = _ref14.host; return dataset === getIn(state, ['datapages', 'dataset', 'dataset']) && host === getIn(state, ['datapages', 'dataset', 'host']); }; var needIdentifiers = function needIdentifiers(state) { return state.page === 'datapages' && getSection(state.params) === 'identifiers' && pick(state.params, 'dataset', 'host'); }; var hasIdentifiers = function hasIdentifiers(state, _ref15) { var dataset = _ref15.dataset, host = _ref15.host; return dataset === getIn(state, ['datapages', 'identifiers', 'dataset']) && host === getIn(state, ['datapages', 'identifiers', 'host']) && getIn(state, ['datapages', 'identifiers', 'identifiers']); }; var needSamples = function needSamples(state) { return state.page === 'datapages' && getSection(state.params) === 'samples' && pick(state.params, 'dataset', 'host'); }; var needMarkDown = function needMarkDown(state) { return state.page === 'datapages' && pick(state.params, 'markdown') && state.params.markdown && state.params.markdown.indexOf("https://raw.githubusercontent.com/ucscXena/cohortMetaData/master") === 0; }; var hasAMarkDown = function hasAMarkDown(state, markdown) { return markdown === getIn(state, ['datapages', 'markdownURL']); }; var hasSamples = function hasSamples(state, _ref16) { var dataset = _ref16.dataset, host = _ref16.host; return dataset === getIn(state, ['datapages', 'samples', 'dataset']) && host === getIn(state, ['datapages', 'samples', 'host']) && getIn(state, ['datapages', 'samples', 'samples']); }; // We don't save datapages over reload. We fetch missing data the first // time it is required, meaning a) in the previous state we did not // require it, or b) it is the 'init' action. function datapagesPostActions(serverBus, state, newState, action) { // XXX is this only relevant in 'init' and 'navigate' actions? var _action = _slicedToArray(action, 1), type = _action[0]; var needHubs = needCohortHubs(newState); if (needHubs) { var prevHubs = needCohortHubs(state), hubChange = difference(needHubs, prevHubs); if (type === 'init' || hubChange.length) { var hasHubs = hasCohortHubs(newState), missing = difference(needHubs, hasHubs); if (missing.length) { fetchCohortSummary(serverBus, missing); } } } var aCohort = needACohort(newState); if (aCohort && !hasACohort(newState, aCohort) && (type === 'init' || needACohort(state) !== aCohort)) { fetchCohortData(serverBus, newState); } var dataset = needDataset(newState); if (dataset && !hasDataset(state, dataset) && (type === 'init' || !isEqual(needDataset(state), dataset))) { fetchDataset(serverBus, newState); } var identifiers = needIdentifiers(newState); if (identifiers && !hasIdentifiers(state, identifiers) && (type === 'init' || !isEqual(needIdentifiers(state), identifiers))) { fetchIdentifiers(serverBus, newState); } var samples = needSamples(newState); if (samples && !hasSamples(state, samples) && (type === 'init' || !isEqual(needSamples(state), samples))) { fetchSamples(serverBus, newState); } var markdown = needMarkDown(newState); if (markdown && !hasAMarkDown(state, markdown)) { fetchMarkDown(serverBus, newState); } } var datapagesPostController = { action: identity, postAction: datapagesPostActions }; module.exports = compose(datapagesPostController, mount(make(spreadsheetControls), ['spreadsheet']), make(controls));