ソースを参照

ability to set default params for volume streaming

David Sehnal 5 年 前
コミット
ccdc894979

+ 1 - 1
src/examples/proteopedia-wrapper/index.ts

@@ -316,7 +316,7 @@ class MolStarProteopediaWrapper {
         init: async (parent: Element) => {
             const asm = this.state.select(StateElements.Assembly)[0].obj!;
             const params = ParamDefinition.getDefaultValues(InitVolumeStreaming.definition.params!(asm, this.plugin));
-            params.behaviorRef = StateElements.VolumeStreaming;
+            params.options.behaviorRef = StateElements.VolumeStreaming;
             params.defaultView = 'box';
             await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, params, StateElements.Assembly));
             this.experimentalDataElement = parent;

+ 26 - 16
src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts

@@ -34,12 +34,20 @@ const Trigger = Binding.Trigger
 export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
 
 export namespace VolumeStreaming {
-    function channelParam(label: string, color: Color, defaultValue: VolumeIsoValue, stats: VolumeData['dataStats']) {
-        return PD.Group({
-            isoValue: createIsoValueParam(defaultValue, stats),
-            color: PD.Color(color),
-            wireframe: PD.Boolean(false),
-            opacity: PD.Numeric(0.3, { min: 0, max: 1, step: 0.01 })
+
+    export interface ChannelParams {
+        isoValue: VolumeIsoValue,
+        color: Color,
+        wireframe: boolean,
+        opacity: number
+    }
+
+    function channelParam(label: string, color: Color, defaultValue: VolumeIsoValue, stats: VolumeData['dataStats'], defaults: Partial<ChannelParams> = {}) {
+        return PD.Group<ChannelParams>({
+            isoValue: createIsoValueParam(typeof defaults.isoValue !== 'undefined' ? defaults.isoValue : defaultValue, stats),
+            color: PD.Color(typeof defaults.color !== 'undefined' ? defaults.color : color),
+            wireframe: PD.Boolean(typeof defaults.wireframe !== 'undefined' ? defaults.wireframe : false),
+            opacity: PD.Numeric(typeof defaults.opacity !== 'undefined' ? defaults.opacity : 0.3, { min: 0, max: 1, step: 0.01 })
         }, { label, isExpanded: true });
     }
 
@@ -54,13 +62,14 @@ export namespace VolumeStreaming {
         clickVolumeAroundOnly: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Show the volume around only the clicked element using ${triggers}.'),
     }
 
-    export function createParams(data?: VolumeServerInfo.Data, defaultView?: ViewTypes, binding?: typeof DefaultBindings) {
+    export function createParams(options: { data?: VolumeServerInfo.Data, defaultView?: ViewTypes, binding?: typeof DefaultBindings, channelParams?: DefaultChannelParams } = { }) {
+        const { data, defaultView, binding, channelParams } = options;
         const map = new Map<string, VolumeServerInfo.EntryData>()
         if (data) data.entries.forEach(d => map.set(d.dataId, d))
         const names = data ? data.entries.map(d => [d.dataId, d.dataId] as [string, string]) : []
         const defaultKey = data ? data.entries[0].dataId : ''
         return {
-            entry: PD.Mapped<EntryParams>(defaultKey, names, name => PD.Group(createEntryParams(map.get(name)!, defaultView, data && data.structure))),
+            entry: PD.Mapped<EntryParams>(defaultKey, names, name => PD.Group(createEntryParams({ entryData: map.get(name)!, defaultView, structure: data && data.structure, channelParams }))),
             bindings: PD.Value(binding || DefaultBindings, { isHidden: true }),
         }
     }
@@ -68,7 +77,9 @@ export namespace VolumeStreaming {
     export type EntryParamDefinition = typeof createEntryParams extends (...args: any[]) => (infer T) ? T : never
     export type EntryParams = EntryParamDefinition extends PD.Params ? PD.Values<EntryParamDefinition> : {}
 
-    export function createEntryParams(entryData?: VolumeServerInfo.EntryData, defaultView?: ViewTypes, structure?: Structure) {
+    export function createEntryParams(options: { entryData?: VolumeServerInfo.EntryData, defaultView?: ViewTypes, structure?: Structure, channelParams?: DefaultChannelParams }) {
+        const { entryData, defaultView, structure, channelParams = { } } = options;
+
         // fake the info
         const info = entryData || { kind: 'em', header: { sampling: [fakeSampling], availablePrecisions: [{ precision: 0, maxVoxels: 0 }] }, emDefaultContourLevel: VolumeIsoValue.relative(0) };
         const box = (structure && structure.boundary.box) || Box3D.empty();
@@ -92,12 +103,12 @@ export namespace VolumeStreaming {
                 info.header.availablePrecisions.map((p, i) => [i, `${i + 1} [ ${Math.pow(p.maxVoxels, 1 / 3) | 0}^3 cells ]`] as [number, string])),
             channels: info.kind === 'em'
                 ? PD.Group({
-                    'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || VolumeIsoValue.relative(1), info.header.sampling[0].valuesInfo[0])
+                    'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || VolumeIsoValue.relative(1), info.header.sampling[0].valuesInfo[0], channelParams['em'])
                 }, { isFlat: true })
                 : PD.Group({
-                    '2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), VolumeIsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0]),
-                    'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), VolumeIsoValue.relative(3), info.header.sampling[0].valuesInfo[1]),
-                    'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), VolumeIsoValue.relative(-3), info.header.sampling[0].valuesInfo[1]),
+                    '2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), VolumeIsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0], channelParams['2fo-fc']),
+                    'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), VolumeIsoValue.relative(3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(+ve)']),
+                    'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), VolumeIsoValue.relative(-3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(-ve)']),
                 }, { isFlat: true }),
         };
     }
@@ -109,9 +120,6 @@ export namespace VolumeStreaming {
     export type ParamDefinition = typeof createParams extends (...args: any[]) => (infer T) ? T : never
     export type Params = ParamDefinition extends PD.Params ? PD.Values<ParamDefinition> : {}
 
-    type CT = typeof channelParam extends (...args: any[]) => (infer T) ? T : never
-    export type ChannelParams = CT extends PD.Group<infer T> ? T : {}
-
     type ChannelsInfo = { [name in ChannelType]?: { isoValue: VolumeIsoValue, color: Color, wireframe: boolean, opacity: number } }
     type ChannelsData = { [name in 'EM' | '2FO-FC' | 'FO-FC']?: VolumeData }
 
@@ -126,6 +134,8 @@ export namespace VolumeStreaming {
     }
     export type Channels = { [name in ChannelType]?: ChannelInfo }
 
+    export type DefaultChannelParams = { [name in ChannelType]?: Partial<ChannelParams> }
+
     export class Behavior extends PluginBehavior.WithSubscribers<Params> {
         private cache = LRUCache.create<ChannelsData>(25);
         public params: Params = {} as any;

+ 13 - 10
src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts

@@ -40,11 +40,14 @@ export const InitVolumeStreaming = StateAction.build({
         return {
             method: PD.Select<VolumeServerInfo.Kind>(method, [['em', 'EM'], ['x-ray', 'X-Ray']]),
             entries: PD.ObjectList({ id: PD.Text(ids[0] || '') }, ({ id }) => id, { defaultValue: ids.map(id => ({ id })) }),
-            serverUrl: PD.Text('https://ds.litemol.org'),
             defaultView: PD.Select<VolumeStreaming.ViewTypes>(method === 'em' ? 'cell' : 'selection-box', VolumeStreaming.ViewTypeOptions as any),
-            behaviorRef: PD.Text('', { isHidden: true }),
-            emContourProvider: PD.Select<'wwpdb' | 'pdbe'>('wwpdb', [['wwpdb', 'wwPDB'], ['pdbe', 'PDBe']], { isHidden: true }),
-            bindings: PD.Value(VolumeStreaming.DefaultBindings, { isHidden: true }),
+            options: PD.Group({
+                serverUrl: PD.Text('https://ds.litemol.org'),
+                behaviorRef: PD.Text('', { isHidden: true }),
+                emContourProvider: PD.Select<'wwpdb' | 'pdbe'>('wwpdb', [['wwpdb', 'wwPDB'], ['pdbe', 'PDBe']], { isHidden: true }),
+                bindings: PD.Value(VolumeStreaming.DefaultBindings, { isHidden: true }),
+                channelParams: PD.Value<VolumeStreaming.DefaultChannelParams>({}, { isHidden: true })
+            })
         };
     },
     isApplicable: (a) => a.data.models.length === 1
@@ -63,12 +66,12 @@ export const InitVolumeStreaming = StateAction.build({
                 const emdbIds = await getEmdbIds(plugin, taskCtx, dataId)
                 for (let j = 0, jl = emdbIds.length; j < jl; ++j) {
                     const emdbId = emdbIds[j]
-                    const contourLevel = await getContourLevel(params.emContourProvider, plugin, taskCtx, emdbId)
+                    const contourLevel = await getContourLevel(params.options.emContourProvider, plugin, taskCtx, emdbId)
                     addEntry(entries, params.method, emdbId, contourLevel || 0)
                 }
                 continue;
             }
-            emDefaultContourLevel = await getContourLevel(params.emContourProvider, plugin, taskCtx, dataId);
+            emDefaultContourLevel = await getContourLevel(params.options.emContourProvider, plugin, taskCtx, dataId);
         }
 
         addEntry(entries, params.method, dataId, emDefaultContourLevel || 0)
@@ -76,15 +79,15 @@ export const InitVolumeStreaming = StateAction.build({
 
     const infoTree = state.build().to(ref)
         .apply(CreateVolumeStreamingInfo, {
-            serverUrl: params.serverUrl,
+            serverUrl: params.options.serverUrl,
             entries
         });
 
     const infoObj = await state.updateTree(infoTree).runInContext(taskCtx);
 
     const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior,
-        PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data, params.defaultView, params.bindings)),
-        { ref: params.behaviorRef ? params.behaviorRef : void 0 });
+        PD.getDefaultValues(VolumeStreaming.createParams({ data: infoObj.data, defaultView: params.defaultView, binding: params.options.bindings, channelParams: params.options.channelParams })),
+        { ref: params.options.behaviorRef ? params.options.behaviorRef : void 0 });
 
     if (params.method === 'em') {
         behTree.apply(VolumeStreamingVisual, { channel: 'em' }, { state: { isGhost: true } });
@@ -185,7 +188,7 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({
     from: VolumeServerInfo,
     to: VolumeStreaming,
     params(a) {
-        return VolumeStreaming.createParams(a && a.data);
+        return VolumeStreaming.createParams({ data: a && a.data });
     }
 })({
     canAutoUpdate: ({ oldParams, newParams }) => {