diff --git a/src/mol-model/structure/query/queries/internal.ts b/src/mol-model/structure/query/queries/internal.ts index 0c65b5c62a320928501be94047bb00f6b57a19e1..8cf1078110a6c3c929f56bada9d17a1e2ea8d8bf 100644 --- a/src/mol-model/structure/query/queries/internal.ts +++ b/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)); + }; +} diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index af037145a351bdf69b37224c336c2ed3bd73f45b..c4a047a20930a742fc3ed15ac737160551d72cc4 100644 --- a/src/mol-plugin/context.ts +++ b/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 diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts index d7e521824c97734cdc7ac07a1bb8c2d4c6ef73b8..dca8203d8f5b404202d8ef468bc2c6794547ba02 100644 --- a/src/mol-plugin/index.ts +++ b/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); } } \ No newline at end of file diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index f10374d3193f8bec997197dbbcd6b12cc8db12ca..152e549b007cea7a98b58b1235b4530aa0976c5b 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/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()); } }); diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 0c29e936769d896809048c88086573ab9c60410b..9f5efdddd610324cd62d8f1bd75c08f9917dd821 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/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.`); } diff --git a/src/mol-plugin/ui/state.tsx b/src/mol-plugin/ui/state.tsx index 031a3a54b572f8b16681f5652bf43366cb9648e1..d22304a0aeec92b8540b2c4b6090886977947513 100644 --- a/src/mol-plugin/ui/state.tsx +++ b/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 }) } }