molstar / molstar

A comprehensive macromolecular library

Home Page:https://molstar.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wondering if `superpose` should be able to handle chains longer than 100-200 residues?

rtviii opened this issue · comments

export function dynamicSuperimpose(ctx: PluginContext,pivot_auth_asym_id: string ) {
    return ctx.dataTransaction(async () => {
        const pivot = MS.struct.filter.first([
            MS.struct.generator.atomGroups({
                'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), pivot_auth_asym_id])
            })
        ]);
        const query         = compile<StructureSelection>(pivot);
        const structureRefs = ctx.managers.structure.hierarchy.current.structures;
        const selections    = structureRefs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.cell.obj!.data))));
        const transforms    = superpose(selections);

        console.log("Got transforms", transforms);
        await siteVisual(ctx, structureRefs[0].cell, pivot)

        for (let i = 1; i < selections.length; i++) {
            await transform(ctx, structureRefs[i].cell, transforms[i - 1].bTransform);
            await siteVisual(ctx, structureRefs[i].cell, pivot)
        }
    });
}

I'm going off the basic wrapper superposition example, of course.

My use case is pre-loading multiple similar protein chains into the viewer and trying to superimpose them. I'm getting pretty underwhelming results, which i'm wondering if that's just the limitation of the javascript linalg library.

A concrete example: i loaded mmcif chains "3AFI.E" and "5AFI.E" into the viewer and trying to run the logic above, but they barely aligned (see pics)

This is what the superpose returns in terms of transforms:

Array [ {…} ]
0: Object { bTransform: (16) […], rmsd: 0.7684224265900069 }
bTransform: Array(16) [ 0.15389930902561844, 0.9016882661254453, 0.4040706705222181, … ]
​0: 0.15389930902561844
​​​1: 0.9016882661254453
​​​2: 0.4040706705222181
​​​3: 0
​​​4: -0.6232907734541886
​​​5: 0.405907098142936
​​​6: -0.6683920424416687
​​​7: 0
​​​8: -0.7666964508666165
​​​9: -0.1489885277602081
​​​10: 0.6244829035830182
​​​11: 0
​​​12: 369.24723345810753
​​​13: -16.299677972091786
​​​14: 160.57300536943566
​​​15: 1
​​​length: 16
​​​<prototype>: Array []
​​rmsd: 0.7684224265900069
​​<prototype>: Object { … }
​length: 1

Okay, at least this seems like it has an attempt at alignment and an rmsd value.

If i try some slightly more dissimilar chains or three+ chains at a time, it returns an "identity" 4x4 Mat and null rmsd. Here is a result for trying 7K00.e and 5AFI.E:

Got transforms 
Array [ {…} ]
​0: Object { bTransform: (16) […], rmsd: NaN }
​​bTransform: Array(16) [ -1, 0, 0, … ]
​​​0: -1
​​​1: 0
​​​2: 0
​​​3: 0
​​​4: 0
​​​5: -1
​​​6: 0
​​​7: 0
​​​8: 0
​​​9: 0
​​​10: 1
​​​11: 0
​​​12: 0
​​​13: 0
​​​14: 0
​​​15: 1
​​​length: 16
​​​<prototype>: Array []
​​rmsd: NaN
​​<prototype>: Object { … }
​length: 1
​<prototype>: Array []

Am i doing something drastically wrong or should i just give up on the idea of doing this in the browser?
Thanks in advance.

I think for this to work better, we would need to implement some sequence alignment as well to determine which residues should be paired together.

The reason you are getting NaN is a bug in the code where it expects the first chain to be longer than the second. I've hopefully fixed that here #1138

Thanks a ton, David, I was just whipping up a chimerax backed instead. I'll try this as soon as it's merged.

I realize this might be a tricky ask in the browser so i'm just reporting back that after the 4.3 Molstar release the situation is not much different from before with dynamic superpose:
the superposees just jump around the pivot with unary matrices for bTransforms and NaN rmsds.

ᢹ rtviii [dev/ribxz_front] yarn list  | grep molstar
├─ molstar@4.3.0

My superpose code is taken from source:

 private async siteVisual( s: StateObjectRef<PSO.Molecule.Structure>, pivot: Expression, ) {
    const center = await this.ctx.builders.structure.tryCreateComponentFromExpression(s, pivot, 'pivot');
    if (center) await    this.ctx.builders.structure.representation.addRepresentation(center, { type: 'ball-and-stick', color: 'residue-name' });
    }

private transform( s: StateObjectRef<PSO.Molecule.Structure>, matrix: Mat4) {
    const b = this.ctx.state.data.build().to(s).insert(StateTransforms.Model.TransformStructureConformation, { transform: { name: 'matrix', params: { data: matrix, transpose: false } } });
    return    this.ctx.runTask(this.ctx.state.data.updateTree(b));
}

dynamicSuperimpose(pivot_auth_asym_id: string ) {
    return this.ctx.dataTransaction(async () => {
            const pivot = MS.struct.filter.first([
            MS.struct.generator.atomGroups({
                'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), pivot_auth_asym_id]),
                'group-by'  : MS.struct.atomProperty.macromolecular.residueKey()
            })
        ]);

        const query         = compile<StructureSelection>(pivot);
        const structureRefs = this.ctx.managers.structure.hierarchy.current.structures;
        const selections    = structureRefs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.cell.obj!.data))));
        const transforms    = superpose(selections);
        console.log({...transforms});
        
        await this.siteVisual( structureRefs[0].cell, pivot)

        for (let i = 1; i < selections.length; i++) {
            await this.transform( structureRefs[i].cell, transforms[i - 1].bTransform);
            await this.siteVisual( structureRefs[i].cell, pivot)
        }
    });
}

And my example models are 4UG0.LC, 7K00.e and 4V6X.CC...

Before

After

The const transforms = superpose(selections);log({...transforms}); logs the following:

{
  "bTransform": [
    -1,
    0,
    0,
    0,
    0,
    -1,
    0,
    0,
    0,
    0,
    1,
    0,
    0,
    0,
    0,
    1
  ],
  "rmsd": null
},
{
  "bTransform": [
    -1,
    0,
    0,
    0,
    0,
    -1,
    0,
    0,
    0,
    0,
    1,
    0,
    0,
    0,
    0,
    1
  ],
  "rmsd": null
}

Hi, you want to use alignAndSuperpose (does sequence alignment and uses that to guide 3d superposition) not just superpose (assumes input is pairs of positions and 3d superposes those).

alignAndSuperposeWithSIFTSMapping in which case should be used instead?

Just not to confuse myself: SIFTS has to do with extra PDB\Uniprot annotations right?
There is a way to do this with alignAndSuperpose just based on seq and structure coordinates, right?

I'll it (alignAndSuperpose) today and reprot back. Thanks again.

Ok thanks, good to know this.

@rtviii good to close?

Yes, thanks Alex. I still haven't tried what you proposed, but will post the solution here if i figure out or reopen/tag in new issue.

Thanks for the issues office-hours, as always.