|
| 1 | +import { CustomLabelProps, CustomLabelRepresentationProvider } from 'molstar/lib/extensions/mvs/components/custom-label/representation'; |
| 2 | +import { MVSBuildPrimitiveShape, MVSInlinePrimitiveData, MVSShapeRepresentation3D } from 'molstar/lib/extensions/mvs/components/primitives'; |
| 3 | +import { Selector } from 'molstar/lib/extensions/mvs/components/selector'; |
| 4 | +import { MVSNode } from 'molstar/lib/extensions/mvs/tree/mvs/mvs-tree'; |
| 5 | +import { ComponentExpressionT } from 'molstar/lib/extensions/mvs/tree/mvs/param-types'; |
1 | 6 | import { Sphere3D } from 'molstar/lib/mol-math/geometry'; |
2 | 7 | import { EPSILON, Mat3, Vec3 } from 'molstar/lib/mol-math/linear-algebra'; |
3 | 8 | import { MinimizeRmsd } from 'molstar/lib/mol-math/linear-algebra/3d/minimize-rmsd'; |
4 | 9 | import { MmcifFormat } from 'molstar/lib/mol-model-formats/structure/mmcif'; |
5 | | -import { Structure, StructureQuery, StructureSelection } from 'molstar/lib/mol-model/structure'; |
| 10 | +import { Structure, StructureElement, StructureQuery, StructureSelection } from 'molstar/lib/mol-model/structure'; |
6 | 11 | import { TraceAtoms } from 'molstar/lib/mol-model/structure/model/types'; |
7 | 12 | import { changeCameraRotation } from 'molstar/lib/mol-plugin-state/manager/focus-camera/orient-axes'; |
8 | 13 | import { StructureRef } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy-state'; |
9 | | -import { Download, ParseCif, RawData } from 'molstar/lib/mol-plugin-state/transforms/data'; |
| 14 | +import { Download, ParseCif } from 'molstar/lib/mol-plugin-state/transforms/data'; |
10 | 15 | import { CreateGroup } from 'molstar/lib/mol-plugin-state/transforms/misc'; |
11 | | -import { ModelFromTrajectory, StructureFromModel, TrajectoryFromMmCif } from 'molstar/lib/mol-plugin-state/transforms/model'; |
| 16 | +import { CustomModelProperties, ModelFromTrajectory, StructureFromModel, TrajectoryFromMmCif } from 'molstar/lib/mol-plugin-state/transforms/model'; |
12 | 17 | import { OverpaintStructureRepresentation3DFromScript, StructureRepresentation3D } from 'molstar/lib/mol-plugin-state/transforms/representation'; |
13 | 18 | import { setSubtreeVisibility } from 'molstar/lib/mol-plugin/behavior/static/state'; |
14 | 19 | import { PluginCommands } from 'molstar/lib/mol-plugin/commands'; |
@@ -86,6 +91,8 @@ function doMagic(viewer: PDBeMolstarPlugin, bsData: BindingSitesData, bindingSit |
86 | 91 | const reprBsCoords = extractTraceCoordsByUniprot(reprBsStruct, uniprotId, bsResidues); |
87 | 92 | console.timeEnd('load representative structure') |
88 | 93 |
|
| 94 | + await addBsLabels(viewer.plugin, viewer.getStructure(REPRESENTATIVE_STRUCT_ID)!, { bindingSiteId, uniprot_accession: uniprotId, uniprot_residue_numbers: bsResidues, auth_asym_id: representativePdbAuthAsymId }); |
| 95 | + |
89 | 96 | console.time('load&superpose all') |
90 | 97 | const ligandsToSuperpose = bsData[bindingSiteId].ligands.slice(0, DEBUG_LIGAND_COUNT_LIMIT); |
91 | 98 | for (const ligandBatch of divideToBatches(ligandsToSuperpose, LIGAND_BATCH_SIZE)) { |
@@ -300,3 +307,100 @@ function divideToBatches<T>(jobs: T[], batchSize: number = Infinity) { |
300 | 307 | } |
301 | 308 | return out; |
302 | 309 | } |
| 310 | + |
| 311 | +async function addBsLabels(plugin: PluginContext, structRef: StructureRef, params: { bindingSiteId: string, auth_asym_id: string, uniprot_accession: string, uniprot_residue_numbers: Iterable<number> }) { |
| 312 | + // Binding site label |
| 313 | + await addLabels( |
| 314 | + plugin, |
| 315 | + structRef, |
| 316 | + [{ |
| 317 | + text: `Binding site ${params.bindingSiteId}`, |
| 318 | + selector: Array.from(params.uniprot_residue_numbers).map(res => ({ |
| 319 | + auth_asym_id: params.auth_asym_id, |
| 320 | + uniprot_accession: params.uniprot_accession, |
| 321 | + uniprot_residue_number: res, |
| 322 | + })), |
| 323 | + }], |
| 324 | + { |
| 325 | + sizeFactor: 0.9, |
| 326 | + attachment: 'bottom-center', |
| 327 | + tether: true, |
| 328 | + tetherLength: 1, |
| 329 | + backgroundColor: ColorNames.yellow, |
| 330 | + } |
| 331 | + ); |
| 332 | + |
| 333 | + // Residue labels |
| 334 | + await addLabels( |
| 335 | + plugin, |
| 336 | + structRef, |
| 337 | + Array.from(params.uniprot_residue_numbers).map(res => ({ |
| 338 | + text: `${res}`, |
| 339 | + selector: [{ |
| 340 | + auth_asym_id: params.auth_asym_id, |
| 341 | + uniprot_accession: params.uniprot_accession, |
| 342 | + uniprot_residue_number: res, |
| 343 | + }], |
| 344 | + })), |
| 345 | + { |
| 346 | + sizeFactor: 0.9, |
| 347 | + } |
| 348 | + ); |
| 349 | + |
| 350 | + // await addLabelsPrimitives(plugin, structRef, [{ text: 'Bar', selector: [{}] }]); |
| 351 | +} |
| 352 | + |
| 353 | +async function addLabels(plugin: PluginContext, structRef: StructureRef, labels: { text: string, selector: QueryParam[] }[], props: Partial<Omit<CustomLabelProps, 'items'>> = {}) { |
| 354 | + const modelProps = structRef.model?.properties?.cell; |
| 355 | + if (modelProps && !modelProps.params?.values.properties?.['mvs-is-mvs-model']?.isMvs) { |
| 356 | + await plugin.build().to(modelProps).update(CustomModelProperties, old => ({ |
| 357 | + ...old, |
| 358 | + properties: { |
| 359 | + ...old.properties, |
| 360 | + 'mvs-is-mvs-model': { isMvs: true }, |
| 361 | + }, |
| 362 | + })).commit(); |
| 363 | + } |
| 364 | + |
| 365 | + const struct = structRef.cell.obj?.data; |
| 366 | + if (!struct) throw new Error(`Failed to get structure for displaying labels`); |
| 367 | + |
| 368 | + const bundles = labels.map(({ text, selector }) => ({ text, bundle: StructureElement.Bundle.fromSelection(StructureQuery.run(QueryHelper.getQueryObject(selector, struct), struct)) })); |
| 369 | + |
| 370 | + await plugin.build() |
| 371 | + .to(structRef.cell) |
| 372 | + .apply(StructureRepresentation3D, { |
| 373 | + type: { |
| 374 | + name: CustomLabelRepresentationProvider.name, |
| 375 | + params: { |
| 376 | + ...props, |
| 377 | + items: bundles.map(({ text, bundle }) => ({ |
| 378 | + text: text, |
| 379 | + position: { name: 'selection', params: { selector: { name: 'bundle', params: bundle } satisfies Selector } }, |
| 380 | + })), |
| 381 | + } satisfies Partial<CustomLabelProps>, |
| 382 | + }, |
| 383 | + }) |
| 384 | + .commit(); |
| 385 | +} |
| 386 | + |
| 387 | +async function addLabelsPrimitives(plugin: PluginContext, structRef: StructureRef, labels: { text: string, selector: ComponentExpressionT[] }[]) { |
| 388 | + const struct = structRef.cell.obj?.data; |
| 389 | + if (!struct) throw new Error(`Failed to get structure for displaying labels`); |
| 390 | + |
| 391 | + await plugin.build() |
| 392 | + .to(structRef.cell) |
| 393 | + .apply(MVSInlinePrimitiveData, { |
| 394 | + node: { |
| 395 | + kind: 'primitives', |
| 396 | + params: {} as any, |
| 397 | + children: labels.map(label => ({ |
| 398 | + kind: 'primitive', |
| 399 | + params: { kind: 'label', text: label.text, position: { expressions: label.selector }, label_color: 'white', label_offset: 0, label_size: 2 }, |
| 400 | + } satisfies MVSNode<'primitive'>)), |
| 401 | + }, |
| 402 | + }) |
| 403 | + .apply(MVSBuildPrimitiveShape, { kind: 'labels' }) |
| 404 | + .apply(MVSShapeRepresentation3D, {}) |
| 405 | + .commit(); |
| 406 | +} |
0 commit comments