Bladeren bron

pdbe validation color theme

David Sehnal 6 jaren geleden
bovenliggende
commit
ee89a9a26c

+ 54 - 0
src/mol-model-props/pdbe/themes/structure-quality-report.ts

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { StructureQualityReport } from 'mol-model-props/pdbe/structure-quality-report';
+import { Location } from 'mol-model/location';
+import { StructureElement } from 'mol-model/structure';
+import { ColorTheme, LocationColor } from 'mol-theme/color';
+import { ThemeDataContext } from 'mol-theme/theme';
+import { Color } from 'mol-util/color';
+import { TableLegend } from 'mol-util/color/tables';
+
+const ValidationColors = [
+    Color.fromRgb(170, 170, 170), // not applicable
+    Color.fromRgb(0, 255, 0), // 0 issues
+    Color.fromRgb(255, 255, 0), // 1
+    Color.fromRgb(255, 128, 0), // 2
+    Color.fromRgb(255, 0, 0), // 3 or more
+]
+
+const ValidationColorTable: [string, Color][] = [
+    ['No Issues', ValidationColors[1]],
+    ['One Issue', ValidationColors[2]],
+    ['Two Issues', ValidationColors[3]],
+    ['Three Or More Issues', ValidationColors[4]],
+    ['Not Applicable', ValidationColors[9]]
+]
+
+export function StructureQualityReportColorTheme(ctx: ThemeDataContext, props: {}): ColorTheme<{}> {
+    let color: LocationColor
+
+    if (ctx.structure && ctx.structure.models[0].customProperties.has(StructureQualityReport.Descriptor)) {
+        const getIssues = StructureQualityReport.getIssues;
+        color = (location: Location) => {
+            if (StructureElement.isLocation(location)) {
+                return ValidationColors[Math.min(3, getIssues(location).length) + 1];
+            }
+            return ValidationColors[0];
+        }
+    } else {
+        color = () => ValidationColors[0];
+    }
+
+    return {
+        factory: StructureQualityReportColorTheme,
+        granularity: 'group',
+        color: color,
+        props: props,
+        description: 'Assigns residue colors according to the number of issues in the PDBe Validation Report.',
+        legend: TableLegend(ValidationColorTable)
+    }
+}

+ 18 - 7
src/mol-plugin/behavior/dynamic/custom-props.ts

@@ -4,15 +4,14 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { ParamDefinition } from 'mol-util/param-definition';
-import { PluginBehavior } from '../behavior';
+import { OrderedSet } from 'mol-data/int';
 import { StructureQualityReport } from 'mol-model-props/pdbe/structure-quality-report';
-import { CustomPropertyRegistry } from 'mol-plugin/util/custom-prop-registry';
+import { StructureQualityReportColorTheme } from 'mol-model-props/pdbe/themes/structure-quality-report';
 import { Loci } from 'mol-model/loci';
 import { StructureElement } from 'mol-model/structure';
-import { OrderedSet } from 'mol-data/int';
-
-// TODO: make auto attach working better for "initial state" by supporting default props in state updates
+import { CustomPropertyRegistry } from 'mol-plugin/util/custom-prop-registry';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { PluginBehavior } from '../behavior';
 
 export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: boolean }>({
     name: 'pdbe-structure-quality-report-prop',
@@ -33,6 +32,15 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
         register(): void {
             this.ctx.customModelProperties.register(this.provider);
             this.ctx.lociLabels.addProvider(labelPDBeValidation);
+
+            // TODO: support filtering of themes based on the input structure
+            // in this case, it would check structure.models[0].customProperties.has(StructureQualityReport.Descriptor)
+            // TODO: add remove functionality
+            this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('pdbe-structure-quality-report', {
+                label: 'PDBe Structure Quality Report',
+                factory: StructureQualityReportColorTheme,
+                getParams: () => ({})
+            })
         }
 
         update(p: { autoAttach: boolean }) {
@@ -45,10 +53,13 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
         unregister() {
             this.ctx.customModelProperties.unregister(StructureQualityReport.Descriptor.name);
             this.ctx.lociLabels.removeProvider(labelPDBeValidation);
+
+            // TODO: add remove functionality to registry
+            // this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove('pdbe-structure-quality-report')
         }
     },
     params: () => ({
-        autoAttach: ParamDefinition.Boolean(false)
+        autoAttach: PD.Boolean(false)
     }),
     display: { name: 'Focus Loci on Select', group: 'Camera' }
 });

+ 31 - 14
src/mol-plugin/state/actions/basic.ts

@@ -27,10 +27,23 @@ const DownloadStructure = StateAction.build({
     display: { name: 'Download Structure', description: 'Load a structure from the provided source and create its default Assembly and visual.' },
     params: {
         source: PD.MappedStatic('bcif-static', {
-            'pdbe-updated': PD.Text('1cbs', { label: 'Id' }),
-            'rcsb': PD.Text('1tqn', { label: 'Id' }),
-            'bcif-static': PD.Text('1tqn', { label: 'Id' }),
-            'url': PD.Group({ url: PD.Text(''), isBinary: PD.Boolean(false) }, { isExpanded: true })
+            'pdbe-updated': PD.Group({
+                id: PD.Text('1cbs', { label: 'Id' }),
+                supportProps: PD.Boolean(false)
+            }, { isExpanded: true }),
+            'rcsb': PD.Group({
+                id: PD.Text('1tqn', { label: 'Id' }),
+                supportProps: PD.Boolean(false)
+            }, { isExpanded: true }),
+            'bcif-static': PD.Group({
+                id: PD.Text('1tqn', { label: 'Id' }),
+                supportProps: PD.Boolean(false)
+            }, { isExpanded: true }),
+            'url': PD.Group({
+                url: PD.Text(''),
+                isBinary: PD.Boolean(false),
+                supportProps: PD.Boolean(false)
+            }, { isExpanded: true })
         }, {
             options: [
                 ['pdbe-updated', 'PDBe Updated'],
@@ -50,19 +63,19 @@ const DownloadStructure = StateAction.build({
             url = src.params;
             break;
         case 'pdbe-updated':
-            url = { url: `https://www.ebi.ac.uk/pdbe/static/entry/${src.params.toLowerCase()}_updated.cif`, isBinary: false, label: `PDBe: ${src.params}` };
+            url = { url: `https://www.ebi.ac.uk/pdbe/static/entry/${src.params.id.toLowerCase()}_updated.cif`, isBinary: false, label: `PDBe: ${src.params}` };
             break;
         case 'rcsb':
-            url = { url: `https://files.rcsb.org/download/${src.params.toUpperCase()}.cif`, isBinary: false, label: `RCSB: ${src.params}` };
+            url = { url: `https://files.rcsb.org/download/${src.params.id.toUpperCase()}.cif`, isBinary: false, label: `RCSB: ${src.params}` };
             break;
         case 'bcif-static':
-            url = { url: `https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${src.params.toLowerCase()}`, isBinary: true, label: `BinaryCIF: ${src.params}` };
+            url = { url: `https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${src.params.id.toLowerCase()}`, isBinary: true, label: `BinaryCIF: ${src.params}` };
             break;
         default: throw new Error(`${(src as any).name} not supported.`);
     }
 
     const data = b.toRoot().apply(StateTransforms.Data.Download, url);
-    return state.update(createStructureTree(data));
+    return state.update(createStructureTree(data, params.source.params.supportProps));
 });
 
 export const OpenStructure = StateAction.build({
@@ -72,16 +85,20 @@ export const OpenStructure = StateAction.build({
 })(({ params, state }) => {
     const b = state.build();
     const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) });
-    return state.update(createStructureTree(data));
+    return state.update(createStructureTree(data, false));
 });
 
-function createStructureTree(b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>): StateTree {
-    const root = b
+function createStructureTree(b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, supportProps: boolean): StateTree {
+    let root = b
         .apply(StateTransforms.Data.ParseCif)
         .apply(StateTransforms.Model.TrajectoryFromMmCif, {})
-        .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
-        .apply(StateTransforms.Model.CustomModelProperties, { properties: [] })
-        .apply(StateTransforms.Model.StructureAssemblyFromModel);
+        .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 });
+
+    if (supportProps) {
+        // TODO: implement automatic default property assigment in State.update
+        root = root.apply(StateTransforms.Model.CustomModelProperties, { properties: [] });
+    }
+    root = root.apply(StateTransforms.Model.StructureAssemblyFromModel);
 
     complexRepresentation(root);
 

+ 1 - 1
src/mol-plugin/state/transforms/model.ts

@@ -180,7 +180,7 @@ const CustomModelProperties = PluginStateTransform.BuiltIn({
     apply({ a, params }, ctx: PluginContext) {
         return Task.create('Custom Props', async taskCtx => {
             await attachProps(a.data, ctx, taskCtx, params.properties);
-            return new SO.Molecule.Model(a.data, { label: a.label, description: 'Custom Props' });
+            return new SO.Molecule.Model(a.data, { label: 'Props', description: `${params.properties.length} Selected` });
         });
     }
 });

+ 1 - 1
src/mol-plugin/ui/controls.tsx

@@ -45,7 +45,7 @@ export class LociLabelControl extends PluginComponent<{}, { entries: ReadonlyArr
     }
 
     render() {
-        return <div>
+        return <div style={{ textAlign: 'right' }}>
             {this.state.entries.map((e, i) => <div key={'' + i}>{e}</div>)}
         </div>
     }