Bladeren bron

mol-state: wip, automatic default params

David Sehnal 6 jaren geleden
bovenliggende
commit
cc462a27a7

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props.ts

@@ -25,7 +25,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
         private provider: CustomPropertyRegistry.Provider = {
             option: [StructureQualityReport.Descriptor.name, 'PDBe Structure Quality Report'],
             descriptor: StructureQualityReport.Descriptor,
-            defaultSelected: false,
+            defaultSelected: this.params.autoAttach,
             attachableTo: () => true,
             attach: this.attach
         }

+ 1 - 1
src/mol-plugin/index.ts

@@ -36,7 +36,7 @@ const DefaultSpec: PluginSpec = {
         PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
         PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
         PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }),
-        PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: false })
+        PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true })
     ]
 }
 

+ 27 - 46
src/mol-plugin/state/actions/basic.ts

@@ -4,25 +4,20 @@
  * @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 { 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 { 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 { StateTree, Transformer } from 'mol-state';
-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';
+import { StructureRepresentation3DHelpers } from '../transforms/representation';
 
 // TODO: "structure parser provider"
 
-export { DownloadStructure }
+export { DownloadStructure };
 type DownloadStructure = typeof DownloadStructure
 const DownloadStructure = StateAction.build({
     from: PluginStateObject.Root,
@@ -55,7 +50,7 @@ const DownloadStructure = StateAction.build({
             ]
         })
     }
-})(({ params, state }) => {
+})(({ params, state }, ctx: PluginContext) => {
     const b = state.build();
     const src = params.source;
     let url: Transformer.Params<Download>;
@@ -77,69 +72,55 @@ const DownloadStructure = StateAction.build({
     }
 
     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({
     display: { name: 'Open Structure', description: 'Load a structure from file and create its default Assembly and visual' },
     from: PluginStateObject.Root,
     params: { file: PD.File({ accept: '.cif,.bcif' }) }
-})(({ params, state }) => {
+})(({ params, state }, ctx: PluginContext) => {
     const b = state.build();
     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
         .apply(StateTransforms.Data.ParseCif)
-        .apply(StateTransforms.Model.TrajectoryFromMmCif, {})
+        .apply(StateTransforms.Model.TrajectoryFromMmCif)
         .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 });
 
     if (supportProps) {
-        // TODO: implement automatic default property assigment in State.update
-        root = root.apply(StateTransforms.Model.CustomModelProperties, { properties: [] });
+        root = root.apply(StateTransforms.Model.CustomModelProperties);
     }
-    root = root.apply(StateTransforms.Model.StructureAssemblyFromModel);
-
-    complexRepresentation(root);
+    const structure = root.apply(StateTransforms.Model.StructureAssemblyFromModel);
+    complexRepresentation(ctx, structure);
 
     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' })
-        .apply(StateTransforms.Representation.StructureRepresentation3D, {
-            type: { name: 'cartoon', params: PD.getDefaultValues(CartoonParams) },
-            colorTheme: { name: 'polymer-id', params: PD.getDefaultValues(PolymerIdColorThemeParams) },
-            sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
-        });
+        .apply(StateTransforms.Representation.StructureRepresentation3D,
+            StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'));
     root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
-        .apply(StateTransforms.Representation.StructureRepresentation3D, {
-            type: { name: 'ball-and-stick', params: PD.getDefaultValues(BallAndStickParams) },
-            colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
-            sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
-        });
+        .apply(StateTransforms.Representation.StructureRepresentation3D,
+            StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'));
     root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
-        .apply(StateTransforms.Representation.StructureRepresentation3D, {
-            type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } },
-            colorTheme: { name: 'element-symbol', params: PD.getDefaultValues(ElementSymbolColorThemeParams) },
-            sizeTheme: { name: 'uniform', params: PD.getDefaultValues(UniformSizeThemeParams) },
-        })
+        .apply(StateTransforms.Representation.StructureRepresentation3D,
+            StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }));
     root.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
-        .apply(StateTransforms.Representation.StructureRepresentation3D, {
-            type: { name: 'spacefill', params: { ...PD.getDefaultValues(SpacefillParams) } },
-            colorTheme: { name: 'polymer-id', params: PD.getDefaultValues(PolymerIdColorThemeParams) },
-            sizeTheme: { name: 'physical', params: PD.getDefaultValues(PhysicalSizeThemeParams) },
-        })
+        .apply(StateTransforms.Representation.StructureRepresentation3D,
+            StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'spacefill'));
 }
 
 export const CreateComplexRepresentation = StateAction.build({
     display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' },
     from: PluginStateObject.Molecule.Structure
-})(({ ref, state }) => {
+})(({ ref, state }, ctx: PluginContext) => {
     const root = state.build().to(ref);
-    complexRepresentation(root);
+    complexRepresentation(ctx, root);
     return state.update(root.getTree());
 });
 

+ 17 - 2
src/mol-plugin/state/transforms/representation.ts

@@ -14,16 +14,31 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { createTheme } from 'mol-theme/theme';
 import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry';
 import { Structure } from 'mol-model/structure';
+import { UnitsMeshParams } from 'mol-repr/structure/units-visual';
 
 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 themeDataCtx = { structure };
         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: 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) },
             sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
         })

+ 15 - 0
src/mol-state/state.ts

@@ -18,6 +18,7 @@ import { StateActionManager } from './action/manager';
 import { TransientTree } from './tree/transient';
 import { LogEntry } from 'mol-util/log-entry';
 import { now, formatTimespan } from 'mol-util/now';
+import { ParamDefinition } from 'mol-util/param-definition';
 
 export { State }
 
@@ -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> {
     const { oldTree, tree } = ctx;
     const current = ctx.cells.get(currentRef)!;
@@ -514,6 +525,10 @@ async function updateNode(ctx: UpdateContext, currentRef: Ref): Promise<UpdateNo
     const parent = parentCell.obj!;
     current.sourceRef = parentCell.transform.ref;
 
+    if (!transform.params) {
+        resolveDefaultParams(ctx, transform, parent);
+    }
+
     if (!oldTree.transforms.has(currentRef)) {
         const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
         current.obj = obj;

+ 1 - 1
src/mol-state/transform.ts

@@ -40,7 +40,7 @@ export namespace Transform {
             transformer,
             props: (options && options.props) || { },
             ref,
-            params: params || {} as any,
+            params: params as any,
             version: UUID.create22()
         }
     }

+ 8 - 1
src/mol-state/tree/builder.ts

@@ -51,6 +51,12 @@ namespace StateTreeBuilder {
     export class To<A extends StateObject> implements StateTreeBuilder {
         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>> {
             const t = tr.apply(this.ref, params, options);
             this.state.tree.add(t, initialCellState);
@@ -84,7 +90,8 @@ namespace StateTreeBuilder {
 
         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)) {
                 throw new Error(`Could not find node '${ref}'.`);
             }