Explorar el Código

proteopedia wrapper

David Sehnal hace 6 años
padre
commit
2632f9db4d

+ 3 - 1
src/examples/proteopedia-wrapper/helpers.ts

@@ -111,5 +111,7 @@ export enum StateElements {
     HetVisual = 'het-visual',
     Het3DSNFG = 'het-3dsnfg',
     Water = 'water',
-    WaterVisual = 'water-visual'
+    WaterVisual = 'water-visual',
+
+    HetGroupFocus = 'het-group-focus'
 }

+ 26 - 0
src/examples/proteopedia-wrapper/index.html

@@ -99,6 +99,7 @@
 
             PluginWrapper.events.modelInfo.subscribe(function (info) {
                 console.log('Model Info', info);
+                listHetGroups(info);
             });
 
             addControl('Load Asym Unit', () => PluginWrapper.load({ url: url, format: format }));
@@ -145,6 +146,12 @@
             addControl('Apply Evo Cons', () => PluginWrapper.coloring.evolutionaryConservation());
             addControl('Default Visuals', () => PluginWrapper.updateStyle());
 
+            addSeparator();
+            addHeader('HET Groups');
+
+            addControl('Reset', () => PluginWrapper.hetGroups.reset());
+            addHetGroupsContainer();
+
             addSeparator();
             addHeader('State');
 
@@ -163,6 +170,12 @@
 
             ////////////////////////////////////////////////////////
 
+            function addHetGroupsContainer() {
+                var div = document.createElement('div');
+                div.id = 'het-groups';
+                $('controls').appendChild(div);
+            }
+
             function addControl(label, action) {
                 var btn = document.createElement('button');
                 btn.onclick = action;
@@ -180,6 +193,19 @@
                 h.innerText = header;
                 $('controls').appendChild(h);
             }
+
+            function listHetGroups(info) {
+                var div = $('het-groups');
+                div.innerHTML = '';
+                info.hetResidues.forEach(function (r) {
+                    var l = document.createElement('button');
+                    l.innerText = r.name;
+                    l.onclick = function () {
+                        PluginWrapper.hetGroups.focusFirst(r.name);
+                    };
+                    div.appendChild(l);
+                });
+            }
         </script>
     </body>
 </html>

+ 71 - 0
src/examples/proteopedia-wrapper/index.ts

@@ -21,6 +21,14 @@ import { ControlsWrapper } from './ui/controls';
 import { PluginState } from 'mol-plugin/state';
 import { Scheduler } from 'mol-task';
 import { createProteopediaCustomTheme } from './coloring';
+import { MolScriptBuilder as MS } from 'mol-script/language/builder';
+import { BuiltInStructureRepresentations } from 'mol-repr/structure/registry';
+import { BuiltInColorThemes } from 'mol-theme/color';
+import { BuiltInSizeThemes } from 'mol-theme/size';
+import { ColorNames } from 'mol-util/color/tables';
+// import { Vec3 } from 'mol-math/linear-algebra';
+// import { ParamDefinition } from 'mol-util/param-definition';
+// import { Text } from 'mol-geo/geometry/text/text';
 require('mol-plugin/skin/light.scss')
 
 class MolStarProteopediaWrapper {
@@ -257,6 +265,69 @@ class MolStarProteopediaWrapper {
         }
     }
 
+    hetGroups = {
+        reset: () => {
+            const update = this.state.build().delete(StateElements.HetGroupFocus);
+            PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
+            PluginCommands.Camera.Reset.dispatch(this.plugin, { });
+        },
+        focusFirst: async (resn: string) => {
+            if (!this.state.transforms.has(StateElements.Assembly)) return;
+
+            // const asm = (this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure).data;
+
+            const update = this.state.build();
+
+            update.delete(StateElements.HetGroupFocus);
+
+            const surroundings = MS.struct.modifier.includeSurroundings({
+                0: MS.struct.filter.first([
+                    MS.struct.generator.atomGroups({
+                        'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), resn]),
+                        'group-by': MS.struct.atomProperty.macromolecular.residueKey()
+                    })
+                ]),
+                radius: 5,
+                'as-whole-residues': true
+            });
+
+            const sel = update.to(StateElements.Assembly)
+                .apply(StateTransforms.Model.StructureSelection, { label: resn, query: surroundings }, { ref: StateElements.HetGroupFocus });
+
+            sel.apply(StateTransforms.Representation.StructureRepresentation3D, this.createSurVisualParams());
+            // sel.apply(StateTransforms.Representation.StructureLabels3D, {
+            //     target: { name: 'residues', params: { } },
+            //     options: {
+            //         ...ParamDefinition.getDefaultValues(Text.Params),
+            //         background: true,
+            //         backgroundMargin: 0.2,
+            //         backgroundColor: ColorNames.snow,
+            //         backgroundOpacity: 0.9,
+            //     }
+            // });
+
+            await PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
+
+            const focus = (this.state.select(StateElements.HetGroupFocus)[0].obj as PluginStateObject.Molecule.Structure).data;
+            const sphere = focus.boundary.sphere;
+            // const asmCenter = asm.boundary.sphere.center;
+            // const position = Vec3.sub(Vec3.zero(), sphere.center, asmCenter);
+            // Vec3.normalize(position, position);
+            // Vec3.scaleAndAdd(position, sphere.center, position, sphere.radius);
+            const snapshot = this.plugin.canvas3d.camera.getFocus(sphere.center, 0.75 * sphere.radius);
+            PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, { snapshot, durationMs: 250 });
+        }
+    }
+
+    private createSurVisualParams() {
+        const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
+        return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
+            repr: BuiltInStructureRepresentations['ball-and-stick'],
+            color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
+            size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
+        });
+    }
+
     snapshot = {
         get: () => {
             return this.plugin.state.getSnapshot();

+ 6 - 2
src/mol-canvas3d/camera.ts

@@ -84,7 +84,7 @@ class Camera implements Object3D {
         return ret;
     }
 
-    focus(target: Vec3, radius: number) {
+    getFocus(target: Vec3, radius: number): Partial<Camera.Snapshot> {
         const fov = this.state.fov
         const { width, height } = this.viewport
         const aspect = width / height
@@ -98,7 +98,11 @@ class Camera implements Object3D {
         if (currentDistance < targetDistance) Vec3.negate(this.deltaDirection, this.deltaDirection)
         Vec3.add(this.newPosition, this.state.position, this.deltaDirection)
 
-        this.setState({ target, position: this.newPosition })
+        return { target, position: Vec3.clone(this.newPosition) };
+    }
+
+    focus(target: Vec3, radius: number) {
+        this.setState(this.getFocus(target, radius));
     }
 
     // lookAt(target: Vec3) {

+ 2 - 0
src/mol-model/structure/query.ts

@@ -9,12 +9,14 @@ import { StructureQuery } from './query/query'
 export * from './query/context'
 import * as generators from './query/queries/generators'
 import * as modifiers from './query/queries/modifiers'
+import * as filters from './query/queries/filters'
 import * as combinators from './query/queries/combinators'
 import * as internal from './query/queries/internal'
 import pred from './query/predicates'
 
 export const Queries = {
     generators,
+    filters,
     modifiers,
     combinators,
     pred,

+ 19 - 0
src/mol-model/structure/query/queries/filters.ts

@@ -31,6 +31,25 @@ export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuer
     };
 }
 
+export function first(query: StructureQuery): StructureQuery {
+    return ctx => {
+        const sel = query(ctx);
+        const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
+        if (sel.kind === 'singletons') {
+            if (sel.structure.elementCount > 0) {
+                const u = sel.structure.units[0];
+                const s = Structure.create([u.getChild(SortedArray.ofSingleton(u.elements[0]))]);
+                ret.add(s);
+            }
+        } else {
+            if (sel.structures.length > 0) {
+                ret.add(sel.structures[0]);
+            }
+        }
+        return ret.getSelection();
+    };
+}
+
 export interface UnitTypeProperties { atomic?: QueryFn, coarse?: QueryFn }
 
 export function getCurrentStructureProperties(ctx: QueryContext, props: UnitTypeProperties, set: Set<any>) {

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

@@ -53,7 +53,7 @@ export const PluginCommands = {
     },
     Camera: {
         Reset: PluginCommand<{}>(),
-        SetSnapshot: PluginCommand<{ snapshot: Camera.Snapshot, durationMs?: number }>(),
+        SetSnapshot: PluginCommand<{ snapshot: Partial<Camera.Snapshot>, durationMs?: number }>(),
         Snapshots: {
             Add: PluginCommand<{ name?: string, description?: string }>(),
             Remove: PluginCommand<{ id: string }>(),

+ 4 - 0
src/mol-script/language/symbol-table/structure-query.ts

@@ -167,6 +167,10 @@ const filter = {
         test: Argument(Type.Bool)
     }), Types.ElementSelectionQuery, 'Pick all atom sets that satisfy the test.'),
 
+    first: symbol(Arguments.Dictionary({
+        0: Argument(Types.ElementSelectionQuery)
+    }), Types.ElementSelectionQuery, 'Take the 1st atom set in the sequence.'),
+
     withSameAtomProperties: symbol(Arguments.Dictionary({
         0: Argument(Types.ElementSelectionQuery),
         source: Argument(Types.ElementSelectionQuery),

+ 3 - 0
src/mol-script/runtime/query/table.ts

@@ -186,6 +186,9 @@ const symbols = [
     C(MolScript.structureQuery.slot.element, (ctx, _) => ctx.element),
     // C(MolScript.structureQuery.slot.elementSetReduce, (ctx, _) => ctx.element),
 
+    // ============= FILTERS ================
+    D(MolScript.structureQuery.filter.first, (ctx, xs) => Queries.filters.first(xs[0] as any)(ctx)),
+
     // ============= GENERATORS ================
     D(MolScript.structureQuery.generator.atomGroups, (ctx, xs) => Queries.generators.atoms({
         entityTest: xs['entity-test'],

+ 1 - 0
src/mol-script/script/mol-script/symbols.ts

@@ -148,6 +148,7 @@ export const SymbolTable = [
         [
             'Filters',
             Alias(MolScript.structureQuery.filter.pick, 'sel.atom.pick'),
+            Alias(MolScript.structureQuery.filter.first, 'sel.atom.first'),
             Alias(MolScript.structureQuery.filter.withSameAtomProperties, 'sel.atom.with-same-atom-properties'),
             Alias(MolScript.structureQuery.filter.intersectedBy, 'sel.atom.intersected-by'),
             Alias(MolScript.structureQuery.filter.within, 'sel.atom.within'),