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

Proteopedia wrapper conservation coloring

parent 2a7066f2
No related branches found
No related tags found
No related merge requests found
...@@ -5,26 +5,84 @@ ...@@ -5,26 +5,84 @@
*/ */
import { CustomElementProperty } from 'mol-model-props/common/custom-element-property'; import { CustomElementProperty } from 'mol-model-props/common/custom-element-property';
import { Model, ElementIndex } from 'mol-model/structure'; import { Model, ElementIndex, ResidueIndex } from 'mol-model/structure';
import { Color } from 'mol-util/color'; import { Color } from 'mol-util/color';
export const StripedResidues = CustomElementProperty.create<number>({ // export const StripedResidues = CustomElementProperty.create<number>({
// isStatic: true,
// name: 'basic-wrapper-residue-striping',
// display: 'Residue Stripes',
// getData(model: Model) {
// const map = new Map<ElementIndex, number>();
// const residueIndex = model.atomicHierarchy.residueAtomSegments.index;
// for (let i = 0, _i = model.atomicHierarchy.atoms._rowCount; i < _i; i++) {
// map.set(i as ElementIndex, residueIndex[i] % 2);
// }
// return map;
// },
// coloring: {
// getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff) },
// defaultColor: Color(0x777777)
// },
// format(e) {
// return e === 0 ? 'Odd stripe' : 'Even stripe'
// }
// });
const EvolutionaryConservationPalette: Color[] = [
[255, 255, 150], // 9
[160, 37, 96],
[240, 125, 171],
[250, 201, 222],
[252, 237, 244],
[255, 255, 255],
[234, 255, 255],
[215, 255, 255],
[140, 255, 255],
[16, 200, 209] // 1
].reverse().map(([r, g, b]) => Color.fromRgb(r, g, b));
export const EvolutionaryConservation = CustomElementProperty.create<number>({
isStatic: true, isStatic: true,
name: 'basic-wrapper-residue-striping', name: 'proteopedia-wrapper-evolutionary-conservation',
display: 'Residue Stripes', display: 'Evolutionary Conservation',
getData(model: Model) { async getData(model: Model) {
const id = model.label.toLowerCase();
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await req.json();
const annotations = (json && json.residueAnnotations) || [];
const conservationMap = new Map<string, number>();
for (const e of annotations) {
for (const r of e.ids) {
conservationMap.set(r, e.annotation);
}
}
const map = new Map<ElementIndex, number>(); const map = new Map<ElementIndex, number>();
const residueIndex = model.atomicHierarchy.residueAtomSegments.index;
for (let i = 0, _i = model.atomicHierarchy.atoms._rowCount; i < _i; i++) { const { _rowCount: residueCount } = model.atomicHierarchy.residues;
map.set(i as ElementIndex, residueIndex[i] % 2); const { offsets: residueOffsets } = model.atomicHierarchy.residueAtomSegments;
const chainIndex = model.atomicHierarchy.chainAtomSegments.index;
for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) {
const cI = chainIndex[residueOffsets[rI]];
const key = `${model.atomicHierarchy.chains.auth_asym_id.value(cI)} ${model.atomicHierarchy.residues.auth_seq_id.value(rI)}`;
if (!conservationMap.has(key)) continue;
const ann = conservationMap.get(key)!;
for (let aI = residueOffsets[rI]; aI < residueOffsets[aI + 1]; aI++) {
map.set(aI, ann);
}
} }
return map; return map;
}, },
coloring: { coloring: {
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff) }, getColor(e) { return EvolutionaryConservationPalette[(e - 1) || 0]; },
defaultColor: Color(0x777777) defaultColor: Color(0x999999)
}, },
format(e) { format(e) {
return e === 0 ? 'Odd stripe' : 'Even stripe' return e ? `Evolutionary Conservation ${e}` : void 0;
} }
}) });
\ No newline at end of file \ No newline at end of file
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
function $(id) { return document.getElementById(id); } function $(id) { return document.getElementById(id); }
var pdbId = '3usb', assemblyId= 'preferred'; var pdbId = '2c1z', assemblyId= 'preferred';
var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif'; var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
var format = 'cif'; var format = 'cif';
...@@ -107,9 +107,11 @@ ...@@ -107,9 +107,11 @@
addControl('Play Loop', () => MolStarProteopediaWrapper.animate.modelIndex.loop()); addControl('Play Loop', () => MolStarProteopediaWrapper.animate.modelIndex.loop());
addControl('Stop', () => MolStarProteopediaWrapper.animate.modelIndex.stop()); addControl('Stop', () => MolStarProteopediaWrapper.animate.modelIndex.stop());
addSeparator();
addHeader('Misc'); addHeader('Misc');
addControl('Apply Stripes', () => MolStarProteopediaWrapper.coloring.applyStripes()); addControl('Apply Evo Cons', () => MolStarProteopediaWrapper.coloring.evolutionaryConservation());
addControl('Default Visuals', () => MolStarProteopediaWrapper.updateStyle());
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
......
...@@ -14,7 +14,7 @@ import { Color } from 'mol-util/color'; ...@@ -14,7 +14,7 @@ import { Color } from 'mol-util/color';
import { PluginStateObject as PSO, PluginStateObject } from 'mol-plugin/state/objects'; import { PluginStateObject as PSO, PluginStateObject } from 'mol-plugin/state/objects';
import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in'; import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in';
import { StateBuilder, StateObject } from 'mol-state'; import { StateBuilder, StateObject } from 'mol-state';
import { StripedResidues } from './annotation'; import { EvolutionaryConservation } from './annotation';
import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo } from './helpers'; import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo } from './helpers';
import { RxEventHelper } from 'mol-util/rx-event-helper'; import { RxEventHelper } from 'mol-util/rx-event-helper';
require('mol-plugin/skin/light.scss') require('mol-plugin/skin/light.scss')
...@@ -39,9 +39,9 @@ class MolStarProteopediaWrapper { ...@@ -39,9 +39,9 @@ class MolStarProteopediaWrapper {
} }
}); });
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!); this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.Descriptor.name, EvolutionaryConservation.colorTheme!);
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider); this.plugin.lociLabels.addProvider(EvolutionaryConservation.labelProvider);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider); this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider);
} }
get state() { get state() {
...@@ -65,7 +65,7 @@ class MolStarProteopediaWrapper { ...@@ -65,7 +65,7 @@ class MolStarProteopediaWrapper {
const model = this.state.build().to('model'); const model = this.state.build().to('model');
return model return model
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', props: { isGhost: false } }) .apply(StateTransforms.Model.CustomModelProperties, { properties: [EvolutionaryConservation.Descriptor.name] }, { ref: 'props', props: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' }); .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
} }
...@@ -97,7 +97,7 @@ class MolStarProteopediaWrapper { ...@@ -97,7 +97,7 @@ class MolStarProteopediaWrapper {
return root; return root;
} }
private getObj<T extends StateObject>(ref: string) { private getObj<T extends StateObject>(ref: string): T['data'] {
const state = this.state; const state = this.state;
const cell = state.select(ref)[0]; const cell = state.select(ref)[0];
if (!cell || !cell.obj) return void 0; if (!cell || !cell.obj) return void 0;
...@@ -105,10 +105,10 @@ class MolStarProteopediaWrapper { ...@@ -105,10 +105,10 @@ class MolStarProteopediaWrapper {
} }
private async doInfo(checkPreferredAssembly: boolean) { private async doInfo(checkPreferredAssembly: boolean) {
const s = this.getObj<PluginStateObject.Molecule.Model>('model'); const model = this.getObj<PluginStateObject.Molecule.Model>('model');
if (!s) return; if (!model) return;
const info = await ModelInfo.get(this.plugin, s, checkPreferredAssembly) const info = await ModelInfo.get(this.plugin, model, checkPreferredAssembly)
this.events.modelInfo.next(info); this.events.modelInfo.next(info);
return info; return info;
} }
...@@ -177,18 +177,18 @@ class MolStarProteopediaWrapper { ...@@ -177,18 +177,18 @@ class MolStarProteopediaWrapper {
} }
coloring = { coloring = {
applyStripes: async () => { evolutionaryConservation: async () => {
await this.updateStyle({ sequence: { kind: 'molecular-surface' } }); await this.updateStyle({ sequence: { kind: 'molecular-surface' } });
const state = this.state; const state = this.state;
const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D)); //const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D));
const tree = state.build(); const tree = state.build();
const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues }; const colorTheme = { name: EvolutionaryConservation.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.Descriptor.name).defaultValues };
for (const v of visuals) { tree.to('sequence-visual').update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
tree.to(v.transform.ref).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme })); //for (const v of visuals) {
} //}
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree }); await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
} }
......
...@@ -26,7 +26,7 @@ namespace CustomElementProperty { ...@@ -26,7 +26,7 @@ namespace CustomElementProperty {
display: string, display: string,
attachableTo?: (model: Model) => boolean, attachableTo?: (model: Model) => boolean,
getData(model: Model): Map<ElementIndex, T> | Promise<Map<ElementIndex, T>>, getData(model: Model): Map<ElementIndex, T> | Promise<Map<ElementIndex, T>>,
format?(e: T): string, format?(e: T): string | undefined,
coloring?: { coloring?: {
getColor: (e: T) => Color, getColor: (e: T) => Color,
defaultColor: Color defaultColor: Color
...@@ -43,17 +43,24 @@ namespace CustomElementProperty { ...@@ -43,17 +43,24 @@ namespace CustomElementProperty {
function attach(model: Model) { function attach(model: Model) {
return Task.create(`Attach ${params.display}`, async () => { return Task.create(`Attach ${params.display}`, async () => {
const data = await params.getData(model); try {
if (model.customProperties.has(Descriptor)) return true;
if (params.isStatic) { const data = await params.getData(model);
model._staticPropertyData[name] = data;
} else { if (params.isStatic) {
model._dynamicPropertyData[name] = data; model._staticPropertyData[name] = data;
} } else {
model._dynamicPropertyData[name] = data;
}
model.customProperties.add(Descriptor); model.customProperties.add(Descriptor);
return true; return true;
} catch (e) {
console.warn('Attach Property', e);
return false;
}
}) })
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment