Bladeren bron

mol-plugin: transform tweaks

David Sehnal 6 jaren geleden
bovenliggende
commit
edda4fe0d4

+ 20 - 2
src/mol-model/structure/query/queries/internal.ts

@@ -11,13 +11,14 @@ import Structure from '../../structure/structure';
 import { StructureQuery } from '../query';
 import { StructureSelection } from '../selection';
 
-export function sequence(): StructureQuery {
+export function atomicSequence(): StructureQuery {
     return ctx => {
         const { inputStructure } = ctx;
         const l = StructureElement.create();
 
         const units: Unit[] = [];
         for (const unit of inputStructure.units) {
+            if (unit.kind !== Unit.Kind.Atomic) continue;
             l.unit = unit;
             const elements = unit.elements;
             l.element = elements[0];
@@ -45,6 +46,8 @@ export function water(): StructureQuery {
 
         const units: Unit[] = [];
         for (const unit of inputStructure.units) {
+            if (unit.kind !== Unit.Kind.Atomic) continue;
+
             l.unit = unit;
             const elements = unit.elements;
             l.element = elements[0];
@@ -55,13 +58,15 @@ export function water(): StructureQuery {
     };
 }
 
-export function lidangs(): StructureQuery {
+export function atomicHet(): StructureQuery {
     return ctx => {
         const { inputStructure } = ctx;
         const l = StructureElement.create();
 
         const units: Unit[] = [];
         for (const unit of inputStructure.units) {
+            if (unit.kind !== Unit.Kind.Atomic) continue;
+
             l.unit = unit;
             const elements = unit.elements;
             l.element = elements[0];
@@ -82,3 +87,16 @@ export function lidangs(): StructureQuery {
         return StructureSelection.Singletons(inputStructure, new Structure(units));
     };
 }
+
+export function spheres(): StructureQuery {
+    return ctx => {
+        const { inputStructure } = ctx;
+
+        const units: Unit[] = [];
+        for (const unit of inputStructure.units) {
+            if (unit.kind !== Unit.Kind.Spheres) continue;
+            units.push(unit);
+        }
+        return StructureSelection.Singletons(inputStructure, new Structure(units));
+    };
+}

+ 8 - 4
src/mol-plugin/context.ts

@@ -83,15 +83,19 @@ export class PluginContext {
             this.canvas3d.animate();
             return true;
         } catch (e) {
-            this.log(LogEntry.error('' + e));
+            this.log.error('' + e);
             console.error(e);
             return false;
         }
     }
 
-    log(e: LogEntry) {
-        this.events.log.next(e);
-    }
+    readonly log = {
+        entry: (e: LogEntry) => this.events.log.next(e),
+        error: (msg: string) => this.events.log.next(LogEntry.error(msg)),
+        message: (msg: string) => this.events.log.next(LogEntry.message(msg)),
+        info: (msg: string) => this.events.log.next(LogEntry.info(msg)),
+        warn: (msg: string) => this.events.log.next(LogEntry.warning(msg)),
+    };
 
     /**
      * This should be used in all transform related request so that it could be "spoofed" to allow

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

@@ -13,7 +13,6 @@ import { PluginSpec } from './spec';
 import { DownloadAtomicStructure, CreateComplexRepresentation, OpenAtomicStructure } from './state/actions/basic';
 import { StateTransforms } from './state/transforms';
 import { PluginBehaviors } from './behavior';
-import { LogEntry } from 'mol-util/log-entry';
 
 function getParam(name: string, regex: string): string {
     let r = new RegExp(`${name}=(${regex})[&]?`, 'i');
@@ -55,7 +54,7 @@ async function trySetSnapshot(ctx: PluginContext) {
         if (!snapshotUrl) return;
         await PluginCommands.State.Snapshots.Fetch.dispatch(ctx, { url: snapshotUrl })
     } catch (e) {
-        ctx.log(LogEntry.error('Failed to load snapshot.'));
+        ctx.log.error('Failed to load snapshot.');
         console.warn('Failed to load snapshot', e);
     }
 }

+ 12 - 12
src/mol-plugin/state/actions/basic.ts

@@ -101,14 +101,20 @@ function atomicStructureTree(b: StateTreeBuilder.To<PluginStateObject.Data.Binar
         .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
         .apply(StateTransforms.Model.StructureAssemblyFromModel);
 
-    root.apply(StateTransforms.Model.StructureComplexElement, { type: 'sequence' })
+    complexRepresentation(root);
+
+    return root.getTree();
+}
+
+function complexRepresentation(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) } });
-    root.apply(StateTransforms.Model.StructureComplexElement, { type: 'ligands' })
+    root.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
         .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'ball-and-stick', params: PD.getDefaultValues(BallAndStickParams) } });
     root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
-        .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } } });
-
-    return root.getTree();
+        .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } } })
+    root.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' });
+        // TODO: create spheres visual
 }
 
 export const CreateComplexRepresentation = StateAction.create<PluginStateObject.Molecule.Structure, void, {}>({
@@ -119,13 +125,7 @@ export const CreateComplexRepresentation = StateAction.create<PluginStateObject.
     },
     apply({ ref, state }) {
         const root = state.build().to(ref);
-        root.apply(StateTransforms.Model.StructureComplexElement, { type: 'sequence' })
-            .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'cartoon', params: PD.getDefaultValues(CartoonParams) } });
-        root.apply(StateTransforms.Model.StructureComplexElement, { type: 'ligands' })
-            .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'ball-and-stick', params: PD.getDefaultValues(BallAndStickParams) } });
-        root.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
-            .apply(StateTransforms.Representation.StructureRepresentation3D, { type: { name: 'ball-and-stick', params: { ...PD.getDefaultValues(BallAndStickParams), alpha: 0.51 } } });
-
+        complexRepresentation(root);
         return state.update(root.getTree());
     }
 });

+ 15 - 7
src/mol-plugin/state/transforms/model.ts

@@ -13,6 +13,7 @@ import Expression from 'mol-script/language/expression';
 import { compile } from 'mol-script/runtime/query/compiler';
 import { MolScriptBuilder } from 'mol-script/language/builder';
 import { StateObject } from 'mol-state';
+import { PluginContext } from 'mol-plugin/context';
 
 export { TrajectoryFromMmCif }
 namespace TrajectoryFromMmCif { export interface Params { blockHeader?: string } }
@@ -102,15 +103,21 @@ const StructureAssemblyFromModel = PluginStateTransform.Create<SO.Molecule.Model
         const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]);
         return { id: PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' }) };
     },
-    apply({ a, params }) {
+    apply({ a, params }, plugin: PluginContext) {
         return Task.create('Build Assembly', async ctx => {
-            let id = params.id;
+            let id = (params.id || '').trim();
             const model = a.data;
             if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id;
-            const asm = ModelSymmetry.findAssembly(model, id || '');
-            if (!asm) throw new Error(`Assembly '${id}' not found`);
+            const asm = ModelSymmetry.findAssembly(model, id);
+            if (id && !asm) throw new Error(`Assembly '${id}' not found`);
 
             const base = Structure.ofModel(model);
+            if (!asm) {
+                plugin.log.warn(`Model '${a.label}' has no assembly, returning default structure.`);
+                const label = { label: a.data.label, description: structureDesc(base) };
+                return new SO.Molecule.Structure(base, label);
+            }
+
             const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
             const label = { label: `Assembly ${id}`, description: structureDesc(s) };
             return new SO.Molecule.Structure(s, label);
@@ -143,7 +150,7 @@ const StructureSelection = PluginStateTransform.Create<SO.Molecule.Structure, SO
 });
 
 export { StructureComplexElement }
-namespace StructureComplexElement { export interface Params { type: 'sequence' | 'water' | 'ligands' } }
+namespace StructureComplexElement { export interface Params { type: 'atomic-sequence' | 'water' | 'atomic-het' | 'spheres' } }
 const StructureComplexElement = PluginStateTransform.Create<SO.Molecule.Structure, SO.Molecule.Structure, StructureComplexElement.Params>({
     name: 'structure-complex-element',
     display: {
@@ -158,9 +165,10 @@ const StructureComplexElement = PluginStateTransform.Create<SO.Molecule.Structur
 
         let query: StructureQuery, label: string;
         switch (params.type) {
-            case 'sequence': query = Queries.internal.sequence(); label = 'Sequence'; break;
+            case 'atomic-sequence': query = Queries.internal.atomicSequence(); label = 'Sequence'; break;
             case 'water': query = Queries.internal.water(); label = 'Water'; break;
-            case 'ligands': query = Queries.internal.lidangs(); label = 'Ligands'; break;
+            case 'atomic-het': query = Queries.internal.atomicHet(); label = 'HET Groups/Ligands'; break;
+            case 'spheres': query = Queries.internal.spheres(); label = 'Coarse Spheres'; break;
             default: throw new Error(`${params.type} is a valid complex element.`);
         }
 

+ 2 - 3
src/mol-plugin/ui/state.tsx

@@ -9,7 +9,6 @@ import * as React from 'react';
 import { PluginComponent } from './base';
 import { shallowEqual } from 'mol-util';
 import { List } from 'immutable';
-import { LogEntry } from 'mol-util/log-entry';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { ParameterControls } from './controls/parameters';
 import { Subject } from 'rxjs';
@@ -58,7 +57,7 @@ class StateSnapshotControls extends PluginComponent<{ serverUrl: string, serverC
         this.setState({ isUploading: true });
         await PluginCommands.State.Snapshots.Upload.dispatch(this.plugin, { name: this.state.name, description: this.state.description, serverUrl: this.state.serverUrl });
         this.setState({ isUploading: false });
-        this.plugin.log(LogEntry.message('Snapshot uploaded.'));
+        this.plugin.log.message('Snapshot uploaded.');
         UploadedEvent.next();
     }
 
@@ -128,7 +127,7 @@ class RemoteStateSnapshotList extends PluginComponent<{ serverUrl: string }, { e
                 }))),
                 isFetching: false })
         } catch (e) {
-            this.plugin.log(LogEntry.error('Fetching Remote Snapshots: ' + e));
+            this.plugin.log.error('Fetching Remote Snapshots: ' + e);
             this.setState({ entries: List<RemoteEntry>(), isFetching: false })
         }
     }