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

mol-state: wip, automatic default params

parent 384f589c
No related branches found
No related tags found
No related merge requests found
...@@ -25,7 +25,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo ...@@ -25,7 +25,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
private provider: CustomPropertyRegistry.Provider = { private provider: CustomPropertyRegistry.Provider = {
option: [StructureQualityReport.Descriptor.name, 'PDBe Structure Quality Report'], option: [StructureQualityReport.Descriptor.name, 'PDBe Structure Quality Report'],
descriptor: StructureQualityReport.Descriptor, descriptor: StructureQualityReport.Descriptor,
defaultSelected: false, defaultSelected: this.params.autoAttach,
attachableTo: () => true, attachableTo: () => true,
attach: this.attach attach: this.attach
} }
......
...@@ -36,7 +36,7 @@ const DefaultSpec: PluginSpec = { ...@@ -36,7 +36,7 @@ const DefaultSpec: PluginSpec = {
PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci), PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider), PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }), PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }),
PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: false }) PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true })
] ]
} }
......
...@@ -4,25 +4,20 @@ ...@@ -4,25 +4,20 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { PluginContext } from 'mol-plugin/context';
import { StateTree, Transformer } from 'mol-state';
import { StateAction } from 'mol-state/action'; import { StateAction } from 'mol-state/action';
import { StateSelection } from 'mol-state/state/selection';
import { StateTreeBuilder } from 'mol-state/tree/builder';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { PluginStateObject } from '../objects'; import { PluginStateObject } from '../objects';
import { StateTransforms } from '../transforms'; import { StateTransforms } from '../transforms';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { StateSelection } from 'mol-state/state/selection';
import { CartoonParams } from 'mol-repr/structure/representation/cartoon';
import { BallAndStickParams } from 'mol-repr/structure/representation/ball-and-stick';
import { Download } from '../transforms/data'; import { Download } from '../transforms/data';
import { StateTree, Transformer } from 'mol-state'; import { StructureRepresentation3DHelpers } from '../transforms/representation';
import { StateTreeBuilder } from 'mol-state/tree/builder';
import { PolymerIdColorThemeParams } from 'mol-theme/color/polymer-id';
import { UniformSizeThemeParams } from 'mol-theme/size/uniform';
import { ElementSymbolColorThemeParams } from 'mol-theme/color/element-symbol';
import { PhysicalSizeThemeParams } from 'mol-theme/size/physical';
import { SpacefillParams } from 'mol-repr/structure/representation/spacefill';
// TODO: "structure parser provider" // TODO: "structure parser provider"
export { DownloadStructure } export { DownloadStructure };
type DownloadStructure = typeof DownloadStructure type DownloadStructure = typeof DownloadStructure
const DownloadStructure = StateAction.build({ const DownloadStructure = StateAction.build({
from: PluginStateObject.Root, from: PluginStateObject.Root,
...@@ -55,7 +50,7 @@ const DownloadStructure = StateAction.build({ ...@@ -55,7 +50,7 @@ const DownloadStructure = StateAction.build({
] ]
}) })
} }
})(({ params, state }) => { })(({ params, state }, ctx: PluginContext) => {
const b = state.build(); const b = state.build();
const src = params.source; const src = params.source;
let url: Transformer.Params<Download>; let url: Transformer.Params<Download>;
...@@ -77,69 +72,55 @@ const DownloadStructure = StateAction.build({ ...@@ -77,69 +72,55 @@ const DownloadStructure = StateAction.build({
} }
const data = b.toRoot().apply(StateTransforms.Data.Download, url); const data = b.toRoot().apply(StateTransforms.Data.Download, url);
return state.update(createStructureTree(data, params.source.params.supportProps)); return state.update(createStructureTree(ctx, data, params.source.params.supportProps));
}); });
export const OpenStructure = StateAction.build({ export const OpenStructure = StateAction.build({
display: { name: 'Open Structure', description: 'Load a structure from file and create its default Assembly and visual' }, display: { name: 'Open Structure', description: 'Load a structure from file and create its default Assembly and visual' },
from: PluginStateObject.Root, from: PluginStateObject.Root,
params: { file: PD.File({ accept: '.cif,.bcif' }) } params: { file: PD.File({ accept: '.cif,.bcif' }) }
})(({ params, state }) => { })(({ params, state }, ctx: PluginContext) => {
const b = state.build(); const b = state.build();
const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) }); const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) });
return state.update(createStructureTree(data, false)); return state.update(createStructureTree(ctx, data, false));
}); });
function createStructureTree(b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, supportProps: boolean): StateTree { function createStructureTree(ctx: PluginContext, b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, supportProps: boolean): StateTree {
let root = b let root = b
.apply(StateTransforms.Data.ParseCif) .apply(StateTransforms.Data.ParseCif)
.apply(StateTransforms.Model.TrajectoryFromMmCif, {}) .apply(StateTransforms.Model.TrajectoryFromMmCif)
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }); .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 });
if (supportProps) { if (supportProps) {
// TODO: implement automatic default property assigment in State.update root = root.apply(StateTransforms.Model.CustomModelProperties);
root = root.apply(StateTransforms.Model.CustomModelProperties, { properties: [] });
} }
root = root.apply(StateTransforms.Model.StructureAssemblyFromModel); const structure = root.apply(StateTransforms.Model.StructureAssemblyFromModel);
complexRepresentation(ctx, structure);
complexRepresentation(root);
return root.getTree(); return root.getTree();
} }
function complexRepresentation(root: StateTreeBuilder.To<PluginStateObject.Molecule.Structure>) { function complexRepresentation(ctx: PluginContext, root: StateTreeBuilder.To<PluginStateObject.Molecule.Structure>) {
root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }) root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D, { .apply(StateTransforms.Representation.StructureRepresentation3D,
type: { name: 'cartoon', params: PD.getDefaultValues(CartoonParams) }, StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'));
colorTheme: { name: 'polymer-id', params: PD.getDefaultValues(PolymerIdColorThemeParams) },
sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
});
root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }) root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D, { .apply(StateTransforms.Representation.StructureRepresentation3D,
type: { name: 'ball-and-stick', params: PD.getDefaultValues(BallAndStickParams) }, StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'));
colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
});
root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' }) root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
.apply(StateTransforms.Representation.StructureRepresentation3D, { .apply(StateTransforms.Representation.StructureRepresentation3D,
type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } }, StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }));
colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
})
root.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' }) root.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
.apply(StateTransforms.Representation.StructureRepresentation3D, { .apply(StateTransforms.Representation.StructureRepresentation3D,
type: { name: 'spacefill', params: { ...PD.getDefaultValues(SpacefillParams) } }, StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'spacefill'));
colorTheme: { name: 'polymer-id', params: PD.getDefaultValues(PolymerIdColorThemeParams) },
sizeTheme: { name: 'physical', params: PD.getDefaultValues(PhysicalSizeThemeParams) },
})
} }
export const CreateComplexRepresentation = StateAction.build({ export const CreateComplexRepresentation = StateAction.build({
display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' }, display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' },
from: PluginStateObject.Molecule.Structure from: PluginStateObject.Molecule.Structure
})(({ ref, state }) => { })(({ ref, state }, ctx: PluginContext) => {
const root = state.build().to(ref); const root = state.build().to(ref);
complexRepresentation(root); complexRepresentation(ctx, root);
return state.update(root.getTree()); return state.update(root.getTree());
}); });
......
...@@ -14,16 +14,31 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; ...@@ -14,16 +14,31 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
import { createTheme } from 'mol-theme/theme'; import { createTheme } from 'mol-theme/theme';
import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry'; import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry';
import { Structure } from 'mol-model/structure'; import { Structure } from 'mol-model/structure';
import { UnitsMeshParams } from 'mol-repr/structure/units-visual';
export namespace StructureRepresentation3DHelpers { export namespace StructureRepresentation3DHelpers {
export function getDefaultParams(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structure: Structure): Transformer.Params<StructureRepresentation3D> { export function getDefaultParams(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structure: Structure, meshParams?: Partial<PD.Values<UnitsMeshParams>>): Transformer.Params<StructureRepresentation3D> {
const type = ctx.structureRepresentation.registry.get(name); const type = ctx.structureRepresentation.registry.get(name);
const themeDataCtx = { structure }; const themeDataCtx = { structure };
const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).getParams(themeDataCtx); const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).getParams(themeDataCtx);
const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx) const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx)
return ({ return ({
type: { name, params: type.defaultValues }, type: { name, params: meshParams ? { ...type.defaultValues, ...meshParams } : type.defaultValues },
colorTheme: { name: type.defaultColorTheme, params: PD.getDefaultValues(colorParams) },
sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
})
}
export function getDefaultParamsStatic(ctx: PluginContext, name: BuiltInStructureRepresentationsName, meshParams?: Partial<PD.Values<UnitsMeshParams>>): Transformer.Params<StructureRepresentation3D> {
const type = ctx.structureRepresentation.registry.get(name);
// TODO: there should be "static default properties" for the themes.
const themeDataCtx = { };
const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).getParams(themeDataCtx);
const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx)
return ({
type: { name, params: meshParams ? { ...type.defaultValues, ...meshParams } : type.defaultValues },
colorTheme: { name: type.defaultColorTheme, params: PD.getDefaultValues(colorParams) }, colorTheme: { name: type.defaultColorTheme, params: PD.getDefaultValues(colorParams) },
sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) } sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
}) })
......
...@@ -18,6 +18,7 @@ import { StateActionManager } from './action/manager'; ...@@ -18,6 +18,7 @@ import { StateActionManager } from './action/manager';
import { TransientTree } from './tree/transient'; import { TransientTree } from './tree/transient';
import { LogEntry } from 'mol-util/log-entry'; import { LogEntry } from 'mol-util/log-entry';
import { now, formatTimespan } from 'mol-util/now'; import { now, formatTimespan } from 'mol-util/now';
import { ParamDefinition } from 'mol-util/param-definition';
export { State } export { State }
...@@ -498,6 +499,16 @@ async function updateSubtree(ctx: UpdateContext, root: Ref) { ...@@ -498,6 +499,16 @@ async function updateSubtree(ctx: UpdateContext, root: Ref) {
} }
} }
function resolveDefaultParams(ctx: UpdateContext, transform: Transform, src: StateObject) {
const prms = transform.transformer.definition.params;
const defaults = prms
? ParamDefinition.getDefaultValues(prms(src, ctx.parent.globalContext))
: { };
// TODO: this should probably be resolved each time separately the transform is applied.
// the params should be cached in the cell?
(transform.params as any) = defaults;
}
async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNodeResult> { async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNodeResult> {
const { oldTree, tree } = ctx; const { oldTree, tree } = ctx;
const current = ctx.cells.get(currentRef)!; const current = ctx.cells.get(currentRef)!;
...@@ -514,6 +525,10 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo ...@@ -514,6 +525,10 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
const parent = parentCell.obj!; const parent = parentCell.obj!;
current.sourceRef = parentCell.transform.ref; current.sourceRef = parentCell.transform.ref;
if (!transform.params) {
resolveDefaultParams(ctx, transform, parent);
}
if (!oldTree.transforms.has(currentRef)) { if (!oldTree.transforms.has(currentRef)) {
const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params); const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
current.obj = obj; current.obj = obj;
......
...@@ -40,7 +40,7 @@ export namespace Transform { ...@@ -40,7 +40,7 @@ export namespace Transform {
transformer, transformer,
props: (options && options.props) || { }, props: (options && options.props) || { },
ref, ref,
params: params || {} as any, params: params as any,
version: UUID.create22() version: UUID.create22()
} }
} }
......
...@@ -51,6 +51,12 @@ namespace StateTreeBuilder { ...@@ -51,6 +51,12 @@ namespace StateTreeBuilder {
export class To<A extends StateObject> implements StateTreeBuilder { export class To<A extends StateObject> implements StateTreeBuilder {
get editInfo() { return this.state.editInfo; } get editInfo() { return this.state.editInfo; }
readonly ref: Transform.Ref;
/**
* Apply the transformed to the parent node
* If no params are specified (params <- undefined), default params are lazily resolved.
*/
apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, options?: Partial<Transform.Options>, initialCellState?: Partial<StateObjectCell.State>): To<Transformer.To<T>> { apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, options?: Partial<Transform.Options>, initialCellState?: Partial<StateObjectCell.State>): To<Transformer.To<T>> {
const t = tr.apply(this.ref, params, options); const t = tr.apply(this.ref, params, options);
this.state.tree.add(t, initialCellState); this.state.tree.add(t, initialCellState);
...@@ -84,7 +90,8 @@ namespace StateTreeBuilder { ...@@ -84,7 +90,8 @@ namespace StateTreeBuilder {
getTree(): StateTree { return this.state.tree.asImmutable(); } getTree(): StateTree { return this.state.tree.asImmutable(); }
constructor(private state: State, private ref: Transform.Ref, private root: Root) { constructor(private state: State, ref: Transform.Ref, private root: Root) {
this.ref = ref;
if (!this.state.tree.transforms.has(ref)) { if (!this.state.tree.transforms.has(ref)) {
throw new Error(`Could not find node '${ref}'.`); throw new Error(`Could not find node '${ref}'.`);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment