diff --git a/src/extensions/dnatco/confal-pyramids/behavior.ts b/src/extensions/dnatco/confal-pyramids/behavior.ts index 6293e2b6cd60b8710dd2c0c3f68ea074980b2b52..7c34704ae344e745aa3ad5b0e0fc948d199dd588 100644 --- a/src/extensions/dnatco/confal-pyramids/behavior.ts +++ b/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)} + `; +} diff --git a/src/extensions/dnatco/confal-pyramids/color.ts b/src/extensions/dnatco/confal-pyramids/color.ts index 8bc71f0f37a411013cb26c629561cf44aa1192dc..1cf4ad87052d33ce98c58c19fe73c39bc8f08726 100644 --- a/src/extensions/dnatco/confal-pyramids/color.ts +++ b/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; } diff --git a/src/extensions/dnatco/confal-pyramids/property.ts b/src/extensions/dnatco/confal-pyramids/property.ts index 4417ebbc18816abdf6cd7fece1af9077b7d88574..dc141990ba2db5304821a795ac5ceaa494df05f8 100644 --- a/src/extensions/dnatco/confal-pyramids/property.ts +++ b/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'); } diff --git a/src/extensions/dnatco/confal-pyramids/representation.ts b/src/extensions/dnatco/confal-pyramids/representation.ts index b0ce90b53e355ad33fcf2379bbe4445949868ed8..d8194e8b4b37b8fbbb99817feed798cb31053ca3 100644 --- a/src/extensions/dnatco/confal-pyramids/representation.ts +++ b/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) { diff --git a/src/extensions/dnatco/confal-pyramids/types.ts b/src/extensions/dnatco/confal-pyramids/types.ts index b7a94099885cb2aa5e37094cb6bb100c355b2392..0e59626927f632392491125ad3f6452bf93aa809 100644 --- a/src/extensions/dnatco/confal-pyramids/types.ts +++ b/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; } } diff --git a/src/extensions/dnatco/confal-pyramids/util.ts b/src/extensions/dnatco/confal-pyramids/util.ts index 467734af416ccba7b34fdf65e64b3e80abf30535..698a34e6d83fe295da1ce6454d788905be90e864 100644 --- a/src/extensions/dnatco/confal-pyramids/util.ts +++ b/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; }