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

pdbe validation color theme

parent 64276543
No related branches found
No related tags found
No related merge requests found
/**
* 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)
}
}
\ No newline at end of file
......@@ -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' }
});
......
......@@ -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);
......
......@@ -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` });
});
}
});
......
......@@ -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>
}
......
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