pdbe-molstar-3dbionotes
Version:
Molstar implementation for PDBe
433 lines • 26.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderSuperposition = exports.initSuperposition = void 0;
var tslib_1 = require("tslib");
var linear_algebra_1 = require("Molstar/mol-math/linear-algebra");
var builder_1 = require("Molstar/mol-script/language/builder");
var transforms_1 = require("Molstar/mol-plugin-state/transforms");
var assets_1 = require("Molstar/mol-util/assets");
var helpers_1 = require("./helpers");
var lists_1 = require("Molstar/mol-util/color/lists");
var color_1 = require("Molstar/mol-util/color/color");
function getRandomColor(plugin, segmentIndex) {
var clList = lists_1.ColorLists;
var spState = plugin.customState.superpositionState;
var palleteIndex = spState.colorState[segmentIndex].palleteIndex;
var colorIndex = spState.colorState[segmentIndex].colorIndex;
if (clList[spState.colorPalette[palleteIndex]].list[colorIndex + 1]) {
colorIndex += 1;
}
else {
colorIndex = 0;
palleteIndex = spState.colorPalette[palleteIndex + 1] ? palleteIndex + 1 : 0;
}
var palleteName = spState.colorPalette[palleteIndex];
plugin.customState.superpositionState.colorState[segmentIndex].palleteIndex = palleteIndex;
plugin.customState.superpositionState.colorState[segmentIndex].colorIndex = colorIndex;
return clList[palleteName].list[colorIndex];
}
function initSuperposition(plugin) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var customState, superpositionParams, segmentData, segmentIndex, clusterIndexs, entryList, clusters;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, plugin.clear()];
case 1:
_a.sent();
customState = plugin.customState;
superpositionParams = customState.initParams.superpositionParams;
plugin.customState.superpositionState = {
models: {},
entries: {},
refMaps: {},
segmentData: void 0,
matrixData: {},
activeSegment: 0,
loadedStructs: [],
visibleRefs: [],
invalidStruct: [],
noMatrixStruct: [],
hets: {},
colorPalette: ['dark-2', 'red-yellow-green', 'paired', 'set-1', 'accent', 'set-2', 'rainbow'],
colorState: []
};
// Get segment and cluster information for the given uniprot accession
return [4 /*yield*/, getSegmentData(plugin)];
case 2:
// Get segment and cluster information for the given uniprot accession
_a.sent();
segmentData = plugin.customState.superpositionState.segmentData;
if (!segmentData)
return [2 /*return*/];
// Load Matrix Data
return [4 /*yield*/, getMatrixData(plugin)];
case 3:
// Load Matrix Data
_a.sent();
if (!plugin.customState.superpositionState.segmentData)
return [2 /*return*/];
segmentData.forEach(function () {
plugin.customState.superpositionState.loadedStructs.push([]);
plugin.customState.superpositionState.visibleRefs.push([]);
plugin.customState.superpositionState.colorState.push({ palleteIndex: 0, colorIndex: -1 });
});
segmentIndex = (superpositionParams && superpositionParams.segment) ? superpositionParams.segment - 1 : 0;
plugin.customState.superpositionState.activeSegment = segmentIndex + 1;
clusterIndexs = (superpositionParams && superpositionParams.cluster) ? superpositionParams.cluster : void 0;
// Emit segment API data load event
plugin.customState.events.superpositionInit.next(true);
entryList = [];
clusters = segmentData[segmentIndex].clusters;
clusters.forEach(function (cluster, clusterIndex) {
// Validate for cluster index if provided in superPositionParams
if (clusterIndexs && clusterIndexs.indexOf(clusterIndex) === -1)
return;
// Add respresentative structure to the list
if (superpositionParams && superpositionParams.superposeAll) {
entryList = entryList.concat(cluster);
}
else {
entryList.push(cluster[0]);
}
});
return [4 /*yield*/, renderSuperposition(plugin, segmentIndex, entryList)];
case 4:
_a.sent();
return [2 /*return*/];
}
});
});
}
exports.initSuperposition = initSuperposition;
function renderSuperposition(plugin, segmentIndex, entryList) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var customState, superpositionParams, busyFlagOn;
var _this = this;
return tslib_1.__generator(this, function (_a) {
customState = plugin.customState;
superpositionParams = customState.initParams.superpositionParams;
busyFlagOn = false;
if (entryList.length > 1) {
busyFlagOn = true;
customState.events.isBusy.next(true);
}
// Load Coordinates and render respresentations
return [2 /*return*/, plugin.dataTransaction(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var spState, entryList_1, entryList_1_1, s, strUrl, strInstance, modelRef, clearOnFail, polymerInstance, modelInstance, isBinary, _a, model, structure, matrix, chainSel, uniformColor1, uniformColor2, invalidStruct, state, hets, interactingHets, hets_1, hets_1_1, het, ligParam, ligandQuery, labelTagParams, hetColor, _b, r, g, b, ligandExp, e_1_1, loadedStructIndex, e_2_1;
var e_2, _c, e_1, _d;
return tslib_1.__generator(this, function (_e) {
switch (_e.label) {
case 0:
spState = plugin.customState.superpositionState;
_e.label = 1;
case 1:
_e.trys.push([1, 35, 36, 41]);
entryList_1 = tslib_1.__asyncValues(entryList);
_e.label = 2;
case 2: return [4 /*yield*/, entryList_1.next()];
case 3:
if (!(entryList_1_1 = _e.sent(), !entryList_1_1.done)) return [3 /*break*/, 34];
s = entryList_1_1.value;
// validate matrix availability
if (!spState.matrixData[s.pdb_id + "_" + s.auth_asym_id]) {
spState.noMatrixStruct.push(s.pdb_id + "_" + s.struct_asym_id);
spState.invalidStruct.push(s.pdb_id + "_" + s.struct_asym_id);
return [3 /*break*/, 33];
}
spState.loadedStructs[segmentIndex].push(s.pdb_id + "_" + s.struct_asym_id);
strUrl = customState.initParams.pdbeUrl + "model-server/v1/" + s.pdb_id + "/atoms?auth_asym_id=" + s.auth_asym_id + "&encoding=" + customState.initParams.encoding;
if (superpositionParams && superpositionParams.ligandView)
strUrl = "https://www.ebi.ac.uk/pdbe/entry-files/download/" + s.pdb_id + ".bcif";
strInstance = void 0;
modelRef = void 0;
clearOnFail = true;
if (!(superpositionParams && superpositionParams.ligandView && spState.entries[s.pdb_id])) return [3 /*break*/, 5];
polymerInstance = plugin.state.data.select(spState.entries[s.pdb_id])[0];
modelRef = polymerInstance.transform.parent;
modelInstance = plugin.state.data.select(modelRef)[0];
return [4 /*yield*/, plugin.builders.structure.createStructure(modelInstance, { name: 'model', params: {} })];
case 4:
strInstance = _e.sent();
clearOnFail = false;
return [3 /*break*/, 7];
case 5:
isBinary = customState.initParams.encoding === 'bcif' ? true : false;
return [4 /*yield*/, loadStructure(plugin, strUrl, 'mmcif', isBinary)];
case 6:
_a = _e.sent(), model = _a.model, structure = _a.structure;
strInstance = structure;
modelRef = model.ref;
_e.label = 7;
case 7:
if (!strInstance)
return [3 /*break*/, 33];
// Store Refs in state
if (!spState.models[s.pdb_id + "_" + s.struct_asym_id])
spState.models[s.pdb_id + "_" + s.struct_asym_id] = strInstance === null || strInstance === void 0 ? void 0 : strInstance.ref;
if (superpositionParams && superpositionParams.ligandView && !spState.entries[s.pdb_id])
spState.entries[s.pdb_id] = strInstance === null || strInstance === void 0 ? void 0 : strInstance.ref;
matrix = linear_algebra_1.Mat4.ofRows(plugin.customState.superpositionState.matrixData[s.pdb_id + "_" + s.auth_asym_id].matrix);
return [4 /*yield*/, transform(plugin, strInstance, matrix)];
case 8:
_e.sent();
chainSel = void 0;
if (!((superpositionParams && superpositionParams.ligandView) && s.is_representative)) return [3 /*break*/, 12];
uniformColor1 = getRandomColor(plugin, segmentIndex);
return [4 /*yield*/, plugin.builders.structure.tryCreateComponentFromExpression(strInstance, chainSelection(s.struct_asym_id), "Chain-" + segmentIndex, { label: "Chain", tags: ["superposition-sel"] })];
case 9:
chainSel = _e.sent();
if (!chainSel) return [3 /*break*/, 11];
return [4 /*yield*/, plugin.builders.structure.representation.addRepresentation(chainSel, { type: 'putty', color: 'uniform', colorParams: { value: uniformColor1 }, size: 'uniform' }, { tag: "superposition-visual" })];
case 10:
_e.sent();
spState.refMaps[chainSel.ref] = s.pdb_id + "_" + s.struct_asym_id;
_e.label = 11;
case 11: return [3 /*break*/, 16];
case 12:
if (!((superpositionParams && superpositionParams.ligandView) && !s.is_representative)) return [3 /*break*/, 13];
return [3 /*break*/, 16];
case 13:
uniformColor2 = getRandomColor(plugin, segmentIndex);
return [4 /*yield*/, plugin.builders.structure.tryCreateComponentStatic(strInstance, 'polymer', { label: "Chain", tags: ["Chain-" + segmentIndex, "superposition-sel"] })];
case 14:
chainSel = _e.sent();
if (!chainSel) return [3 /*break*/, 16];
return [4 /*yield*/, plugin.builders.structure.representation.addRepresentation(chainSel, { type: 'putty', color: 'uniform', colorParams: { value: uniformColor2 }, size: 'uniform' }, { tag: "superposition-visual" })];
case 15:
_e.sent();
spState.refMaps[chainSel.ref] = s.pdb_id + "_" + s.struct_asym_id;
_e.label = 16;
case 16:
invalidStruct = chainSel ? false : true;
if (!(superpositionParams && superpositionParams.ligandView)) return [3 /*break*/, 33];
state = plugin.state.data;
return [4 /*yield*/, getHetNames(state, modelRef)];
case 17:
hets = _e.sent();
interactingHets = [];
if (!(hets && hets.length > 0)) return [3 /*break*/, 32];
_e.label = 18;
case 18:
_e.trys.push([18, 26, 27, 32]);
hets_1 = (e_1 = void 0, tslib_1.__asyncValues(hets));
_e.label = 19;
case 19: return [4 /*yield*/, hets_1.next()];
case 20:
if (!(hets_1_1 = _e.sent(), !hets_1_1.done)) return [3 /*break*/, 25];
het = hets_1_1.value;
ligParam = {
label_comp_id: het,
auth_asym_id: s.auth_asym_id
};
ligandQuery = helpers_1.LigandView.query(ligParam);
labelTagParams = { label: "" + het, tags: ["superposition-ligand-sel"] };
hetColor = color_1.Color.fromRgb(253, 3, 253);
if (superpositionParams && superpositionParams.ligandColor) {
_b = superpositionParams.ligandColor, r = _b.r, g = _b.g, b = _b.b;
hetColor = color_1.Color.fromRgb(r, g, b);
}
return [4 /*yield*/, plugin.builders.structure.tryCreateComponentFromExpression(strInstance, ligandQuery.core, het + "-" + segmentIndex, labelTagParams)];
case 21:
ligandExp = _e.sent();
if (!ligandExp) return [3 /*break*/, 23];
return [4 /*yield*/, plugin.builders.structure.representation.addRepresentation(ligandExp, { type: 'ball-and-stick', color: 'uniform', colorParams: { value: hetColor } }, { tag: "superposition-ligand-visual" })];
case 22:
_e.sent();
spState.refMaps[ligandExp.ref] = s.pdb_id + "_" + s.struct_asym_id;
_e.label = 23;
case 23:
if (ligandExp) {
invalidStruct = false;
interactingHets.push(het);
}
_e.label = 24;
case 24: return [3 /*break*/, 19];
case 25: return [3 /*break*/, 32];
case 26:
e_1_1 = _e.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 32];
case 27:
_e.trys.push([27, , 30, 31]);
if (!(hets_1_1 && !hets_1_1.done && (_d = hets_1.return))) return [3 /*break*/, 29];
return [4 /*yield*/, _d.call(hets_1)];
case 28:
_e.sent();
_e.label = 29;
case 29: return [3 /*break*/, 31];
case 30:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
case 31: return [7 /*endfinally*/];
case 32:
if (invalidStruct) {
spState.invalidStruct.push(s.pdb_id + "_" + s.struct_asym_id);
loadedStructIndex = spState.loadedStructs[segmentIndex].indexOf(s.pdb_id + "_" + s.struct_asym_id);
if (loadedStructIndex > -1)
spState.loadedStructs[segmentIndex].splice(loadedStructIndex, 1);
// remove downloaded data
if (clearOnFail) {
// const m = plugin.state.data.select(modelRef)[0];
// const t = plugin.state.data.select(m.transform.parent)[0];
// const d = plugin.state.data.select(t.transform.parent)[0];
// PluginCommands.State.RemoveObject(plugin, { state: d.parent!, ref: d.transform.parent, removeParentGhosts: true });
}
}
else {
if (interactingHets.length > 0)
spState.hets[s.pdb_id + "_" + s.struct_asym_id] = interactingHets;
}
_e.label = 33;
case 33: return [3 /*break*/, 2];
case 34: return [3 /*break*/, 41];
case 35:
e_2_1 = _e.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 41];
case 36:
_e.trys.push([36, , 39, 40]);
if (!(entryList_1_1 && !entryList_1_1.done && (_c = entryList_1.return))) return [3 /*break*/, 38];
return [4 /*yield*/, _c.call(entryList_1)];
case 37:
_e.sent();
_e.label = 38;
case 38: return [3 /*break*/, 40];
case 39:
if (e_2) throw e_2.error;
return [7 /*endfinally*/];
case 40: return [7 /*endfinally*/];
case 41:
if (busyFlagOn) {
busyFlagOn = false;
customState.events.isBusy.next(false);
}
return [2 /*return*/];
}
});
}); })];
});
});
}
exports.renderSuperposition = renderSuperposition;
function getHetNames(state, modelRef) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var cell, model, info;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
cell = state.select(modelRef)[0];
if (!cell || !cell.obj)
return [2 /*return*/, void 0];
model = cell.obj.data;
if (!model)
return [2 /*return*/];
return [4 /*yield*/, helpers_1.ModelInfo.get(model)];
case 1:
info = _a.sent();
if (info && info.hetNames.length > 0)
return [2 /*return*/, info.hetNames];
return [2 /*return*/, void 0];
}
});
});
}
function loadStructure(plugin, url, format, isBinary) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var data, trajectory, model, structure, e_3;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 5, , 6]);
return [4 /*yield*/, plugin.builders.data.download({ url: assets_1.Asset.Url(url), isBinary: isBinary })];
case 1:
data = _a.sent();
return [4 /*yield*/, plugin.builders.structure.parseTrajectory(data, format)];
case 2:
trajectory = _a.sent();
return [4 /*yield*/, plugin.builders.structure.createModel(trajectory)];
case 3:
model = _a.sent();
return [4 /*yield*/, plugin.builders.structure.createStructure(model, { name: 'model', params: {} })];
case 4:
structure = _a.sent();
return [2 /*return*/, { data: data, trajectory: trajectory, model: model, structure: structure }];
case 5:
e_3 = _a.sent();
return [2 /*return*/, { structure: void 0 }];
case 6: return [2 /*return*/];
}
});
});
}
function chainSelection(struct_asym_id) {
return builder_1.MolScriptBuilder.struct.generator.atomGroups({
'chain-test': builder_1.MolScriptBuilder.core.rel.eq([builder_1.MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), struct_asym_id])
});
}
function transform(plugin, s, matrix) {
var b = plugin.state.data.build().to(s)
.insert(transforms_1.StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: { data: matrix, transpose: false } } });
return plugin.runTask(plugin.state.data.updateTree(b));
}
function getMatrixData(plugin) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var customState, matrixAccession, clusterRecUrlStr, assetManager, clusterRecUrl, clusterRecData, e_4;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
customState = plugin.customState;
matrixAccession = customState.initParams.superpositionParams.matrixAccession ? customState.initParams.superpositionParams.matrixAccession : customState.initParams.moleculeId;
clusterRecUrlStr = customState.initParams.pdbeUrl + "graph-api/uniprot/superposition_matrices/" + matrixAccession;
assetManager = plugin.managers.asset;
clusterRecUrl = assets_1.Asset.getUrlAsset(assetManager, clusterRecUrlStr);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, plugin.runTask(assetManager.resolve(clusterRecUrl, 'json', false))];
case 2:
clusterRecData = _a.sent();
if (clusterRecData && clusterRecData.data) {
plugin.customState.superpositionState.matrixData = clusterRecData.data;
}
return [3 /*break*/, 4];
case 3:
e_4 = _a.sent();
customState['superpositionError'] = "Matrix data not available for " + matrixAccession;
plugin.customState.events.superpositionInit.next(true); // Emit segment API data load event
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
}
function getSegmentData(plugin) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var customState, segmentsUrl, assetManager, url, result, e_5;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
customState = plugin.customState;
segmentsUrl = customState.initParams.pdbeUrl + "graph-api/uniprot/superposition/" + customState.initParams.moleculeId;
assetManager = plugin.managers.asset;
url = assets_1.Asset.getUrlAsset(assetManager, segmentsUrl);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, plugin.runTask(assetManager.resolve(url, 'json', false))];
case 2:
result = _a.sent();
if (result && result.data) {
customState.superpositionState.segmentData = result.data[customState.initParams.moleculeId];
}
return [3 /*break*/, 4];
case 3:
e_5 = _a.sent();
customState['superpositionError'] = "Superposition data not available for " + customState.initParams.moleculeId;
plugin.customState.events.superpositionInit.next(true); // Emit segment API data load event
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
}
//# sourceMappingURL=superposition.js.map