Browse Source

add wwpdb provider for emdb contourLevel

Alexander Rose 5 years ago
parent
commit
1819a2bbda

+ 11 - 9
src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts

@@ -2,6 +2,7 @@
  * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { PluginStateObject as SO, PluginStateTransform } from '../../../state/objects';
@@ -13,38 +14,39 @@ import { urlCombine } from '../../../../mol-util/url';
 import { createIsoValueParam } from '../../../../mol-repr/volume/isosurface';
 import { VolumeIsoValue } from '../../../../mol-model/volume';
 import { StateAction, StateObject, StateTransformer } from '../../../../mol-state';
-import { getStreamingMethod, getEmdbIdAndContourLevel } from './util';
+import { getStreamingMethod, getId, getContourLevel, getEmdbId } from './util';
 import { VolumeStreaming } from './behavior';
 import { VolumeRepresentation3DHelpers } from '../../../../mol-plugin/state/transforms/representation';
 import { BuiltInVolumeRepresentations } from '../../../../mol-repr/volume/registry';
 import { createTheme } from '../../../../mol-theme/theme';
 import { Box3D } from '../../../../mol-math/geometry';
 import { Vec3 } from '../../../../mol-math/linear-algebra';
-// import { PluginContext } from '../../../../mol-plugin/context';
 
 export const InitVolumeStreaming = StateAction.build({
     display: { name: 'Volume Streaming' },
     from: SO.Molecule.Structure,
     params(a) {
         const method = getStreamingMethod(a && a.data);
+        const id = getId(a && a.data);
         return {
             method: PD.Select<VolumeServerInfo.Kind>(method, [['em', 'EM'], ['x-ray', 'X-Ray']]),
-            id: PD.Text((a && a.data.models.length > 0 && a.data.models[0].entry) || ''),
+            id: PD.Text(id),
             serverUrl: PD.Text('https://ds.litemol.org'),
             defaultView: PD.Text<VolumeStreaming.ViewTypes>(method === 'em' ? 'cell' : 'selection-box'),
-            behaviorRef: PD.Text('', { isHidden: true })
+            behaviorRef: PD.Text('', { isHidden: true }),
+            emContourProvider: PD.Select<'wwpdb' | 'pdbe'>('wwpdb', [['wwpdb', 'wwPDB'], ['pdbe', 'PDBe']], { isHidden: true }),
         };
     },
     isApplicable: (a) => a.data.models.length === 1
 })(({ ref, state, params }, plugin: PluginContext) => Task.create('Volume Streaming', async taskCtx => {
-    // TODO: custom react view for this and the VolumeStreamingBehavior transformer
-
     let dataId = params.id.toLowerCase(), emDefaultContourLevel: number | undefined;
     if (params.method === 'em') {
         await taskCtx.update('Getting EMDB info...');
-        const emInfo = await getEmdbIdAndContourLevel(plugin, taskCtx, dataId);
-        dataId = emInfo.emdbId;
-        emDefaultContourLevel = emInfo.contour;
+        if (!dataId.toUpperCase().startsWith('EMD')) {
+            dataId = await getEmdbId(plugin, taskCtx, dataId)
+        }
+        const contourLevel = await getContourLevel(params.emContourProvider, plugin, taskCtx, dataId);
+        emDefaultContourLevel = contourLevel || 0;
     }
 
     const infoTree = state.build().to(ref)

+ 50 - 10
src/mol-plugin/behavior/dynamic/volume-streaming/util.ts

@@ -2,12 +2,14 @@
  * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { Structure } from '../../../../mol-model/structure';
 import { VolumeServerInfo } from './model';
 import { PluginContext } from '../../../../mol-plugin/context';
 import { RuntimeContext } from '../../../../mol-task';
+import { getXMLNodeByName, XMLDocument } from '../../../../mol-util/xml-parser';
 
 export function getStreamingMethod(s?: Structure, defaultKind: VolumeServerInfo.Kind = 'x-ray'): VolumeServerInfo.Kind {
     if (!s) return defaultKind;
@@ -23,7 +25,53 @@ export function getStreamingMethod(s?: Structure, defaultKind: VolumeServerInfo.
     return 'x-ray';
 }
 
-export async function getEmdbIdAndContourLevel(plugin: PluginContext, taskCtx: RuntimeContext, pdbId: string) {
+export function getId(s?: Structure): string {
+    if (!s) return ''
+
+    const model = s.models[0]
+    if (model.sourceData.kind !== 'mmCIF') return ''
+
+    const d = model.sourceData.data
+    for (let i = 0, il = d.pdbx_database_related._rowCount; i < il; ++i) {
+        if (d.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
+            return d.pdbx_database_related.db_id.value(i)
+        }
+    }
+
+    return s.models.length > 0 ? s.models[0].entryId : ''
+}
+
+export async function getContourLevel(provider: 'wwpdb' | 'pdbe', plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
+    switch (provider) {
+        case 'wwpdb': return getContourLevelWwpdb(plugin, taskCtx, emdbId)
+        case 'pdbe': return getContourLevelPdbe(plugin, taskCtx, emdbId)
+    }
+}
+
+export async function getContourLevelWwpdb(plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
+    // TODO: parametrize to a differnt URL? in plugin settings perhaps
+    const header = await plugin.fetch<XMLDocument>({ url: `https://ftp.wwpdb.org/pub/emdb/structures/${emdbId.toUpperCase()}/header/${emdbId.toLowerCase()}.xml`, type: 'xml' }).runInContext(taskCtx);
+
+    const map = getXMLNodeByName('map', header!.root!.children!)!
+    const contourLevel = parseFloat(getXMLNodeByName('contourLevel', map.children!)!.content!)
+
+    return contourLevel;
+}
+
+export async function getContourLevelPdbe(plugin: PluginContext, taskCtx: RuntimeContext, emdbId: string) {
+    emdbId = emdbId.toUpperCase()
+    // TODO: parametrize to a differnt URL? in plugin settings perhaps
+    const header = await plugin.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/emdb/entry/map/${emdbId}`, type: 'json' }).runInContext(taskCtx);
+    const emdbEntry = header && header[emdbId];
+    let contourLevel: number | undefined = void 0;
+    if (emdbEntry && emdbEntry[0] && emdbEntry[0].map && emdbEntry[0].map.contour_level && emdbEntry[0].map.contour_level.value !== void 0) {
+        contourLevel = +emdbEntry[0].map.contour_level.value;
+    }
+
+    return contourLevel;
+}
+
+export async function getEmdbId(plugin: PluginContext, taskCtx: RuntimeContext, pdbId: string) {
     // TODO: parametrize to a differnt URL? in plugin settings perhaps
     const summary = await plugin.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${pdbId}`, type: 'json' }).runInContext(taskCtx);
 
@@ -39,13 +87,5 @@ export async function getEmdbIdAndContourLevel(plugin: PluginContext, taskCtx: R
         throw new Error(`No related EMDB entry found for '${pdbId}'.`);
     }
 
-    // TODO: parametrize to a differnt URL? in plugin settings perhaps
-    const emdb = await plugin.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/emdb/entry/map/${emdbId}`, type: 'json' }).runInContext(taskCtx);
-    const emdbEntry = emdb && emdb[emdbId];
-    let contour: number | undefined = void 0;
-    if (emdbEntry && emdbEntry[0] && emdbEntry[0].map && emdbEntry[0].map.contour_level && emdbEntry[0].map.contour_level.value !== void 0) {
-        contour = +emdbEntry[0].map.contour_level.value;
-    }
-
-    return { emdbId, contour };
+    return emdbId
 }