molstar
Version:
A comprehensive macromolecular library.
418 lines • 23.6 kB
JavaScript
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign, __awaiter, __extends, __generator } from "tslib";
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
import { ValidationReport, ValidationReportProvider } from './prop';
import { RandomCoilIndexColorThemeProvider } from './color/random-coil-index';
import { GeometryQualityColorThemeProvider } from './color/geometry-quality';
import { OrderedSet } from '../../../mol-data/int';
import { ClashesRepresentationProvider } from './representation';
import { DensityFitColorThemeProvider } from './color/density-fit';
import { cantorPairing } from '../../../mol-data/util';
import { DefaultQueryRuntimeTable } from '../../../mol-script/runtime/query/compiler';
import { StructureSelectionQuery, StructureSelectionCategory } from '../../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
import { Task } from '../../../mol-task';
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../../mol-state';
import { Model } from '../../../mol-model/structure';
export var RCSBValidationReport = PluginBehavior.create({
name: 'rcsb-validation-report-prop',
category: 'custom-props',
display: {
name: 'Validation Report',
description: 'Data from wwPDB Validation Report, obtained via RCSB PDB.'
},
ctor: /** @class */ (function (_super) {
__extends(class_1, _super);
function class_1() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.provider = ValidationReportProvider;
_this.labelProvider = {
label: function (loci) {
if (!_this.params.showTooltip)
return;
return [
geometryQualityLabel(loci),
densityFitLabel(loci),
randomCoilIndexLabel(loci)
].filter(function (l) { return !!l; }).join('</br>');
}
};
return _this;
}
class_1.prototype.register = function () {
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
this.ctx.managers.lociLabels.addProvider(this.labelProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(DensityFitColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(GeometryQualityColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(RandomCoilIndexColorThemeProvider);
this.ctx.representation.structure.registry.add(ClashesRepresentationProvider);
this.ctx.query.structure.registry.add(hasClash);
this.ctx.builders.structure.representation.registerPreset(ValidationReportGeometryQualityPreset);
this.ctx.builders.structure.representation.registerPreset(ValidationReportDensityFitPreset);
this.ctx.builders.structure.representation.registerPreset(ValidationReportRandomCoilIndexPreset);
};
class_1.prototype.update = function (p) {
var updated = this.params.autoAttach !== p.autoAttach;
this.params.autoAttach = p.autoAttach;
this.params.showTooltip = p.showTooltip;
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
return updated;
};
class_1.prototype.unregister = function () {
DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
this.ctx.managers.lociLabels.removeProvider(this.labelProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(DensityFitColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(GeometryQualityColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(RandomCoilIndexColorThemeProvider);
this.ctx.representation.structure.registry.remove(ClashesRepresentationProvider);
this.ctx.query.structure.registry.remove(hasClash);
this.ctx.builders.structure.representation.unregisterPreset(ValidationReportGeometryQualityPreset);
this.ctx.builders.structure.representation.unregisterPreset(ValidationReportDensityFitPreset);
this.ctx.builders.structure.representation.unregisterPreset(ValidationReportRandomCoilIndexPreset);
};
return class_1;
}(PluginBehavior.Handler)),
params: function () { return ({
autoAttach: PD.Boolean(false),
showTooltip: PD.Boolean(true),
baseUrl: PD.Text(ValidationReport.DefaultBaseUrl)
}); }
});
//
function geometryQualityLabel(loci) {
if (loci.kind === 'element-loci') {
if (loci.elements.length === 0)
return;
if (loci.elements.length === 1 && OrderedSet.size(loci.elements[0].indices) === 1) {
var _a = loci.elements[0], unit = _a.unit, indices = _a.indices;
var validationReport = ValidationReportProvider.get(unit.model).value;
if (!validationReport)
return;
if (!unit.model.customProperties.hasReference(ValidationReportProvider.descriptor))
return;
var bondOutliers_1 = validationReport.bondOutliers, angleOutliers_1 = validationReport.angleOutliers;
var eI = unit.elements[OrderedSet.start(indices)];
var issues_1 = new Set();
var bonds = bondOutliers_1.index.get(eI);
if (bonds)
bonds.forEach(function (b) { return issues_1.add(bondOutliers_1.data[b].tag); });
var angles = angleOutliers_1.index.get(eI);
if (angles)
angles.forEach(function (a) { return issues_1.add(angleOutliers_1.data[a].tag); });
if (issues_1.size === 0) {
return "Geometry Quality <small>(1 Atom)</small>: no issues";
}
var summary_1 = [];
issues_1.forEach(function (name) { return summary_1.push(name); });
return "Geometry Quality <small>(1 Atom)</small>: " + summary_1.join(', ');
}
var hasValidationReport = false;
var seen_1 = new Set();
var cummulativeIssues_1 = new Map();
var _loop_1 = function (indices, unit) {
var validationReport = ValidationReportProvider.get(unit.model).value;
if (!validationReport)
return "continue";
if (!unit.model.customProperties.hasReference(ValidationReportProvider.descriptor))
return "continue";
hasValidationReport = true;
var geometryIssues = validationReport.geometryIssues;
var residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
var elements = unit.elements;
OrderedSet.forEach(indices, function (idx) {
var eI = elements[idx];
var rI = residueIndex[eI];
var residueKey = cantorPairing(rI, unit.id);
if (!seen_1.has(residueKey)) {
var issues = geometryIssues.get(rI);
if (issues) {
issues.forEach(function (name) {
var count = cummulativeIssues_1.get(name) || 0;
cummulativeIssues_1.set(name, count + 1);
});
}
seen_1.add(residueKey);
}
});
};
for (var _i = 0, _b = loci.elements; _i < _b.length; _i++) {
var _c = _b[_i], indices = _c.indices, unit = _c.unit;
_loop_1(indices, unit);
}
if (!hasValidationReport)
return;
var residueCount = "<small>(" + seen_1.size + " " + (seen_1.size > 1 ? 'Residues' : 'Residue') + ")</small>";
if (cummulativeIssues_1.size === 0) {
return "Geometry Quality " + residueCount + ": no issues";
}
var summary_2 = [];
cummulativeIssues_1.forEach(function (count, name) {
summary_2.push("" + name + (count > 1 ? " \u00D7 " + count : ''));
});
return "Geometry Quality " + residueCount + ": " + summary_2.join(', ');
}
}
function densityFitLabel(loci) {
if (loci.kind === 'element-loci') {
if (loci.elements.length === 0)
return;
var seen_2 = new Set();
var rsrzSeen_1 = new Set();
var rsccSeen_1 = new Set();
var rsrzSum_1 = 0;
var rsccSum_1 = 0;
var _loop_2 = function (indices, unit) {
var validationReport = ValidationReportProvider.get(unit.model).value;
if (!validationReport)
return "continue";
if (!unit.model.customProperties.hasReference(ValidationReportProvider.descriptor))
return "continue";
var rsrz = validationReport.rsrz, rscc = validationReport.rscc;
var residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
var elements = unit.elements;
OrderedSet.forEach(indices, function (idx) {
var eI = elements[idx];
var rI = residueIndex[eI];
var residueKey = cantorPairing(rI, unit.id);
if (!seen_2.has(residueKey)) {
var rsrzValue = rsrz.get(rI);
var rsccValue = rscc.get(rI);
if (rsrzValue !== undefined) {
rsrzSum_1 += rsrzValue;
rsrzSeen_1.add(residueKey);
}
else if (rsccValue !== undefined) {
rsccSum_1 += rsccValue;
rsccSeen_1.add(residueKey);
}
seen_2.add(residueKey);
}
});
};
for (var _i = 0, _a = loci.elements; _i < _a.length; _i++) {
var _b = _a[_i], indices = _b.indices, unit = _b.unit;
_loop_2(indices, unit);
}
if (seen_2.size === 0)
return;
var summary = [];
if (rsrzSeen_1.size) {
var rsrzCount = "<small>(" + rsrzSeen_1.size + " " + (rsrzSeen_1.size > 1 ? 'Residues avg.' : 'Residue') + ")</small>";
var rsrzAvg = rsrzSum_1 / rsrzSeen_1.size;
summary.push("Real-Space R Z-score " + rsrzCount + ": " + rsrzAvg.toFixed(2));
}
if (rsccSeen_1.size) {
var rsccCount = "<small>(" + rsccSeen_1.size + " " + (rsccSeen_1.size > 1 ? 'Residues avg.' : 'Residue') + ")</small>";
var rsccAvg = rsccSum_1 / rsccSeen_1.size;
summary.push("Real-Space Correlation Coefficient " + rsccCount + ": " + rsccAvg.toFixed(2));
}
if (summary.length) {
return summary.join('</br>');
}
}
}
function randomCoilIndexLabel(loci) {
if (loci.kind === 'element-loci') {
if (loci.elements.length === 0)
return;
var seen_3 = new Set();
var sum_1 = 0;
var _loop_3 = function (indices, unit) {
var validationReport = ValidationReportProvider.get(unit.model).value;
if (!validationReport)
return "continue";
if (!unit.model.customProperties.hasReference(ValidationReportProvider.descriptor))
return "continue";
var rci = validationReport.rci;
var residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
var elements = unit.elements;
OrderedSet.forEach(indices, function (idx) {
var eI = elements[idx];
var rI = residueIndex[eI];
var residueKey = cantorPairing(rI, unit.id);
if (!seen_3.has(residueKey)) {
var rciValue = rci.get(rI);
if (rciValue !== undefined) {
sum_1 += rciValue;
seen_3.add(residueKey);
}
}
});
};
for (var _i = 0, _a = loci.elements; _i < _a.length; _i++) {
var _b = _a[_i], indices = _b.indices, unit = _b.unit;
_loop_3(indices, unit);
}
if (seen_3.size === 0)
return;
var residueCount = "<small>(" + seen_3.size + " " + (seen_3.size > 1 ? 'Residues avg.' : 'Residue') + ")</small>";
var rciAvg = sum_1 / seen_3.size;
return "Random Coil Index " + residueCount + ": " + rciAvg.toFixed(2);
}
}
//
var hasClash = StructureSelectionQuery('Residues with Clashes', MS.struct.modifier.union([
MS.struct.modifier.wholeResidues([
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
'atom-test': ValidationReport.symbols.hasClash.symbol(),
})
])
])
]), {
description: 'Select residues with clashes in the wwPDB validation report.',
category: StructureSelectionCategory.Residue,
ensureCustomProperties: function (ctx, structure) {
return ValidationReportProvider.attach(ctx, structure.models[0]);
}
});
//
export var ValidationReportGeometryQualityPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-rcsb-validation-report-geometry-uality',
display: {
name: 'Validation Report (Geometry Quality)', group: 'Annotation',
description: 'Color structure based on geometry quality; show geometry clashes. Data from wwPDB Validation Report, obtained via RCSB PDB.'
},
isApplicable: function (a) {
return a.data.models.length === 1 && ValidationReport.isApplicable(a.data.models[0]);
},
params: function () { return StructureRepresentationPresetProvider.CommonParams; },
apply: function (ref, params, plugin) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var structureCell, structure, colorTheme, _b, components, representations, clashes, _c, update, builder, typeParams, color, clashesBallAndStick, clashesRepr;
var _this = this;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
structure = (_a = structureCell === null || structureCell === void 0 ? void 0 : structureCell.obj) === null || _a === void 0 ? void 0 : _a.data;
if (!structureCell || !structure)
return [2 /*return*/, {}];
return [4 /*yield*/, plugin.runTask(Task.create('Validation Report', function (runtime) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, ValidationReportProvider.attach({ runtime: runtime, assetManager: plugin.managers.asset }, structure.models[0])];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }))];
case 1:
_d.sent();
colorTheme = GeometryQualityColorThemeProvider.name;
return [4 /*yield*/, PresetStructureRepresentations.auto.apply(ref, __assign(__assign({}, params), { theme: { globalName: colorTheme, focus: { name: colorTheme } } }), plugin)];
case 2:
_b = _d.sent(), components = _b.components, representations = _b.representations;
return [4 /*yield*/, plugin.builders.structure.tryCreateComponentFromExpression(structureCell, hasClash.expression, 'clashes', { label: 'Clashes' })];
case 3:
clashes = _d.sent();
_c = StructureRepresentationPresetProvider.reprBuilder(plugin, params), update = _c.update, builder = _c.builder, typeParams = _c.typeParams, color = _c.color;
if (representations) {
clashesBallAndStick = builder.buildRepresentation(update, clashes, { type: 'ball-and-stick', typeParams: typeParams, color: colorTheme }, { tag: 'clashes-ball-and-stick' });
clashesRepr = builder.buildRepresentation(update, clashes, { type: ClashesRepresentationProvider.name, typeParams: typeParams, color: color }, { tag: 'clashes-repr' });
}
return [4 /*yield*/, update.commit({ revertOnError: true })];
case 4:
_d.sent();
return [2 /*return*/, { components: __assign(__assign({}, components), { clashes: clashes }), representations: __assign(__assign({}, representations), { clashesBallAndStick: clashesBallAndStick, clashesRepr: clashesRepr }) }];
}
});
});
}
});
export var ValidationReportDensityFitPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-rcsb-validation-report-density-fit',
display: {
name: 'Validation Report (Density Fit)', group: 'Annotation',
description: 'Color structure based on density fit. Data from wwPDB Validation Report, obtained via RCSB PDB.'
},
isApplicable: function (a) {
return a.data.models.length === 1 && ValidationReport.isApplicable(a.data.models[0]) && Model.isFromXray(a.data.models[0]) && Model.probablyHasDensityMap(a.data.models[0]);
},
params: function () { return StructureRepresentationPresetProvider.CommonParams; },
apply: function (ref, params, plugin) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var structureCell, structure, colorTheme;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
structure = (_a = structureCell === null || structureCell === void 0 ? void 0 : structureCell.obj) === null || _a === void 0 ? void 0 : _a.data;
if (!structureCell || !structure)
return [2 /*return*/, {}];
return [4 /*yield*/, plugin.runTask(Task.create('Validation Report', function (runtime) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, ValidationReportProvider.attach({ runtime: runtime, assetManager: plugin.managers.asset }, structure.models[0])];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }))];
case 1:
_b.sent();
colorTheme = DensityFitColorThemeProvider.name;
return [4 /*yield*/, PresetStructureRepresentations.auto.apply(ref, __assign(__assign({}, params), { theme: { globalName: colorTheme, focus: { name: colorTheme } } }), plugin)];
case 2: return [2 /*return*/, _b.sent()];
}
});
});
}
});
export var ValidationReportRandomCoilIndexPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-rcsb-validation-report-random-coil-index',
display: {
name: 'Validation Report (Random Coil Index)', group: 'Annotation',
description: 'Color structure based on Random Coil Index. Data from wwPDB Validation Report, obtained via RCSB PDB.'
},
isApplicable: function (a) {
return a.data.models.length === 1 && ValidationReport.isApplicable(a.data.models[0]) && Model.isFromNmr(a.data.models[0]);
},
params: function () { return StructureRepresentationPresetProvider.CommonParams; },
apply: function (ref, params, plugin) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var structureCell, structure, colorTheme;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
structure = (_a = structureCell === null || structureCell === void 0 ? void 0 : structureCell.obj) === null || _a === void 0 ? void 0 : _a.data;
if (!structureCell || !structure)
return [2 /*return*/, {}];
return [4 /*yield*/, plugin.runTask(Task.create('Validation Report', function (runtime) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, ValidationReportProvider.attach({ runtime: runtime, assetManager: plugin.managers.asset }, structure.models[0])];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); }))];
case 1:
_b.sent();
colorTheme = RandomCoilIndexColorThemeProvider.name;
return [4 /*yield*/, PresetStructureRepresentations.auto.apply(ref, __assign(__assign({}, params), { theme: { globalName: colorTheme, focus: { name: colorTheme } } }), plugin)];
case 2: return [2 /*return*/, _b.sent()];
}
});
});
}
});
//# sourceMappingURL=behavior.js.map