ucsc-xena-client
Version:
UCSC Xena Client. Functional genomics visualizations.
484 lines (403 loc) • 17.9 kB
JavaScript
;
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));