pdbe-molstar
Version:
Molstar implementation for PDBe
158 lines (157 loc) • 12.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AfSuperpositionControls = exports.AlphafoldSuperpositionParams = exports.AlphafoldSuperpositionControls = exports.AlphafoldPaeControls = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const d3_axis_1 = require("d3-axis");
const d3_scale_1 = require("d3-scale");
const d3_selection_1 = require("d3-selection");
const base_1 = require("molstar/lib/mol-plugin-ui/base");
const common_1 = require("molstar/lib/mol-plugin-ui/controls/common");
const icons_1 = require("molstar/lib/mol-plugin-ui/controls/icons");
const parameters_1 = require("molstar/lib/mol-plugin-ui/controls/parameters");
const param_definition_1 = require("molstar/lib/mol-util/param-definition");
const react_1 = tslib_1.__importDefault(require("react"));
const plugin_custom_state_1 = require("../plugin-custom-state");
const superposition_1 = require("../superposition");
const icons_2 = require("./icons");
class AlphafoldPaeControls extends base_1.CollapsableControls {
defaultState() {
return {
isCollapsed: false,
header: 'AlphaFold PAE',
brand: { accent: 'gray', svg: icons_1.SuperpositionSvg },
isHidden: true,
};
}
constructor(props, context) {
super(props, context);
this.axisBoxRef = react_1.default.createRef();
}
componentDidMount() {
this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => {
const superpositionState = (0, plugin_custom_state_1.PluginCustomState)(this.plugin).superpositionState;
if (superpositionState && superpositionState.alphafold.ref && superpositionState.alphafold.apiData.pae && superpositionState.alphafold.apiData.pae !== '' && superpositionState.alphafold.apiData.pae !== '') {
this.setState({ isHidden: false });
const domainMax = superpositionState.alphafold.apiData.length;
const x = (0, d3_scale_1.scaleLinear)().domain([0, domainMax]).range([0, 200]);
const xAxis = (0, d3_axis_1.axisBottom)(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0);
const yAxis = (0, d3_axis_1.axisLeft)(x).ticks(6).tickFormat(this.formatTicks).tickSizeOuter(0);
const axisContainer = (0, d3_selection_1.select)(this.axisBoxRef.current);
axisContainer.append('svg:svg')
.attr('width', 220)
.attr('height', 30)
.attr('class', 'pae-x-axis')
.style('z-index', '1')
.style('position', 'absolute')
.attr('transform', `translate(-93,202)`)
.append('g')
.attr('transform', `translate(6,0)`)
.call(xAxis);
axisContainer.append('svg:svg')
.attr('width', 50)
.attr('height', 220)
.attr('class', 'pae-y-axis')
.style('z-index', '1')
.style('position', 'absolute')
.attr('transform', `translate(-123,0)`)
.append('g')
.attr('transform', `translate(36,4)`)
.call(yAxis);
}
});
}
formatTicks(d) {
return d > 999 ? d / 1000 + 'k' : d;
}
renderControls() {
const superpositionState = (0, plugin_custom_state_1.PluginCustomState)(this.plugin).superpositionState;
if (!superpositionState || !superpositionState.alphafold)
return null;
const errorScale = [0, 5, 10, 15, 20, 25, 30];
return (0, jsx_runtime_1.jsxs)("div", { className: 'msp-flex-row', style: { height: 'auto', textAlign: 'center', justifyContent: 'center', padding: '15px 0', position: 'relative', fontSize: '12px' }, children: [(0, jsx_runtime_1.jsx)("div", { ref: this.axisBoxRef, className: 'pae-axis-box', style: { position: 'absolute', width: '100%', height: '100%' } }), (0, jsx_runtime_1.jsx)("span", { style: { transform: 'rotate(270deg)', position: 'absolute', transformOrigin: '0 0', left: '10px', top: '165px', fontWeight: 500 }, children: "Aligned residue" }), (0, jsx_runtime_1.jsxs)("div", { className: 'msp-flex-row', style: { height: 'auto', flexDirection: 'column' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { width: '200px', height: '200px', border: '1px solid #6a635a', margin: '2px 0 25px 25px', position: 'relative' }, children: (0, jsx_runtime_1.jsx)("img", { style: { width: '100%', height: '100%', position: 'absolute', left: 0, top: 0 }, src: `${superpositionState.alphafold.apiData.pae}`, alt: "PAE" }) }), (0, jsx_runtime_1.jsx)("div", { style: { textAlign: 'center', paddingLeft: '30px', marginBottom: '20px', fontWeight: 500 }, children: "Scored residue" }), (0, jsx_runtime_1.jsx)("img", { style: { width: '200px', height: '10px', border: '1px solid #6a635a', margin: '2px 0 25px 25px', transform: 'rotate(180deg)' }, src: 'https://alphafold.ebi.ac.uk/assets/img/horizontal_colorbar.png', alt: "PAE Scale" }), (0, jsx_runtime_1.jsx)("ul", { style: { listStyleType: 'none', fontWeight: 500, margin: 0, display: 'inline-block', position: 'absolute', top: '292px', marginLeft: '24px' }, children: errorScale.map((errValue) => (0, jsx_runtime_1.jsx)("li", { style: { float: 'left', marginRight: '18px' }, children: errValue }, errValue)) }), (0, jsx_runtime_1.jsx)("div", { style: { textAlign: 'center', paddingLeft: '20px', fontWeight: 500 }, children: "Expected position error (\u00C5ngstr\u00F6ms)" })] })] });
}
}
exports.AlphafoldPaeControls = AlphafoldPaeControls;
class AlphafoldSuperpositionControls extends base_1.CollapsableControls {
defaultState() {
return {
isCollapsed: false,
header: 'AlphaFold Superposition',
brand: { accent: 'gray', svg: icons_1.SuperpositionSvg },
isHidden: true,
};
}
componentDidMount() {
this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, sel => {
const superpositionState = (0, plugin_custom_state_1.PluginCustomState)(this.plugin).superpositionState;
if ((superpositionState === null || superpositionState === void 0 ? void 0 : superpositionState.alphafold.apiData.cif) && (superpositionState === null || superpositionState === void 0 ? void 0 : superpositionState.alphafold.apiData.bcif)) {
this.setState({ isHidden: false });
}
});
}
rmsdTable() {
const spData = (0, plugin_custom_state_1.PluginCustomState)(this.plugin).superpositionState;
if (!spData)
throw new Error('customState.superpositionState has not been initialized');
const { activeSegment } = spData;
const { rmsds } = spData.alphafold;
return (0, jsx_runtime_1.jsxs)("div", { className: 'msp-control-offset', children: [(rmsds.length === 0 || !rmsds[activeSegment - 1]) && (0, jsx_runtime_1.jsx)("div", { className: 'msp-flex-row', style: { padding: '5px 0 0 10px' }, children: (0, jsx_runtime_1.jsx)("strong", { children: "No overlap found!" }) }), rmsds[activeSegment - 1] && (0, jsx_runtime_1.jsxs)("div", { className: 'msp-flex-row', children: [(0, jsx_runtime_1.jsx)("div", { style: { width: '40%', borderRight: '1px solid rgb(213 206 196)', padding: '5px 0 0 5px' }, children: (0, jsx_runtime_1.jsx)("strong", { children: "Entry" }) }), (0, jsx_runtime_1.jsx)("div", { style: { padding: '5px 0 0 5px' }, children: (0, jsx_runtime_1.jsx)("strong", { children: "RMSD (\u212B)" }) })] }), rmsds[activeSegment - 1] && rmsds[activeSegment - 1].map((d) => {
const details = d.split(':');
return details[1] !== '-' ? (0, jsx_runtime_1.jsxs)("div", { className: 'msp-flex-row', children: [(0, jsx_runtime_1.jsx)("div", { className: 'msp-control-row-label', style: { width: '40%', borderRight: '1px solid rgb(213 206 196)', padding: '5px 0 0 5px' }, children: details[0] }), (0, jsx_runtime_1.jsx)("div", { style: { padding: '5px 0 0 5px' }, children: details[1] })] }, d) : null;
})] });
}
renderControls() {
const superpositionState = (0, plugin_custom_state_1.PluginCustomState)(this.plugin).superpositionState;
if (!superpositionState)
throw new Error('customState.superpositionState has not been initialized');
return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [superpositionState.alphafold.ref !== '' && this.rmsdTable(), superpositionState.alphafold.ref === '' && (0, jsx_runtime_1.jsx)(AfSuperpositionControls, {})] });
}
}
exports.AlphafoldSuperpositionControls = AlphafoldSuperpositionControls;
exports.AlphafoldSuperpositionParams = {
// alignSequences: PD.Boolean(true, { isEssential: true, description: 'For Chain-based 3D superposition, perform a sequence alignment and use the aligned residue pairs to guide the 3D superposition.' }),
traceOnly: param_definition_1.ParamDefinition.Boolean(true, { description: 'For Chain- and Uniprot-based 3D superposition, base superposition only on CA (and equivalent) atoms.' }),
};
const DefaultAlphafoldSuperpositionOptions = param_definition_1.ParamDefinition.getDefaultValues(exports.AlphafoldSuperpositionParams);
class AfSuperpositionControls extends base_1.PurePluginUIComponent {
constructor() {
super(...arguments);
this.state = {
isBusy: false,
canUseDb: true,
action: undefined,
options: DefaultAlphafoldSuperpositionOptions,
};
this.superposeDb = () => tslib_1.__awaiter(this, void 0, void 0, function* () {
this.setState({ isBusy: true });
const spData = this.customState.superpositionState;
if (!spData)
throw new Error('customState.superpositionState has not been initialized');
spData.alphafold.traceOnly = this.state.options.traceOnly;
(0, superposition_1.superposeAf)(this.plugin, this.state.options.traceOnly);
});
this.toggleOptions = () => this.setState({ action: this.state.action === 'options' ? undefined : 'options' });
this.setOptions = (values) => {
this.setState({ options: values });
};
}
componentDidMount() {
this.subscribe(this.plugin.behaviors.state.isBusy, v => {
this.setState({ isBusy: v });
});
}
get selection() {
return this.plugin.managers.structure.selection;
}
get customState() {
return (0, plugin_custom_state_1.PluginCustomState)(this.plugin);
}
superposeByDbMapping() {
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(common_1.Button, { icon: icons_1.SuperposeChainsSvg, title: 'Superpose AlphaFold structure using intersection of residues from SIFTS UNIPROT mapping.', className: 'msp-btn msp-btn-block', onClick: this.superposeDb, style: { marginTop: '1px', textAlign: 'left' }, disabled: this.state.isBusy, children: "Load AlphaFold structure" }) });
}
render() {
return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: { backgroundColor: '#dce54e', fontWeight: 500, padding: '5px 12px' }, children: "New Feature!" }), (0, jsx_runtime_1.jsx)("div", { className: 'msp-help-text', style: { margin: '2px 0' }, children: (0, jsx_runtime_1.jsxs)("div", { className: 'msp-help-description', children: [(0, jsx_runtime_1.jsx)(icons_1.Icon, { svg: icons_2.InfoIconSvg, inline: true }), "Load and superpose AlphaFold structure against representative chains."] }) }), (0, jsx_runtime_1.jsxs)("div", { className: 'msp-flex-row', children: [this.state.canUseDb && this.superposeByDbMapping(), (0, jsx_runtime_1.jsx)(common_1.ToggleButton, { icon: icons_1.TuneSvg, label: '', title: 'Options', toggle: this.toggleOptions, isSelected: this.state.action === 'options', disabled: this.state.isBusy, style: { flex: '0 0 40px', padding: 0 } })] }), this.state.action === 'options' && (0, jsx_runtime_1.jsx)("div", { className: 'msp-control-offset', children: (0, jsx_runtime_1.jsx)(parameters_1.ParameterControls, { params: exports.AlphafoldSuperpositionParams, values: this.state.options, onChangeValues: this.setOptions, isDisabled: this.state.isBusy }) })] });
}
}
exports.AfSuperpositionControls = AfSuperpositionControls;