Browse Source

BasicWrapper PDB support, PDB parser fix

David Sehnal 6 years ago
parent
commit
79ba2fb2bc

+ 8 - 4
src/apps/basic-wrapper/index.html

@@ -3,7 +3,7 @@
     <head>
         <meta charset="utf-8" />
         <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-        <title>Mol* Viewer</title>
+        <title>Mol* Plugin Wrapper</title>
         <style>
             * {
                 margin: 0;
@@ -30,15 +30,19 @@
         <script>            
             var pdbId = '5ire', assemblyId= '1';
             var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
+            var format = 'cif';
+
+            // var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
+            // var format = 'pdb';
 
             BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
             BasicMolStarWrapper.setBackground(0xffffff);
-            BasicMolStarWrapper.loadCif(url, assemblyId);
+            BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
             BasicMolStarWrapper.toggleSpin();
 
             document.getElementById('spin').onclick = () => BasicMolStarWrapper.toggleSpin();
-            document.getElementById('asym').onclick = () => BasicMolStarWrapper.loadCif(url);
-            document.getElementById('asm').onclick = () => BasicMolStarWrapper.loadCif(url, assemblyId);
+            document.getElementById('asym').onclick = () => BasicMolStarWrapper.load({ url: url, format: format });
+            document.getElementById('asm').onclick = () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
         </script>
     </body>
 </html>

+ 41 - 15
src/apps/basic-wrapper/index.ts

@@ -10,13 +10,16 @@ import { PluginContext } from 'mol-plugin/context';
 import { PluginCommands } from 'mol-plugin/command';
 import { StateTransforms } from 'mol-plugin/state/transforms';
 import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation';
-import { StateTree } from 'mol-state';
 import { Color } from 'mol-util/color';
+import { StateTreeBuilder } from 'mol-state/tree/builder';
+import { PluginStateObject as PSO } from 'mol-plugin/state/objects';
 require('mol-plugin/skin/light.scss')
 
+type SupportedFormats = 'cif' | 'pdb'
+type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
+
 class BasicWrapper {
     plugin: PluginContext;
-    stateTemplate: StateTree;
 
     init(target: string | HTMLElement) {
         this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
@@ -26,15 +29,23 @@ class BasicWrapper {
                 showControls: false
             }
         });
+    }
+
+    private download(b: StateTreeBuilder.To<PSO.Root>, url: string) {
+        return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
+    }
 
-        const state = this.plugin.state.dataState.build();
-        const visualRoot = state.toRoot()
-            .apply(StateTransforms.Data.Download, { url: '', isBinary: false }, { ref: 'url' })
-            .apply(StateTransforms.Data.ParseCif)
-            .apply(StateTransforms.Model.TrajectoryFromMmCif)
+    private parse(b: StateTreeBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
+        const parsed = format === 'cif'
+            ? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
+            : b.apply(StateTransforms.Model.TrajectoryFromPDB);
+
+        return parsed
             .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
-            .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: '' }, { ref: 'asm' })
+            .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
+    }
 
+    private visual(visualRoot: StateTreeBuilder.To<PSO.Molecule.Structure>) {
         visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
             .apply(StateTransforms.Representation.StructureRepresentation3D,
                 StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'));
@@ -47,18 +58,33 @@ class BasicWrapper {
         visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
             .apply(StateTransforms.Representation.StructureRepresentation3D,
                 StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'));
-
-        this.stateTemplate = state.getTree();
+        return visualRoot;
     }
 
-    async loadCif(url: string, assemblyId?: string) {
-        const state = this.stateTemplate.build();
+    private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
+    async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
+        let loadType: 'full' | 'update' = 'full';
+
+        const state = this.plugin.state.dataState;
 
-        state.to('url').update(StateTransforms.Data.Download, p => ({ ...p, url }));
-        state.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
+        if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
+            loadType = 'full';
+        } else if (this.loadedParams.url === url) {
+            if (state.select('asm').length > 0) loadType = 'update';
+        }
 
-        await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree: state });
+        let tree: StateTreeBuilder.Root;
+        if (loadType === 'full') {
+            await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
+            tree = state.build();
+            this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
+        } else {
+            tree = state.build();
+            tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
+        }
 
+        await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
+        this.loadedParams = { url, format, assemblyId };
         PluginCommands.Camera.Reset.dispatch(this.plugin, { });
     }
 

+ 6 - 2
src/mol-model-formats/structure/pdb/assembly.ts

@@ -65,8 +65,12 @@ export function parseRemark350(lines: Tokens, lineStart: number, lineEnd: number
         let line = getLine(i);
         if (line.substr(11, 12) === 'BIOMOLECULE:') {
             const id = line.substr(23).trim();
-            line = getLine(++i);
-            const details = line.substr(11).trim();
+            let details: string = `Biomolecule ` + id;
+            line = getLine(i + 1);
+            if (line.substr(11, 30) !== 'APPLY THE FOLLOWING TO CHAINS:') {
+                i++;
+                details = line.substr(11).trim();
+            }
             current = PdbAssembly(id, details);
             assemblies.push(current);
         } else if (line.substr(13, 5) === 'BIOMT') {