Skip to content

Commit

Permalink
Merge pull request #432 from plantinformatics/feature/reconnectGerminate
Browse files Browse the repository at this point in the history
Merge Germinate update
  • Loading branch information
Don-Isdale authored Nov 27, 2024
2 parents 5418265 + 3e90d9d commit a462b9f
Show file tree
Hide file tree
Showing 15 changed files with 1,080 additions and 1,008 deletions.
2 changes: 1 addition & 1 deletion frontend/app/components/draw/axis-1d.js
Original file line number Diff line number Diff line change
Expand Up @@ -1441,7 +1441,7 @@ export default Component.extend(Evented, AxisEvents, AxisPosition, {
as.classed("extended", this.get('extended'));
},
buttonStateEffect : computed('brushed', 'zoomed', function () {
later(() => this.isDestroying && this.showZoomResetButtonState(), 200);
later(() => ! this.isDestroying && this.showZoomResetButtonState(), 200);
}),
showZoomResetButtonState() {
let
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/components/form/dataset-graph.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<BsButton @type="info" class="margin-top" @onClick={{@close}}>Close</BsButton>

{{input type="search" value=naturalQuery
{{input type="search" value=this.naturalQuery
enter=(action this.naturalQueryChanged)
placeholder="Natural language search" }}

Expand Down
6 changes: 1 addition & 5 deletions frontend/app/components/panel/manage-genotype.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -838,12 +838,8 @@
{{!-- ----------------------------------------------------------------- --}}
{{#if this.vcfGenotypeLookupDomain}}
{{!-- disabled if ! All && no samples selected, or All && Common && no samples to select --}}
<button type="button" onclick={{action this.vcfGenotypeLookup}}
disabled={{or
(and (not @userSettings.requestSamplesAll) (not this.vcfGenotypeSamplesSelected.length))
(and @userSettings.requestSamplesAll @userSettings.samplesIntersection (not this.samples.length))
}}
disabled={{this.vcfGenotypeLookupButtonDisabled}}
class="btn btn-info">VCF Lookup</button>
{{else}}
{{#if this.urlOptions.gtIntervalLimit}}
Expand Down
84 changes: 71 additions & 13 deletions frontend/app/components/panel/manage-genotype.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { tracked } from '@glimmer/tracking';
import { later } from '@ember/runloop';
import { A as Ember_A } from '@ember/array';

import { task } from 'ember-concurrency';

// see comment in vcfGenotypeLookupDataset()
import { allSettled } from 'rsvp';

Expand All @@ -17,7 +19,7 @@ import createIntervalTree from 'interval-tree-1d';

import NamesFilters from '../../utils/data/names-filters';
import { toPromiseProxy, toArrayPromiseProxy, addObjectArrays, arrayClear } from '../../utils/ember-devel';
import { thenOrNow, contentOf, pollCondition } from '../../utils/common/promises';
import { thenOrNow, contentOf, pollCondition, promiseThrottle } from '../../utils/common/promises';
import { responseTextParseHtml } from '../../utils/domElements';
import { clipboard_writeText } from '../../utils/common/html';
import { arrayChoose } from '../../utils/common/arrays';
Expand Down Expand Up @@ -281,10 +283,11 @@ export default class PanelManageGenotypeComponent extends Component {
* sampleNames should be stored for.
* The dataset's name is this.lookupDatasetId, which is not necessarily unique
* when using multiple servers - see datasetsForName().
* dataset.sampleNames is used in services/data/paths-progressive.js : vcfGenotypeLookup()
*/
datasetStoreSampleNames(block, sampleNames) {
const
dataset = block.get('datasetId');
dataset = contentOf(block.get('datasetId'));
dataset.sampleNames = sampleNames;
}

Expand Down Expand Up @@ -2043,6 +2046,7 @@ export default class PanelManageGenotypeComponent extends Component {
if (vcfDataset.hasTag('BrAPI')) {
vcfDataset.samples = t;
t = t.mapBy('sampleName');
// instead use : sampleNames = t;
this.datasetStoreSampleNames(vcfBlock, t);
}
let sampleNamesText, sampleNames;
Expand Down Expand Up @@ -2079,7 +2083,9 @@ export default class PanelManageGenotypeComponent extends Component {
const
fnName = 'vcfGenotypeSamples',
vcfBlock = this.lookupBlock,
textP = this.vcfGenotypeSamplesDataset(vcfBlock);
dataset = contentOf(vcfBlock.get('datasetId')),
textPFn = () => this.vcfGenotypeSamplesDataset(vcfBlock),
textP = promiseThrottle(dataset, Symbol.for('samplesP'), 2 * 60 * 1000, textPFn);
/* vcfGenotypeSamplesDataset() initialises .vcfGenotypeSamplesSelected in
* this case; could move to here. */

Expand Down Expand Up @@ -2140,7 +2146,7 @@ export default class PanelManageGenotypeComponent extends Component {
* related : .ensureSamples();
*/
if (! this.vcfGenotypeSamplesText) {
dLog(fnName);
dLog(fnName, new Date().toISOString(), this.lookupBlock?.brushName);
this.vcfGenotypeSamples();
}

Expand Down Expand Up @@ -2284,13 +2290,43 @@ export default class PanelManageGenotypeComponent extends Component {
return {samples, samplesOK : ok};
}

/** Disable vcfGenotypeLookup button when samples are required and not
* selected, or previous button action is in process.
* @return disabled if ! All && no samples selected, or All && Common && no samples to select
* Also disabled if vcfGenotypeLookup button action is in process.
*/
get vcfGenotypeLookupButtonDisabled() {
const
userSettings = this.args.userSettings,
disabled =
((! userSettings.requestSamplesAll) && (! this.vcfGenotypeSamplesSelected?.length)) ||
(userSettings.requestSamplesAll && userSettings.samplesIntersection && ! this.samples?.length) ||
this.vcfGenotypeLookupTask.isRunning;
return disabled;
}

/** if vcfGenotypeLookupTask is not running, perform it. */
vcfGenotypeLookup() {
if (! this.vcfGenotypeLookupTask.isRunning) {
this.vcfGenotypeLookupTaskInstance = this.vcfGenotypeLookupTask.perform();
}
}
/** Call vcfGenotypeLookupP() in a task - yield the result.
*/
vcfGenotypeLookupTask = task({ drop: true }, async () => {
console.log('vcfGenotypeLookupTask');
let block = await this.vcfGenotypeLookupP();

return block;
});
/** Lookup the genotype for the selected samples in the interval of, depending on autoLookup :
* . all visible brushed VCF blocks, or
* . the brushed block selected by the currently viewed Datasets tab.
*/
vcfGenotypeLookup() {
vcfGenotypeLookupP() {
const
fnName = 'vcfGenotypeLookup';
let promise;
/** Germinate data is in Nucleotide format (CATG) and Alt / Ref is not
* currently received from Germinate data / interface, so cannot determine
* Numerical format (number of copies of Alt). So request and display CATG.
Expand All @@ -2299,18 +2335,21 @@ export default class PanelManageGenotypeComponent extends Component {
Ember_set(this, 'args.userSettings.requestFormat', 'CATG');
}
if (this.args.userSettings.autoLookup) {
this.vcfGenotypeLookupAllDatasets();
promise = Promise.all(this.vcfGenotypeLookupAllDatasets());
} else {
this.vcfGenotypeLookupSelected();
promise = this.vcfGenotypeLookupSelected();
}
return promise;
}

//----------------------------------------------------------------------------

/** Lookup the genotype for the selected samples in the interval of the brushed block,
* selected by the currently viewed Datasets tab.
* @return a promise, signalling completion, with response or failure, of the request
*/
vcfGenotypeLookupSelected() {
let promise;
const
fnName = 'vcfGenotypeLookupSelected',
/** this.axisBrush.block is currently the reference; lookup the data block. */
Expand All @@ -2330,12 +2369,15 @@ export default class PanelManageGenotypeComponent extends Component {
let blockV = this.lookupBlock;
const intersection = this.intersectionParamsSimple(vcfDatasetId);

this.vcfGenotypeLookupDataset(blockV, vcfDatasetId, intersection, scope, domainInteger, samples, samplesLimitEnable);
promise = this.vcfGenotypeLookupDataset(blockV, vcfDatasetId, intersection, scope, domainInteger, samples, samplesLimitEnable);
}
return promise;
}
/** Request VCF genotype for brushed datasets which are visible
* @return an array of promises, signalling completion, with response or failure, of the requests
*/
vcfGenotypeLookupAllDatasets() {
let promises;
// related : notes in showSamplesWithinBrush() re. isZoomedOut(), .rowLimit.
const
visibleBlocks = this.brushedOrViewedVCFBlocksVisible,
Expand All @@ -2361,24 +2403,30 @@ export default class PanelManageGenotypeComponent extends Component {
const
flags = '' + (k+1), /*-n*/
/** (visibleBlocks - requiredBlock) C k */
groups = arrayChoose(notSelf, k);
groups.forEach(group => {
groups = arrayChoose(notSelf, k),
groupsP =
groups.map(group => {
/** group combined with requiredBlock */
const selfAnd = group.concat([requiredBlock]);
this.vcfGenotypeLookupGroup(selfAnd, flags);
return this.vcfGenotypeLookupGroup(selfAnd, flags);
});
promises = groupsP.flat();
} else {
this.vcfGenotypeLookupGroup(blocks, /*flags*/undefined);
promises = this.vcfGenotypeLookupGroup(blocks, /*flags*/undefined);
}
return promises;
}
/** Request genotype calls for blocks.
* @param blocks
* @param flags for intersection, bcftools isec.
* Defined if choose, otherwise intersectionParamsSimple() is used.
* @return an array of promises, signalling completion, with response or failure, of the requests
*/
vcfGenotypeLookupGroup(blocks, flags) {
const
promises =
blocks
.forEach((blockV, i) => {
.map((blockV, i) => {
const
vcfDatasetId = blockV.get('datasetId.id'),
vcfDatasetIdAPI = blockV.get('datasetId.genotypeId'),
Expand All @@ -2394,6 +2442,7 @@ export default class PanelManageGenotypeComponent extends Component {
domain = blockV.get('brushedDomain'),
/** as in vcfGenotypeLookupDomain() and brushedDomainRounded() */
domainInteger = domain.map((d) => d.toFixed(0));
let promise;
/* samplesOK() returns .samples '' if none are selected; passing
* vcfGenotypeLookupDataset( samples==='' ) will get all samples, which
* may be valid, but for now skip this dataset if ! .length.
Expand All @@ -2404,9 +2453,12 @@ export default class PanelManageGenotypeComponent extends Component {
{datasetIds : blocks.mapBy('datasetId.genotypeId'), flags} :
this.intersectionParamsSimple(vcfDatasetId);

promise =
this.vcfGenotypeLookupDataset(blockV, vcfDatasetIdAPI, intersection, scope, domainInteger, samples, samplesLimitEnable);
}
return promise;
});
return promises.filter(p => p);
}
/** Send API request for VCF genotype of the given vcfDatasetId.
* If scope is defined it indicates which scope / chromosome of vcfDatasetId,
Expand Down Expand Up @@ -3775,6 +3827,7 @@ export default class PanelManageGenotypeComponent extends Component {
fnName = 'headerText',
isBrAPI = this.lookupBlock?.hasTag('BrAPI') ||
(this.lookupBlock?.server?.serverType === 'BrAPI'),
isGerminate = this.lookupBlock?.hasTag('Germinate'),
/** not clear why passing limitSamples false for VCF (edit was 2023 'Mar 1 21:20') */
{samples, samplesOK} = this.samplesOK(isBrAPI),
domainInteger = [0, 1],
Expand Down Expand Up @@ -3818,6 +3871,11 @@ export default class PanelManageGenotypeComponent extends Component {
this.headerText = text;
textP = Promise.resolve(text);
}
} else if (isGerminate) {
/** short-cut the vcfGenotypeLookup() request below because Germinate is
* taking ~1min for it, and there is no benefit - the header is expected to
* be simply samples. */
textP = Promise.resolve(samples);
} else
if (samplesOK && scopeOK && vcfDatasetId) {
const
Expand Down
57 changes: 45 additions & 12 deletions frontend/app/components/service/api-server-germinate.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,15 @@ export default EmberObject.extend(ApiServerAttributes, BrAPIWrapObj, {
*/
viewDatasetP : function(store, germinateDataset, linkageGroups) {
const
fnName = 'viewDatasetP',
datasetId = germinateDataset.mapDbId + '_' + germinateDataset.mapName,
apiServers = this.get('apiServers'),
/** Record the created datasets and blocks in id2Server, as in :
* services/data/dataset.js : taskGetList() : datasets.forEach()
*/
id2Server = apiServers.get('id2Server'),
datasetsBlocks = this.datasetsBlocks || this.set("datasetsBlocks", Ember_A()),
blocksP = linkageGroups.map(linkageGroup => {
linkageGroup2block = linkageGroup => {
const
name = linkageGroup.linkageGroupName,
chrMap = this.chrMapping?.findBy('0', name),
Expand All @@ -107,14 +109,22 @@ export default EmberObject.extend(ApiServerAttributes, BrAPIWrapObj, {
name : scope,
id : germinateDataset.mapDbId + '_' + name,
scope,
/* To link block to dataset, included the datasetId attribute here, but got :
* ... is not a record instantiated by @ember-data/store
* Solution used is to link dataset and block in blocksFinish() :
* ... block.set('datasetId', dataset);
* ... dataset.blocks.pushObjects(blocks);
*/
// datasetId,
featureCount : linkageGroup.markerCount,
/** linkageGroupName is used for /chromosome/ path param in API call. */
_meta : {linkageGroupName : linkageGroup.linkageGroupName},
},
blockP = store.createRecord('block', blockAttributes);
return blockP;
}),
datasetP = Promise.all(blocksP).then(blocks => {
block = store.createRecord('block', blockAttributes);
return block;
},

createDataset = () => {
const
/** Use .mapName for .id as well as .name, because dataset.id (not
* .displayName) is used in gtDatasetTabs which doesn't have space for
Expand All @@ -124,24 +134,43 @@ export default EmberObject.extend(ApiServerAttributes, BrAPIWrapObj, {
name = germinateDataset.mapName,
datasetAttributes = {
name,
id : germinateDataset.mapDbId + '_' + name,
id : datasetId,
parentName : this.parentName,
// type, _meta.type ?
tags : ['view', 'Genotype', 'Germinate'],
_meta : {
displayName : germinateDataset.mapName,
paths : false, germinate : germinateDataset},
// namespace
blocks
blocks : [],
};
const dataset = store.createRecord('dataset', datasetAttributes);
return dataset;
};

const
dataset = createDataset();

const blocksFinish = (dataset, blocks) => {
blocks.forEach(block => {
id2Server[block.get('id')] = this;
block.set('mapName', germinateDataset.mapName);
});
const p = store.createRecord('dataset', datasetAttributes);
return p;
});
datasetP.then(dataset => {

blocks.forEach(block => {
if (! block.get('datasetId.id')) {
dLog(fnName, block.scope, 'set datasetId', dataset.id);
block.set('datasetId', dataset);
}
});
dataset.blocks.pushObjects(blocks);
};

const
blocks = linkageGroups.map(linkageGroup2block);
blocksFinish(dataset, blocks);

const shareDataset = (dataset) => {
id2Server[dataset.get('id')] = this;
id2Server[dataset.get('genotypeId')] = this;
if (! datasetsBlocks.findBy('name', dataset.name)) {
Expand All @@ -151,7 +180,11 @@ export default EmberObject.extend(ApiServerAttributes, BrAPIWrapObj, {
apiServers.trigger('receivedDatasets', datasetsBlocks);
});
}
});
};

shareDataset(dataset);
const datasetP = Promise.resolve(dataset);

return datasetP;
},

Expand Down
2 changes: 1 addition & 1 deletion frontend/app/models/block-adj.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ export default Model.extend(Evented, {
dLog('taskGetPaths cancelled');
let
lastPerformed = this.get('lastPerformed');
if (lastPerformed.error)
if (lastPerformed?.error)
dLog('taskGetPaths lastPerformed.error', lastPerformed.error);
}
/* close EventSource.
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/services/data/paths-progressive.js
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ export default Service.extend({
/** VCF lookup does not require param samples, but Germinate and BrAPI require
* samples to be given.
*/
if (block.hasTag('BrAPI')) {
if (block.hasTag('BrAPI') || block.hasTag('Germinate')) {
const sampleNames = block.get('datasetId.sampleNames');
if (! sampleNames?.length) {
return Promise.resolve([]);
Expand All @@ -892,7 +892,7 @@ export default Service.extend({
* param so that error streams are independent. */
.catch(error => {
dLog(fnName, 'catch', error);
this.showText(error.responseJSON.error.message);
this.showText(error.responseJSON?.error?.message);
});
return textP;
},
Expand Down
Loading

0 comments on commit a462b9f

Please sign in to comment.