Skip to content
Snippets Groups Projects
Commit d1b8b6da authored by David Sehnal's avatar David Sehnal
Browse files

mol-plugin: user selections

parent 7b8b2c10
No related branches found
No related tags found
No related merge requests found
...@@ -28,6 +28,8 @@ function paramInfo(param: PD.Any, offset: number): string { ...@@ -28,6 +28,8 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`; case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`;
case 'mapped': return `Object { name: string, params: object } where name+params are:\n${getMapped(param, offset + 2)}`; case 'mapped': return `Object { name: string, params: object } where name+params are:\n${getMapped(param, offset + 2)}`;
case 'line-graph': return `A list of 2d vectors [xi, yi][]`; case 'line-graph': return `A list of 2d vectors [xi, yi][]`;
// TODO: support more languages
case 'script-expression': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
default: default:
const _: never = param; const _: never = param;
console.warn(`${_} has no associated UI component`); console.warn(`${_} has no associated UI component`);
......
...@@ -40,6 +40,7 @@ export const DefaultPluginSpec: PluginSpec = { ...@@ -40,6 +40,7 @@ export const DefaultPluginSpec: PluginSpec = {
PluginSpec.Action(StateTransforms.Model.StructureSymmetryFromModel), PluginSpec.Action(StateTransforms.Model.StructureSymmetryFromModel),
PluginSpec.Action(StateTransforms.Model.StructureFromModel), PluginSpec.Action(StateTransforms.Model.StructureFromModel),
PluginSpec.Action(StateTransforms.Model.ModelFromTrajectory), PluginSpec.Action(StateTransforms.Model.ModelFromTrajectory),
PluginSpec.Action(StateTransforms.Model.UserStructureSelection),
PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4), PluginSpec.Action(StateTransforms.Volume.VolumeFromCcp4),
PluginSpec.Action(StateTransforms.Representation.StructureRepresentation3D), PluginSpec.Action(StateTransforms.Representation.StructureRepresentation3D),
PluginSpec.Action(StateTransforms.Representation.StructureLabels3D), PluginSpec.Action(StateTransforms.Representation.StructureLabels3D),
......
...@@ -22,6 +22,8 @@ import { stringToWords } from 'mol-util/string'; ...@@ -22,6 +22,8 @@ import { stringToWords } from 'mol-util/string';
import { PluginStateObject as SO, PluginStateTransform } from '../objects'; import { PluginStateObject as SO, PluginStateTransform } from '../objects';
import { trajectoryFromGRO } from 'mol-model-formats/structure/gro'; import { trajectoryFromGRO } from 'mol-model-formats/structure/gro';
import { parseGRO } from 'mol-io/reader/gro/parser'; import { parseGRO } from 'mol-io/reader/gro/parser';
import { parseMolScript } from 'mol-script/language/parser';
import { transpileMolScript } from 'mol-script/script/mol-script/symbols';
export { TrajectoryFromMmCif }; export { TrajectoryFromMmCif };
export { TrajectoryFromPDB }; export { TrajectoryFromPDB };
...@@ -31,8 +33,10 @@ export { StructureFromModel }; ...@@ -31,8 +33,10 @@ export { StructureFromModel };
export { StructureAssemblyFromModel }; export { StructureAssemblyFromModel };
export { StructureSymmetryFromModel }; export { StructureSymmetryFromModel };
export { StructureSelection }; export { StructureSelection };
export { UserStructureSelection };
export { StructureComplexElement }; export { StructureComplexElement };
export { CustomModelProperties }; export { CustomModelProperties };
type TrajectoryFromMmCif = typeof TrajectoryFromMmCif type TrajectoryFromMmCif = typeof TrajectoryFromMmCif
const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({ const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({
name: 'trajectory-from-mmcif', name: 'trajectory-from-mmcif',
...@@ -243,6 +247,31 @@ const StructureSelection = PluginStateTransform.BuiltIn({ ...@@ -243,6 +247,31 @@ const StructureSelection = PluginStateTransform.BuiltIn({
} }
}); });
type UserStructureSelection = typeof UserStructureSelection
const UserStructureSelection = PluginStateTransform.BuiltIn({
name: 'user-structure-selection',
display: { name: 'Structure Selection', description: 'Create a molecular structure from the specified query expression.' },
from: SO.Molecule.Structure,
to: SO.Molecule.Structure,
params: {
query: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname ALA))' }),
label: PD.makeOptional(PD.Text(''))
}
})({
apply({ a, params }) {
// TODO: use cache, add "update"
const parsed = parseMolScript(params.query.expression);
if (parsed.length === 0) throw new Error('No query');
const query = transpileMolScript(parsed[0]);
const compiled = compile<Sel>(query);
const result = compiled(new QueryContext(a.data));
const s = Sel.unionStructure(result);
if (s.elementCount === 0) return StateObject.Null;
const props = { label: `${params.label || 'Selection'}`, description: structureDesc(s) };
return new SO.Molecule.Structure(s, props);
}
});
namespace StructureComplexElement { namespace StructureComplexElement {
export type Types = 'atomic-sequence' | 'water' | 'atomic-het' | 'spheres' export type Types = 'atomic-sequence' | 'water' | 'atomic-het' | 'spheres'
} }
......
...@@ -63,6 +63,7 @@ function controlFor(param: PD.Any): ParamControl | undefined { ...@@ -63,6 +63,7 @@ function controlFor(param: PD.Any): ParamControl | undefined {
case 'group': return GroupControl; case 'group': return GroupControl;
case 'mapped': return MappedControl; case 'mapped': return MappedControl;
case 'line-graph': return LineGraphControl; case 'line-graph': return LineGraphControl;
case 'script-expression': return ScriptExpressionControl;
default: default:
const _: never = param; const _: never = param;
console.warn(`${_} has no associated UI component`); console.warn(`${_} has no associated UI component`);
...@@ -77,7 +78,7 @@ export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> { name: strin ...@@ -77,7 +78,7 @@ export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> { name: strin
export type ParamControl = React.ComponentClass<ParamProps<any>> export type ParamControl = React.ComponentClass<ParamProps<any>>
export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<ParamProps<P>> { export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<ParamProps<P>> {
protected update(value: any) { protected update(value: P['defaultValue']) {
this.props.onChange({ param: this.props.param, name: this.props.name, value }); this.props.onChange({ param: this.props.param, name: this.props.name, value });
} }
...@@ -562,3 +563,32 @@ export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converte ...@@ -562,3 +563,32 @@ export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converte
return <Converted param={this.props.param.converted} value={value} name={this.props.name} onChange={this.onChange} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} /> return <Converted param={this.props.param.converted} value={value} name={this.props.name} onChange={this.onChange} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />
} }
} }
export class ScriptExpressionControl extends SimpleParam<PD.ScriptExpression> {
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
if (value !== this.props.value.expression) {
this.update({ language: this.props.value.language, expression: value });
}
}
onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (!this.props.onEnter) return;
if ((e.keyCode === 13 || e.charCode === 13)) {
this.props.onEnter();
}
}
renderControl() {
// TODO: improve!
const placeholder = this.props.param.label || camelCaseToWords(this.props.name);
return <input type='text'
value={this.props.value.expression || ''}
placeholder={placeholder}
onChange={this.onChange}
onKeyPress={this.props.onEnter ? this.onKeyPress : void 0}
disabled={this.props.isDisabled}
/>;
}
}
\ No newline at end of file
...@@ -213,7 +213,14 @@ export namespace ParamDefinition { ...@@ -213,7 +213,14 @@ export namespace ParamDefinition {
return { type: 'conditioned', select: Select<string>(conditionForValue(defaultValue) as string, options), defaultValue, conditionParams, conditionForValue, conditionedValue }; return { type: 'conditioned', select: Select<string>(conditionForValue(defaultValue) as string, options), defaultValue, conditionParams, conditionForValue, conditionedValue };
} }
export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> export interface ScriptExpression extends Base<{ language: 'mol-script', expression: string }> {
type: 'script-expression'
}
export function ScriptExpression(defaultValue: ScriptExpression['defaultValue'], info?: Info): ScriptExpression {
return setInfo<ScriptExpression>({ type: 'script-expression', defaultValue }, info)
}
export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | ScriptExpression
export type Params = { [k: string]: Any } export type Params = { [k: string]: Any }
export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] } export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] }
...@@ -301,6 +308,9 @@ export namespace ParamDefinition { ...@@ -301,6 +308,9 @@ export namespace ParamDefinition {
return true; return true;
} else if (p.type === 'vec3') { } else if (p.type === 'vec3') {
return Vec3Data.equals(a, b); return Vec3Data.equals(a, b);
} else if (p.type === 'script-expression') {
const u = a as ScriptExpression['defaultValue'], v = b as ScriptExpression['defaultValue'];
return u.language === v.language && u.expression === v.expression;
} else if (typeof a === 'object' && typeof b === 'object') { } else if (typeof a === 'object' && typeof b === 'object') {
return shallowEqual(a, b); return shallowEqual(a, b);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment