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

element custom properties helper

parent 5e8ad436
No related branches found
No related tags found
No related merge requests found
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { CustomElementProperty } from 'mol-model-props/common/custom-element-property';
import { Model, ElementIndex } from 'mol-model/structure';
import { Color } from 'mol-util/color';
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'
}
})
\ No newline at end of file
...@@ -100,6 +100,10 @@ ...@@ -100,6 +100,10 @@
addControl('Play Loop', () => BasicMolStarWrapper.animate.modelIndex.loop()); addControl('Play Loop', () => BasicMolStarWrapper.animate.modelIndex.loop());
addControl('Stop', () => BasicMolStarWrapper.animate.modelIndex.stop()); addControl('Stop', () => BasicMolStarWrapper.animate.modelIndex.stop());
addHeader('Misc');
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
function addControl(label, action) { function addControl(label, action) {
......
...@@ -11,9 +11,10 @@ import { PluginCommands } from 'mol-plugin/command'; ...@@ -11,9 +11,10 @@ import { PluginCommands } from 'mol-plugin/command';
import { StateTransforms } from 'mol-plugin/state/transforms'; import { StateTransforms } from 'mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation'; import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation';
import { Color } from 'mol-util/color'; import { Color } from 'mol-util/color';
import { PluginStateObject as PSO } 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 } from 'mol-state'; import { StateBuilder } from 'mol-state';
import { StripedResidues } from './coloring';
require('mol-plugin/skin/light.scss') require('mol-plugin/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb' type SupportedFormats = 'cif' | 'pdb'
...@@ -30,6 +31,10 @@ class BasicWrapper { ...@@ -30,6 +31,10 @@ class BasicWrapper {
showControls: false showControls: false
} }
}); });
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!);
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider);
} }
private download(b: StateBuilder.To<PSO.Root>, url: string) { private download(b: StateBuilder.To<PSO.Root>, url: string) {
...@@ -43,6 +48,7 @@ class BasicWrapper { ...@@ -43,6 +48,7 @@ class BasicWrapper {
return parsed return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }) .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.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' });
} }
...@@ -110,6 +116,22 @@ class BasicWrapper { ...@@ -110,6 +116,22 @@ class BasicWrapper {
stop: () => this.plugin.state.animation.stop() stop: () => this.plugin.state.animation.stop()
} }
} }
coloring = {
applyStripes: async () => {
const state = this.plugin.state.dataState;
const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D));
const tree = state.build();
const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues };
for (const v of visuals) {
tree.to(v.transform.ref).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
}
}
} }
(window as any).BasicMolStarWrapper = new BasicWrapper(); (window as any).BasicMolStarWrapper = new BasicWrapper();
\ No newline at end of file
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
...@@ -9,7 +9,7 @@ import { StructureElement } from 'mol-model/structure/structure'; ...@@ -9,7 +9,7 @@ import { StructureElement } from 'mol-model/structure/structure';
import { Location } from 'mol-model/location'; import { Location } from 'mol-model/location';
import { CustomPropertyRegistry } from './custom-property-registry'; import { CustomPropertyRegistry } from './custom-property-registry';
import { Task } from 'mol-task'; import { Task } from 'mol-task';
import { ThemeDataContext } from 'mol-theme/theme'; import { ThemeDataContext, ThemeProvider } from 'mol-theme/theme';
import { ColorTheme, LocationColor } from 'mol-theme/color'; import { ColorTheme, LocationColor } from 'mol-theme/color';
import { Color } from 'mol-util/color'; import { Color } from 'mol-util/color';
import { TableLegend } from 'mol-util/color/tables'; import { TableLegend } from 'mol-util/color/tables';
...@@ -19,12 +19,12 @@ import { OrderedSet } from 'mol-data/int'; ...@@ -19,12 +19,12 @@ import { OrderedSet } from 'mol-data/int';
export { CustomElementProperty }; export { CustomElementProperty };
namespace CustomElementProperty { namespace CustomElementProperty {
export interface CreateParams<S, T> { export interface CreateParams<T> {
isStatic: boolean, isStatic: boolean,
name: string, name: string,
autoAttach?: boolean, autoAttach?: boolean,
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,
coloring?: { coloring?: {
...@@ -33,7 +33,7 @@ namespace CustomElementProperty { ...@@ -33,7 +33,7 @@ namespace CustomElementProperty {
} }
} }
export function create<S, T>(params: CreateParams<S, T>) { export function create<T>(params: CreateParams<T>) {
const name = params.name; const name = params.name;
const Descriptor = ModelPropertyDescriptor({ const Descriptor = ModelPropertyDescriptor({
...@@ -51,6 +51,8 @@ namespace CustomElementProperty { ...@@ -51,6 +51,8 @@ namespace CustomElementProperty {
model._dynamicPropertyData[name] = data; model._dynamicPropertyData[name] = data;
} }
model.customProperties.add(Descriptor);
return true; return true;
}) })
} }
...@@ -58,7 +60,7 @@ namespace CustomElementProperty { ...@@ -58,7 +60,7 @@ namespace CustomElementProperty {
function getStatic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); } function getStatic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); }
function getDynamic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); } function getDynamic(e: StructureElement) { return e.unit.model._staticPropertyData[name].get(e.element); }
const provider: CustomPropertyRegistry.Provider = { const propertyProvider: CustomPropertyRegistry.Provider = {
option: [name, params.display], option: [name, params.display],
descriptor: Descriptor, descriptor: Descriptor,
defaultSelected: !!params.autoAttach, defaultSelected: !!params.autoAttach,
...@@ -68,12 +70,14 @@ namespace CustomElementProperty { ...@@ -68,12 +70,14 @@ namespace CustomElementProperty {
const get = params.isStatic ? getStatic : getDynamic; const get = params.isStatic ? getStatic : getDynamic;
function has(model: Model) { return model.customProperties.has(Descriptor); }
function Coloring(ctx: ThemeDataContext, props: {}): ColorTheme<{}> { function Coloring(ctx: ThemeDataContext, props: {}): ColorTheme<{}> {
let color: LocationColor; let color: LocationColor;
const getColor = params.coloring!.getColor; const getColor = params.coloring!.getColor;
const defaultColor = params.coloring!.defaultColor; const defaultColor = params.coloring!.defaultColor;
if (ctx.structure && !ctx.structure.isEmpty && ctx.structure.models[0].customProperties.has(Descriptor)) { if (ctx.structure && !ctx.structure.isEmpty && has(ctx.structure.models[0])) {
color = (location: Location) => { color = (location: Location) => {
if (StructureElement.isLocation(location)) { if (StructureElement.isLocation(location)) {
const e = get(location); const e = get(location);
...@@ -95,9 +99,18 @@ namespace CustomElementProperty { ...@@ -95,9 +99,18 @@ namespace CustomElementProperty {
}; };
} }
const colorTheme: ThemeProvider<ColorTheme<{}>, {}> = {
label: params.display,
factory: Coloring,
getParams: () => ({}),
defaultValues: {},
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && !ctx.structure.isEmpty && has(ctx.structure.models[0])
}
function LabelProvider(loci: Loci): string | undefined { function LabelProvider(loci: Loci): string | undefined {
if (loci.kind === 'element-loci') { if (loci.kind === 'element-loci') {
const e = loci.elements[0]; const e = loci.elements[0];
if (!has(e.unit.model)) return void 0;
return params.format!(get(StructureElement.create(e.unit, e.unit.elements[OrderedSet.getAt(e.indices, 0)]))); return params.format!(get(StructureElement.create(e.unit, e.unit.elements[OrderedSet.getAt(e.indices, 0)])));
} }
return void 0; return void 0;
...@@ -107,8 +120,8 @@ namespace CustomElementProperty { ...@@ -107,8 +120,8 @@ namespace CustomElementProperty {
Descriptor, Descriptor,
attach, attach,
get, get,
provider, propertyProvider,
colorTheme: params.coloring ? Coloring : void 0, colorTheme: params.coloring ? colorTheme : void 0,
labelProvider: params.format ? LabelProvider : ((loci: Loci) => void 0) labelProvider: params.format ? LabelProvider : ((loci: Loci) => void 0)
}; };
} }
......
...@@ -97,6 +97,14 @@ namespace StateSelection { ...@@ -97,6 +97,14 @@ namespace StateSelection {
}); });
} }
export function ofType(type: StateObject.Ctor) {
return build(() => state => {
const ctx = { ret: [] as StateObjectCell[], cells: state.cells, type: type.type };
StateTree.doPreOrder(state.tree, state.tree.root, ctx, _findOfType);
return ctx.ret;
});
}
function _findRootsOfType(n: StateTransform, _: any, s: { type: StateObject.Type, roots: StateObjectCell[], cells: State.Cells }) { function _findRootsOfType(n: StateTransform, _: any, s: { type: StateObject.Type, roots: StateObjectCell[], cells: State.Cells }) {
const cell = s.cells.get(n.ref); const cell = s.cells.get(n.ref);
if (cell && cell.obj && cell.obj.type === s.type) { if (cell && cell.obj && cell.obj.type === s.type) {
...@@ -105,6 +113,14 @@ namespace StateSelection { ...@@ -105,6 +113,14 @@ namespace StateSelection {
} }
return true; return true;
} }
function _findOfType(n: StateTransform, _: any, s: { type: StateObject.Type, ret: StateObjectCell[], cells: State.Cells }) {
const cell = s.cells.get(n.ref);
if (cell && cell.obj && cell.obj.type === s.type) {
s.ret.push(cell);
}
return true;
}
} }
registerModifier('flatMap', flatMap); registerModifier('flatMap', flatMap);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment