Skip to content
Snippets Groups Projects
Commit 2a7066f2 authored by David Sehnal's avatar David Sehnal
Browse files

work on Proteopedia wrapper

parent 2852a335
Branches
Tags
No related merge requests found
......@@ -4,13 +4,83 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { ResidueIndex } from 'mol-model/structure';
import { ResidueIndex, Model } from 'mol-model/structure';
import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry';
import { BuiltInColorThemeName } from 'mol-theme/color';
import { AminoAcidNames } from 'mol-model/structure/model/types';
import { PluginContext } from 'mol-plugin/context';
export interface StructureInfo {
ligands: { name: string, indices: ResidueIndex[] }[],
assemblies: { id: string, description: string, isPreferred: boolean }[]
export interface ModelInfo {
hetResidues: { name: string, indices: ResidueIndex[] }[],
assemblies: { id: string, details: string, isPreferred: boolean }[],
preferredAssemblyId: string | undefined
}
export namespace ModelInfo {
async function getPreferredAssembly(ctx: PluginContext, model: Model) {
if (model.label.length <= 3) return void 0;
try {
const id = model.label.toLowerCase();
const src = await ctx.runTask(ctx.fetch(`https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${id}`)) as string;
const json = JSON.parse(src);
const data = json && json[id];
console.log(data);
const assemblies = data[0] && data[0].assemblies;
if (!assemblies || !assemblies.length) return void 0;
for (const asm of assemblies) {
if (asm.preferred) {
return asm.assembly_id;
}
}
return void 0;
} catch (e) {
console.warn('getPreferredAssembly', e);
}
}
export async function get(ctx: PluginContext, model: Model, checkPreferred: boolean): Promise<ModelInfo> {
const { _rowCount: residueCount } = model.atomicHierarchy.residues;
const { offsets: residueOffsets } = model.atomicHierarchy.residueAtomSegments;
const chainIndex = model.atomicHierarchy.chainAtomSegments.index;
// const resn = SP.residue.label_comp_id, entType = SP.entity.type;
const pref = checkPreferred
? getPreferredAssembly(ctx, model)
: void 0;
const hetResidues: ModelInfo['hetResidues'] = [];
const hetMap = new Map<string, ModelInfo['hetResidues'][0]>();
for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) {
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
if (AminoAcidNames.has(comp_id)) continue;
const mod_parent = model.properties.modifiedResidues.parentId.get(comp_id);
if (mod_parent && AminoAcidNames.has(mod_parent)) continue;
const cI = chainIndex[residueOffsets[rI]];
const eI = model.atomicHierarchy.index.getEntityFromChain(cI);
if (model.entities.data.type.value(eI) === 'water') continue;
let lig = hetMap.get(comp_id);
if (!lig) {
lig = { name: comp_id, indices: [] };
hetResidues.push(lig);
hetMap.set(comp_id, lig);
}
lig.indices.push(rI);
}
const preferredAssemblyId = await pref;
return {
hetResidues: hetResidues,
assemblies: model.symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })),
preferredAssemblyId
};
}
}
export type SupportedFormats = 'cif' | 'pdb'
......
......@@ -61,7 +61,7 @@
function $(id) { return document.getElementById(id); }
var pdbId = '1grm', assemblyId= '1';
var pdbId = '3usb', assemblyId= 'preferred';
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
var format = 'cif';
......@@ -81,6 +81,10 @@
MolStarProteopediaWrapper.load({ url: url, format: format, assemblyId: assemblyId });
MolStarProteopediaWrapper.toggleSpin();
MolStarProteopediaWrapper.events.modelInfo.subscribe(function (info) {
console.log('Model Info', info);
});
addControl('Load Asym Unit', () => MolStarProteopediaWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => MolStarProteopediaWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
......
......@@ -13,14 +13,21 @@ import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/re
import { Color } from 'mol-util/color';
import { PluginStateObject as PSO, PluginStateObject } from 'mol-plugin/state/objects';
import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in';
import { StateBuilder } from 'mol-state';
import { StateBuilder, StateObject } from 'mol-state';
import { StripedResidues } from './annotation';
import { LoadParams, SupportedFormats, RepresentationStyle } from './helpers';
import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo } from './helpers';
import { RxEventHelper } from 'mol-util/rx-event-helper';
require('mol-plugin/skin/light.scss')
class MolStarProteopediaWrapper {
static VERSION_MAJOR = 1;
private _ev = RxEventHelper.create();
readonly events = {
modelInfo: this._ev<ModelInfo>()
};
plugin: PluginContext;
init(target: string | HTMLElement) {
......@@ -45,24 +52,28 @@ class MolStarProteopediaWrapper {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }, { ref: 'model' });
}
private structure(assemblyId: string) {
const model = this.state.build().to('model');
return model
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', props: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
}
private visual(ref: string, style?: RepresentationStyle) {
const state = this.state;
const cell = state.select(ref)[0];
if (!cell || !cell.obj) return void 0;
const structure = (cell.obj as PluginStateObject.Molecule.Structure).data;
const structure = this.getObj<PluginStateObject.Molecule.Structure>(ref);
if (!structure) return;
const root = state.build().to(ref);
const root = this.state.build().to(ref);
root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
......@@ -86,6 +97,26 @@ class MolStarProteopediaWrapper {
return root;
}
private getObj<T extends StateObject>(ref: string) {
const state = this.state;
const cell = state.select(ref)[0];
if (!cell || !cell.obj) return void 0;
return (cell.obj as T).data;
}
private async doInfo(checkPreferredAssembly: boolean) {
const s = this.getObj<PluginStateObject.Molecule.Model>('model');
if (!s) return;
const info = await ModelInfo.get(this.plugin, s, checkPreferredAssembly)
this.events.modelInfo.next(info);
return info;
}
private applyState(tree: StateBuilder) {
return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
}
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = '', representationStyle }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
......@@ -98,17 +129,19 @@ class MolStarProteopediaWrapper {
if (state.select('asm').length > 0) loadType = 'update';
}
let tree: StateBuilder.Root;
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
tree = state.build();
this.parse(this.download(tree.toRoot(), url), format, assemblyId);
const modelTree = this.model(this.download(state.build().toRoot(), url), format, assemblyId);
await this.applyState(modelTree);
const info = await this.doInfo(true);
const structureTree = this.structure((assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId);
await this.applyState(structureTree);
} else {
tree = state.build();
const tree = state.build();
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
await this.applyState(tree);
}
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
await this.updateStyle(representationStyle);
this.loadedParams = { url, format, assemblyId };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment