Sfoglia il codice sorgente

Add labels for Confal pyramids

Michal Malý 2 anni fa
parent
commit
6fec598b96

+ 11 - 13
src/extensions/dnatco/confal-pyramids/behavior.ts

@@ -8,7 +8,7 @@
 import { ConfalPyramidsColorThemeProvider } from './color';
 import { ConfalPyramids, ConfalPyramidsProvider } from './property';
 import { ConfalPyramidsRepresentationProvider } from './representation';
-import { Loci } from '../../../mol-model/loci';
+import { ConfalPyramidsTypes } from './types';
 import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
 import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../../mol-plugin-state/builder/structure/representation-preset';
 import { StateObjectRef } from '../../../mol-state';
@@ -56,21 +56,10 @@ export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean,
         description: 'Schematic depiction of conformer class and confal value.',
     },
     ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showToolTip: boolean }> {
-
         private provider = ConfalPyramidsProvider;
 
-        private labelConfalPyramids = {
-            label: (loci: Loci): string | undefined => {
-                if (!this.params.showToolTip) return void 0;
-
-                /* TODO: Implement this */
-                return void 0;
-            }
-        };
-
         register(): void {
             this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
-            this.ctx.managers.lociLabels.addProvider(this.labelConfalPyramids);
 
             this.ctx.representation.structure.themes.colorThemeRegistry.add(ConfalPyramidsColorThemeProvider);
             this.ctx.representation.structure.registry.add(ConfalPyramidsRepresentationProvider);
@@ -88,7 +77,6 @@ export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean,
 
         unregister() {
             this.ctx.customModelProperties.unregister(ConfalPyramidsProvider.descriptor.name);
-            this.ctx.managers.lociLabels.removeProvider(this.labelConfalPyramids);
 
             this.ctx.representation.structure.registry.remove(ConfalPyramidsRepresentationProvider);
             this.ctx.representation.structure.themes.colorThemeRegistry.remove(ConfalPyramidsColorThemeProvider);
@@ -101,3 +89,13 @@ export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean,
         showToolTip: PD.Boolean(true)
     })
 });
+
+export function confalPyramidLabel(halfPyramid: ConfalPyramidsTypes.HalfPyramid) {
+    const { step } = halfPyramid;
+    return `
+        <b>${step.auth_asym_id_1}</b> |
+        <b>${step.label_comp_id_1} ${step.auth_seq_id_1}${step.PDB_ins_code_1}${step.label_alt_id_1.length > 0 ? ` (alt ${step.label_alt_id_1})` : ''}
+           ${step.label_comp_id_2} ${step.auth_seq_id_2}${step.PDB_ins_code_2}${step.label_alt_id_2.length > 0 ? ` (alt ${step.label_alt_id_2})` : ''} </b><br />
+        <i>NtC:</i> ${step.NtC} | <i>Confal score:</i> ${step.confal_score} | <i>RMSD:</i> ${step.rmsd.toFixed(2)}
+    `;
+}

+ 2 - 2
src/extensions/dnatco/confal-pyramids/color.ts

@@ -247,8 +247,8 @@ export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values
 
     function color(location: Location, isSecondary: boolean): Color {
         if (CPT.isLocation(location)) {
-            const { pyramid, isLower } = location.data;
-            const key = pyramid.NtC + `_${isLower ? 'Lwr' : 'Upr'}` as keyof PyramidsColors;
+            const { step, isLower } = location.data;
+            const key = step.NtC + `_${isLower ? 'Lwr' : 'Upr'}` as keyof PyramidsColors;
             return colorMap[key] ?? ErrorColor;
         }
 

+ 30 - 19
src/extensions/dnatco/confal-pyramids/property.ts

@@ -16,7 +16,7 @@ import { PropertyWrapper } from '../../../mol-model-props/common/wrapper';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
 
-export type ConfalPyramids = PropertyWrapper<CPT.PyramidsData | undefined >;
+export type ConfalPyramids = PropertyWrapper<CPT.StepsData | undefined>;
 
 export namespace ConfalPyramids {
     export const Schema = {
@@ -106,18 +106,19 @@ export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramids
 type StepsSummaryTable = Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step_summary>;
 
 function createPyramidsFromCif(model: Model,
-    steps: Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step>,
-    stepsSummary: StepsSummaryTable): CPT.PyramidsData {
-    const pyramids = new Array<CPT.Pyramid>();
+    cifSteps: Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step>,
+    stepsSummary: StepsSummaryTable): CPT.StepsData {
+    const steps = new Array<CPT.Step>();
     const names = new Map<string, number>();
-    const locations = new Array<CPT.Location>();
+    const halfPyramids = new Array<CPT.HalfPyramid>();
     let hasMultipleModels = false;
 
     const {
         id, PDB_model_number, name,
         auth_asym_id_1, auth_seq_id_1, label_comp_id_1, label_alt_id_1, PDB_ins_code_1,
         auth_asym_id_2, auth_seq_id_2, label_comp_id_2, label_alt_id_2, PDB_ins_code_2,
-        _rowCount } = steps;
+        _rowCount
+    } = cifSteps;
 
     if (_rowCount !== stepsSummary._rowCount) throw new Error('Inconsistent mmCIF data');
 
@@ -126,9 +127,13 @@ function createPyramidsFromCif(model: Model,
         if (model_num !== model.modelNum)
             hasMultipleModels = true;
 
-        const { _NtC, _confal_score } = getNtCAndConfalScore(id.value(i), i, stepsSummary);
+        const {
+            NtC,
+            confal_score,
+            rmsd
+        } = getSummaryData(id.value(i), i, stepsSummary);
 
-        const pyramid = {
+        const step = {
             PDB_model_number: model_num,
             name: name.value(i),
             auth_asym_id_1: auth_asym_id_1.value(i),
@@ -141,30 +146,36 @@ function createPyramidsFromCif(model: Model,
             label_comp_id_2: label_comp_id_2.value(i),
             label_alt_id_2: label_alt_id_2.value(i),
             PDB_ins_code_2: PDB_ins_code_2.value(i),
-            confal_score: _confal_score,
-            NtC: _NtC
+            confal_score,
+            NtC,
+            rmsd,
         };
 
-        pyramids.push(pyramid);
-        names.set(pyramid.name, pyramids.length - 1);
+        steps.push(step);
+        names.set(step.name, steps.length - 1);
 
-        locations.push(CPT.Location(pyramid, false));
-        locations.push(CPT.Location(pyramid, true));
+        halfPyramids.push({ step, isLower: false });
+        halfPyramids.push({ step, isLower: true });
     }
 
-    return { pyramids, names, locations, hasMultipleModels };
+    return { steps, names, halfPyramids, hasMultipleModels };
 }
 
-function getNtCAndConfalScore(id: number, i: number, stepsSummary: StepsSummaryTable) {
-    const { step_id, confal_score, assigned_NtC } = stepsSummary;
+function getSummaryData(id: number, i: number, stepsSummary: StepsSummaryTable) {
+    const {
+        step_id,
+        confal_score,
+        assigned_NtC,
+        cartesian_rmsd_closest_NtC_representative,
+    } = stepsSummary;
 
     // Assume that step_ids in ntc_step_summary are in the same order as steps in ntc_step
     for (let j = i; j < stepsSummary._rowCount; j++) {
-        if (id === step_id.value(j)) return { _NtC: assigned_NtC.value(j), _confal_score: confal_score.value(j) };
+        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
     }
     // Safety net for cases where the previous assumption is not met
     for (let j = 0; j < i; j++) {
-        if (id === step_id.value(j)) return { _NtC: assigned_NtC.value(j), _confal_score: confal_score.value(j) };
+        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
     }
     throw new Error('Inconsistent mmCIF data');
 }

+ 14 - 15
src/extensions/dnatco/confal-pyramids/representation.ts

@@ -16,14 +16,14 @@ import { PrimitiveBuilder } from '../../../mol-geo/primitive/primitive';
 import { LocationIterator } from '../../../mol-geo/util/location-iterator';
 import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
 import { EmptyLoci, Loci } from '../../../mol-model/loci';
-import { Structure, StructureProperties, Unit } from '../../../mol-model/structure';
+import { Structure, Unit } from '../../../mol-model/structure';
 import { CustomProperty } from '../../../mol-model-props/common/custom-property';
 import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../../mol-repr/representation';
 import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder, UnitsRepresentation } from '../../../mol-repr/structure/representation';
 import { UnitsMeshParams, UnitsMeshVisual, UnitsVisual } from '../../../mol-repr/structure/units-visual';
 import { VisualUpdateState } from '../../../mol-repr/util';
 import { VisualContext } from '../../../mol-repr/visual';
-import { getAltResidueLociFromId, StructureGroup } from '../../../mol-repr/structure/visual/util/common';
+import { StructureGroup } from '../../../mol-repr/structure/visual/util/common';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { Theme, ThemeRegistryContext } from '../../../mol-theme/theme';
 import { NullLocation } from '../../../mol-model/location';
@@ -58,13 +58,13 @@ function createConfalPyramidsIterator(structureGroup: StructureGroup): LocationI
         return LocationIterator(0, 1, 1, () => NullLocation);
     }
 
-    const { locations } = prop.data;
+    const { halfPyramids } = prop.data;
 
     const getLocation = (groupIndex: number, instanceIndex: number) => {
-        if (locations.length <= groupIndex) return NullLocation;
-        return locations[groupIndex];
+        if (halfPyramids.length <= groupIndex) return NullLocation;
+        return CPT.Location(halfPyramids[groupIndex]);
     };
-    return LocationIterator(locations.length, instanceCount, 1, getLocation);
+    return LocationIterator(halfPyramids.length, instanceCount, 1, getLocation);
 }
 
 function createConfalPyramidsMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<ConfalPyramidsMeshParams>, mesh?: Mesh) {
@@ -73,16 +73,16 @@ function createConfalPyramidsMesh(ctx: VisualContext, unit: Unit, structure: Str
     const prop = ConfalPyramidsProvider.get(structure.model).value;
     if (prop === undefined || prop.data === undefined) return Mesh.createEmpty(mesh);
 
-    const { pyramids } = prop.data;
-    if (pyramids.length === 0) return Mesh.createEmpty(mesh);
+    const { steps } = prop.data;
+    if (steps.length === 0) return Mesh.createEmpty(mesh);
 
     const mb = MeshBuilder.createState(512, 512, mesh);
 
-    const handler = (pyramid: CPT.Pyramid, first: ConfalPyramidsUtil.FirstResidueAtoms, second: ConfalPyramidsUtil.SecondResidueAtoms, firsLocIndex: number, secondLocIndex: number) => {
+    const handler = (step: CPT.Step, first: ConfalPyramidsUtil.FirstResidueAtoms, second: ConfalPyramidsUtil.SecondResidueAtoms, firsLocIndex: number, secondLocIndex: number) => {
         if (firsLocIndex === -1 || secondLocIndex === -1)
             throw new Error('Invalid location index');
 
-        const scale = (pyramid.confal_score - 20.0) / 100.0;
+        const scale = (step.confal_score - 20.0) / 100.0;
         const O3 = first.O3.pos;
         const OP1 = second.OP1.pos; const OP2 = second.OP2.pos; const O5 = second.O5.pos; const P = second.P.pos;
 
@@ -127,13 +127,12 @@ function getConfalPyramidLoci(pickingId: PickingId, structureGroup: StructureGro
     const prop = ConfalPyramidsProvider.get(structure.model).value;
     if (prop === undefined || prop.data === undefined) return EmptyLoci;
 
-    const { locations } = prop.data;
+    const { halfPyramids } = prop.data;
 
-    if (locations.length <= groupId) return EmptyLoci;
-    const altId = StructureProperties.atom.label_alt_id(CPT.toElementLocation(locations[groupId]));
-    const rI = unit.residueIndex[locations[groupId].element.element];
+    if (halfPyramids.length <= groupId) return EmptyLoci;
+    const hp = halfPyramids[groupId];
 
-    return getAltResidueLociFromId(structure, unit, rI, altId);
+    return CPT.Loci(hp, [{}]);
 }
 
 function eachConfalPyramid(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {

+ 25 - 21
src/extensions/dnatco/confal-pyramids/types.ts

@@ -6,10 +6,13 @@
  */
 
 import { DataLocation } from '../../../mol-model/location';
-import { ElementIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
+import { DataLoci } from '../../../mol-model/loci';
+import { confalPyramidLabel } from './behavior';
 
 export namespace ConfalPyramidsTypes {
-    export type Pyramid = {
+    export const DataTag = 'dnatco-confal-half-pyramid';
+
+    export type Step = {
         PDB_model_number: number,
         name: string,
         auth_asym_id_1: string,
@@ -23,38 +26,39 @@ export namespace ConfalPyramidsTypes {
         label_alt_id_2: string,
         PDB_ins_code_2: string,
         confal_score: number,
-        NtC: string
+        NtC: string,
+        rmsd: number,
     }
 
-    export interface PyramidsData {
-        pyramids: Array<Pyramid>,
+    export interface StepsData {
+        steps: Array<Step>,
         names: Map<string, number>,
-        locations: Array<Location>,
+        halfPyramids: Array<HalfPyramid>,
         hasMultipleModels: boolean
     }
 
-    export interface LocationData {
-        readonly pyramid: Pyramid
-        readonly isLower: boolean;
-    }
-
-    export interface Element {
-        structure: Structure;
-        unit: Unit.Atomic;
-        element: ElementIndex;
+    export interface HalfPyramid {
+        step: Step,
+        isLower: boolean,
     }
 
-    export interface Location extends DataLocation<LocationData, Element> {}
+    export interface Location extends DataLocation<HalfPyramid, {}> {}
 
-    export function Location(pyramid: Pyramid, isLower: boolean, structure?: Structure, unit?: Unit.Atomic, element?: ElementIndex) {
-        return DataLocation('pyramid', { pyramid, isLower }, { structure: structure as any, unit: unit as any, element: element as any });
+    export function Location(halfPyramid: HalfPyramid) {
+        return DataLocation(DataTag, halfPyramid, {});
     }
 
     export function isLocation(x: any): x is Location {
-        return !!x && x.kind === 'data-location' && x.tag === 'pyramid';
+        return !!x && x.kind === 'data-location' && x.tag === DataTag;
+    }
+
+    export interface Loci extends DataLoci<HalfPyramid, {}> {}
+
+    export function Loci(data: HalfPyramid, elements: ReadonlyArray<{}>): Loci {
+        return DataLoci(DataTag, data, elements, undefined, () => confalPyramidLabel(data));
     }
 
-    export function toElementLocation(location: Location) {
-        return StructureElement.Location.create(location.element.structure, location.element.unit, location.element.element);
+    export function isLoci(x: any): x is Loci {
+        return !!x && x.kind === 'data-loci' && x.tag === DataTag;
     }
 }

+ 4 - 12
src/extensions/dnatco/confal-pyramids/util.ts

@@ -42,7 +42,7 @@ export namespace ConfalPyramidsUtil {
         ins_code: string,
     };
 
-    export type Handler = (pyramid: CPT.Pyramid, first: FirstResidueAtoms, second: SecondResidueAtoms, firstLocIndex: number, secondLocIndex: number) => void;
+    export type Handler = (pyramid: CPT.Step, first: FirstResidueAtoms, second: SecondResidueAtoms, firstLocIndex: number, secondLocIndex: number) => void;
 
     function residueInfoFromLocation(loc: StructureElement.Location): ResidueInfo {
         return {
@@ -77,11 +77,11 @@ export namespace ConfalPyramidsUtil {
     }
 
     class Utility {
-        protected getPyramidByName(name: string): { pyramid: CPT.Pyramid | undefined, index: number } {
+        protected getPyramidByName(name: string): { pyramid: CPT.Step | undefined, index: number } {
             const index = this.data.names.get(name);
             if (index === undefined) return { pyramid: undefined, index: -1 };
 
-            return { pyramid: this.data.pyramids[index], index };
+            return { pyramid: this.data.steps[index], index };
         }
 
         protected stepToName(entry_id: string, modelNum: number, locFirst: StructureElement.Location, locSecond: StructureElement.Location, fakeAltId_1: string, fakeAltId_2: string) {
@@ -107,7 +107,7 @@ export namespace ConfalPyramidsUtil {
             this.modelNum = unit.model.modelNum;
         }
 
-        protected readonly data: CPT.PyramidsData;
+        protected readonly data: CPT.StepsData;
         protected readonly hasMultipleModels: boolean;
         protected readonly entryId: string;
         protected readonly modelNum: number;
@@ -164,15 +164,7 @@ export namespace ConfalPyramidsUtil {
                     const name = this.stepToName(this.entryId, modelNum, firstLoc, secondLoc, first.O3.fakeAltId, second.OP1.fakeAltId);
                     const { pyramid, index } = this.getPyramidByName(name);
                     if (pyramid !== undefined) {
-                        const setLoc = (loc: CPT.Location, eI: ElementIndex) => {
-                            loc.element.structure = this.structure;
-                            loc.element.unit = this.unit;
-                            loc.element.element = eI;
-                        };
-
                         const locIndex = index * 2;
-                        setLoc(this.data.locations[locIndex], firstLoc.element);
-                        setLoc(this.data.locations[locIndex + 1], secondLoc.element);
                         this.handler(pyramid, first, second, locIndex, locIndex + 1);
                         ok = true;
                     }