Skip to content
Snippets Groups Projects
Commit e1b7a5b2 authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, structure tools, repr presets

parent 1ed420ae
No related branches found
No related tags found
No related merge requests found
......@@ -13,6 +13,8 @@ import { Color } from '../../../mol-util/color';
import { ButtonSelect, Options } from '../controls/common'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { VisualQuality, VisualQualityOptions } from '../../../mol-geo/geometry/base';
import { StructureRepresentationPresets as P } from '../../util/structure-representation-helper';
import { camelCaseToWords } from '../../../mol-util/string';
abstract class BaseStructureRepresentationControls extends PluginUIComponent {
onChange = (value: string) => {
......@@ -49,25 +51,19 @@ abstract class BaseStructureRepresentationControls extends PluginUIComponent {
<span title={this.label}>{this.label}</span>
<div className='msp-select-row'>
<ButtonSelect label='Show' onChange={this.show}>
<optgroup label='Show'>
{Options(types)}
</optgroup>
<optgroup label='Show'>{Options(types)}</optgroup>
</ButtonSelect>
<ButtonSelect label='Hide' onChange={this.hide}>
<optgroup label='Clear'>
<option key={'__all__'} value={'__all__'}>All</option>
</optgroup>
<optgroup label='Hide'>
{Options(types)}
</optgroup>
<optgroup label='Hide'>{Options(types)}</optgroup>
</ButtonSelect>
<ButtonSelect label='Color' onChange={this.color}>
<optgroup label='Clear'>
<option key={-1} value={-1}>Theme</option>
</optgroup>
<optgroup label='Color'>
{ColorOptions()}
</optgroup>
<optgroup label='Color'>{ColorOptions()}</optgroup>
</ButtonSelect>
</div>
</div>
......@@ -90,8 +86,11 @@ class SelectionStructureRepresentationControls extends BaseStructureRepresentati
}
export class StructureRepresentationControls extends PluginUIComponent {
preset = async () => {
await this.plugin.helpers.structureRepresentation.preset()
preset = async (value: string) => {
const presetFn = P[value as keyof typeof P]
if (presetFn) {
await presetFn(this.plugin.helpers.structureRepresentation)
}
}
onChange = async (p: { param: PD.Base<any>, name: string, value: any }) => {
......@@ -123,12 +122,20 @@ export class StructureRepresentationControls extends PluginUIComponent {
}
render() {
const presets = Object.keys(P).map(name => {
return [name, camelCaseToWords(name)] as [string, string]
})
return <div className='msp-transform-wrapper'>
<div className='msp-transform-header'>
<button className='msp-btn msp-btn-block'>Representation</button>
</div>
<div className='msp-btn-row-group'>
<button className='msp-btn msp-btn-block msp-form-control' onClick={() => this.preset()}>Preset</button>
<div className='msp-control-row'>
<div className='msp-select-row'>
<ButtonSelect label='Preset' onChange={this.preset}>
<optgroup label='Preset'>{Options(presets)}</optgroup>
</ButtonSelect>
</div>
</div>
<EverythingStructureRepresentationControls />
<SelectionStructureRepresentationControls />
......
......@@ -15,8 +15,6 @@ import { Interactivity } from '../../util/interactivity';
import { ParameterControls } from '../controls/parameters';
import { camelCaseToWords } from '../../../mol-util/string';
type SelectionModifier = 'add' | 'remove' | 'only'
const StructureSelectionParams = {
granularity: Interactivity.Params.granularity,
}
......
......@@ -49,7 +49,7 @@ export class StructureRepresentationHelper {
return selections.length > 0 ? selections[0] : undefined
}
private async _set(modifier: SelectionModifier, type: string, loci: StructureElement.Loci, structure: StructureTransform) {
private async _set(modifier: SelectionModifier, type: string, loci: StructureElement.Loci, structure: StructureTransform, props = {}) {
const state = this.plugin.state.dataState
const update = state.build()
const s = structure.obj!.data
......@@ -69,6 +69,7 @@ export class StructureRepresentationHelper {
const params = StructureRepresentation3DHelpers.getDefaultParams(this.plugin, type as any, s)
const p = params.type.params
Object.assign(p, props)
if (p.ignoreHydrogens !== undefined) p.ignoreHydrogens = this._ignoreHydrogens
if (p.quality !== undefined) p.quality = this._quality
......@@ -84,23 +85,23 @@ export class StructureRepresentationHelper {
await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }))
}
async set(modifier: SelectionModifier, type: string, lociGetter: (structure: Structure) => StructureElement.Loci) {
async set(modifier: SelectionModifier, type: string, lociGetter: (structure: Structure) => StructureElement.Loci, props = {}) {
const state = this.plugin.state.dataState;
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
for (const structure of structures) {
const s = structure.obj!.data
const loci = lociGetter(s)
await this._set(modifier, type, loci, structure)
await this._set(modifier, type, loci, structure, props)
}
}
async setFromExpression(modifier: SelectionModifier, type: string, expression: Expression) {
async setFromExpression(modifier: SelectionModifier, type: string, expression: Expression, props = {}) {
return this.set(modifier, type, (structure) => {
const compiled = compile<StructureSelection>(expression)
const result = compiled(new QueryContext(structure))
return StructureSelection.toLoci2(result)
})
}, props)
}
async clear() {
......@@ -169,16 +170,72 @@ export class StructureRepresentationHelper {
}
async preset() {
// TODO generalize and make configurable
await this.clear()
await this.setFromExpression('add', 'cartoon', Q.all)
await this.setFromExpression('add', 'carbohydrate', Q.all)
await this.setFromExpression('add', 'ball-and-stick', MS.struct.modifier.union([
MS.struct.combinator.merge([ Q.ligandsPlusConnected, Q.branchedConnectedOnly, Q.water ])
]))
// TODO option to limit to specific structure
const state = this.plugin.state.dataState;
const structures = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure))
if (structures.length === 0) return
const s = structures[0].obj!.data
if (s.elementCount < 50000) {
polymerAndLigand(this)
} else if (s.elementCount < 200000) {
proteinAndNucleic(this)
} else {
if (s.unitSymmetryGroups[0].units.length > 10) {
capsid(this)
} else {
coarseCapsid(this)
}
}
}
constructor(private plugin: PluginContext) {
}
}
//
async function polymerAndLigand(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'cartoon', Q.all)
await r.setFromExpression('add', 'carbohydrate', Q.all)
await r.setFromExpression('add', 'ball-and-stick', MS.struct.modifier.union([
MS.struct.combinator.merge([ Q.ligandPlusConnected, Q.branchedConnectedOnly, Q.water ])
]))
}
async function proteinAndNucleic(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'cartoon', Q.protein)
await r.setFromExpression('add', 'gaussian-surface', Q.nucleic)
await r.setFromExpression('add', 'carbohydrate', Q.all)
await r.setFromExpression('add', 'ball-and-stick', MS.struct.modifier.union([
MS.struct.combinator.merge([ Q.ligandPlusConnected, Q.branchedConnectedOnly, Q.water ])
]))
}
async function capsid(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'gaussian-surface', Q.polymer, {
smoothness: 0.5,
})
}
async function coarseCapsid(r: StructureRepresentationHelper) {
await r.clear()
await r.setFromExpression('add', 'gaussian-surface', Q.trace, {
radiusOffset: 1,
smoothness: 0.5,
visuals: ['structure-gaussian-surface-mesh']
})
}
export const StructureRepresentationPresets = {
polymerAndLigand,
proteinAndNucleic,
capsid,
coarseCapsid
}
\ No newline at end of file
......@@ -15,17 +15,52 @@ import Expression from '../../mol-script/language/expression';
const all = MS.struct.generator.all()
const polymers = MS.struct.modifier.union([
const polymer = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer'])
})
])
const backboneTrace = MS.struct.modifier.union([
const trace = MS.struct.modifier.union([
MS.struct.combinator.merge([
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
'chain-test': MS.core.set.has([
MS.set('sphere', 'gaussian'), MS.ammp('objectPrimitive')
])
})
]),
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
'atom-test': MS.core.set.has([MS.set('CA', 'P'), MS.ammp('label_atom_id')])
})
])
])
])
const protein = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.logic.and([
MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
MS.core.str.match([
MS.re('(polypeptide|cyclic-pseudo-peptide)', 'i'),
MS.ammp('entitySubtype')
])
])
})
])
const nucleic = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'atom-test': MS.core.logic.or([
MS.core.rel.eq([MS.ammp('label_atom_id'), 'CA']),
MS.core.rel.eq([MS.ammp('label_atom_id'), 'P'])
'entity-test': MS.core.logic.and([
MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
MS.core.str.match([
MS.re('(nucleotide|peptide nucleic acid)', 'i'),
MS.ammp('entitySubtype')
])
])
})
])
......@@ -37,19 +72,18 @@ const water = MS.struct.modifier.union([
])
const branched = MS.struct.modifier.union([
MS.struct.combinator.merge([
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'branched'])
})
]),
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'non-polymer']),
'residue-test': MS.core.str.match([MS.re('saccharide', 'i'), MS.ammp('chemCompType')])
})
MS.struct.generator.atomGroups({
'entity-test': MS.core.logic.or([
MS.core.rel.eq([MS.ammp('entityType'), 'branched']),
MS.core.logic.and([
MS.core.rel.eq([MS.ammp('entityType'), 'non-polymer']),
MS.core.str.match([
MS.re('oligosaccharide', 'i'),
MS.ammp('entitySubtype')
])
])
])
])
})
])
const branchedPlusConnected = MS.struct.modifier.union([
......@@ -65,21 +99,22 @@ const branchedConnectedOnly = MS.struct.modifier.union([
})
])
const ligands = MS.struct.modifier.union([
const ligand = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.logic.and([
MS.core.rel.neq([MS.ammp('entityType'), 'branched']),
MS.core.rel.eq([MS.ammp('entityType'), 'non-polymer'])
]),
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
'residue-test': MS.core.logic.not([
MS.core.str.match([MS.re('saccharide', 'i'), MS.ammp('chemCompType')])
])
})
])
const ligandsPlusConnected = MS.struct.modifier.union([
const ligandPlusConnected = MS.struct.modifier.union([
MS.struct.modifier.includeConnected({
0: ligands, 'layer-count': 1, 'as-whole-residues': true
0: ligand, 'layer-count': 1, 'as-whole-residues': true
})
])
......@@ -93,20 +128,22 @@ const coarse = MS.struct.modifier.union([
export const StructureSelectionQueries = {
all,
polymers,
backboneTrace,
polymer,
trace,
protein,
nucleic,
water,
branched,
branchedPlusConnected,
branchedConnectedOnly,
ligands,
ligandsPlusConnected,
ligand,
ligandPlusConnected,
coarse,
}
//
type SelectionModifier = 'add' | 'remove' | 'only'
export type SelectionModifier = 'add' | 'remove' | 'only'
export class StructureSelectionHelper {
private get structures() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment