pdbe-molstar
Version:
Molstar implementation for PDBe
100 lines (99 loc) • 7.19 kB
JavaScript
;
/** Helper functions to allow superposition of complexes */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Coloring = void 0;
exports.loadComplexSuperposition = loadComplexSuperposition;
const tslib_1 = require("tslib");
const commands_1 = require("molstar/lib/mol-plugin/commands");
const sleep_1 = require("molstar/lib/mol-util/sleep");
const __1 = require("../..");
const helpers_1 = require("../../helpers");
const superposition_1 = require("../../superposition");
const Coloring = tslib_1.__importStar(require("./coloring"));
const superpose_by_biggest_chain_1 = require("./superpose-by-biggest-chain");
const superpose_by_sequence_alignment_1 = require("./superpose-by-sequence-alignment");
exports.Coloring = tslib_1.__importStar(require("./coloring"));
/** Load a structure, superpose onto the main structure based on Uniprot residue numbers (or seq alignment if numbers not available),
* and optionally apply coloring to show common/additional components.
*
* **Superposition method:**
* Complexes are superposed based on the largest common component (measured the by number of residues) with a UniProt mapping (taken from atom_site mmCIF category).
* In case there are no common components with Uniprot mapping, the largest common component with an Rfam mapping is used (taken from `baseMappings` and `otherMappings` parameters).
* Residue-residue correspondence is determined by UniProt residue numbers (for UniProt mappings) or by sequence alignment (for Rfam mappings).
*
* **Coloring - subcomplexes:**
* Common components are colored by entity; additional components are gray. Components in the subcomplex are slightly darkened.
*
* **Coloring - supercomplexes:**
* Common components are gray; mapped additional components are colored by entity; unmapped additional components are magenta. Components in the supercomplex are slightly darkened.
*/
function loadComplexSuperposition(viewer, params) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g;
const { pdbId, assemblyId, animationDuration = 250, coloring, baseComponents, otherComponents, baseMappings, otherMappings, coreColor, unmappedColor, componentColors } = params;
const baseStructId = __1.PDBeMolstarPlugin.MAIN_STRUCTURE_ID;
const otherStructId = (_a = params.id) !== null && _a !== void 0 ? _a : `${pdbId}_${assemblyId}`;
// Apply coloring to base structure
if (coloring) {
if (!baseComponents)
throw new Error('`baseComponents` is required when `coloring` is not `undefined`');
if (!otherComponents)
throw new Error('`otherComponents` is required when `coloring` is not `undefined`');
}
if (coloring === 'subcomplex') {
yield Coloring.colorSubcomplex(viewer, { baseStructId, baseComponents: baseComponents, otherComponents: otherComponents, baseMappings, otherMappings, coreColor, componentColors });
}
if (coloring === 'supercomplex') {
yield Coloring.colorSupercomplex(viewer, { baseStructId, baseComponents: baseComponents, otherComponents: otherComponents, baseMappings, otherMappings, coreColor, unmappedColor, componentColors });
}
// Load other structure
const otherStructUrl = (0, helpers_1.getStructureUrl)(viewer.initParams, { pdbId, queryType: 'full' });
yield viewer.load({ url: otherStructUrl, isBinary: viewer.initParams.encoding === 'bcif', assemblyId, id: otherStructId }, false);
yield viewer.visual.structureVisibility(otherStructId, false); // hide structure until superposition complete, to avoid flickering
const baseStruct = (_c = (_b = viewer.getStructure(baseStructId)) === null || _b === void 0 ? void 0 : _b.cell.obj) === null || _c === void 0 ? void 0 : _c.data;
if (!baseStruct)
throw new Error('Static structure not loaded');
const otherStruct = (_e = (_d = viewer.getStructure(otherStructId)) === null || _d === void 0 ? void 0 : _d.cell.obj) === null || _e === void 0 ? void 0 : _e.data;
if (!otherStruct)
throw new Error('Mobile structure not loaded');
// Superpose other structure on base structure
let superposition = (0, superpose_by_biggest_chain_1.superposeByBiggestCommonChain)(baseStruct, otherStruct, baseComponents, otherComponents);
if (!superposition) {
console.log(`UniProt-based superposition method failed, trying sequence alignment superposition (RNAs)`);
superposition = (0, superpose_by_sequence_alignment_1.superposeBySequenceAlignment)(baseStruct, otherStruct, baseMappings !== null && baseMappings !== void 0 ? baseMappings : {}, otherMappings !== null && otherMappings !== void 0 ? otherMappings : {});
}
if (superposition) {
yield (0, superposition_1.transform)(viewer.plugin, viewer.getStructure(otherStructId).cell, superposition.bTransform);
}
else {
console.log(`Sequence alignment superposition method failed, leaving unsuperposed`);
}
// Apply coloring to other structure
if (coloring === 'subcomplex') {
yield Coloring.colorSubcomplex(viewer, { otherStructId, baseComponents: baseComponents, otherComponents: otherComponents, baseMappings, otherMappings, coreColor, componentColors });
}
if (coloring === 'supercomplex') {
yield Coloring.colorSupercomplex(viewer, { otherStructId, baseComponents: baseComponents, otherComponents: otherComponents, baseMappings, otherMappings, coreColor, unmappedColor, componentColors });
}
// Adjust camera
const staticStructRef = viewer.getStructure(baseStructId);
const mobileStructRef = viewer.getStructure(otherStructId); // it is important to run this after superposition, to get correct coordinates for camera adjustment
// Wanted to use PluginCommands.Camera.Focus with viewer.plugin.canvas3d?.boundingSphere, but seems to not work properly, so using the following workaround:
yield commands_1.PluginCommands.Camera.FocusObject(viewer.plugin, {
targets: [
{ targetRef: staticStructRef === null || staticStructRef === void 0 ? void 0 : staticStructRef.cell.transform.ref, extraRadius: 0.3 },
{ targetRef: (_g = ((_f = mobileStructRef === null || mobileStructRef === void 0 ? void 0 : mobileStructRef.transform) !== null && _f !== void 0 ? _f : mobileStructRef)) === null || _g === void 0 ? void 0 : _g.cell.transform.ref, extraRadius: 0.3 },
// 0.3 is amount by which bounding sphere algorithm usually underestimates actual visible bounding sphere
],
durationMs: animationDuration,
});
yield (0, sleep_1.sleep)(animationDuration); // wait until camera adjustment completed
// Reveal new structure
yield viewer.visual.structureVisibility(otherStructId, true);
return {
id: otherStructId,
superposition,
delete: () => viewer.deleteStructure(otherStructId),
};
});
}