Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color a given part of the protein #55

Open
gerdos opened this issue Aug 7, 2019 · 28 comments
Open

Color a given part of the protein #55

gerdos opened this issue Aug 7, 2019 · 28 comments

Comments

@gerdos
Copy link

gerdos commented Aug 7, 2019

I would like to simple color a part of the molecule to green, and the rest to red. Lets say from residue 10-30 in the A chain to green, rest to red.

I know there is a similar question here, however that is 3 years old, and i found the explanation extremely unclear, and the codes provided there does not seem to function.

I have this protein loaded now:

plugin.loadMolecule({
            id: pdb,
            url: 'https://files.rcsb.org/download/5e0m.pdb ',
            format: 'pdb',
            ref: 'model'
        });
@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

Thanks a lot! Is there a chance you could give me a short JavaScript example? I tried to understand these parts in the example, but i struggle with it :(

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

Unfortunately, there is no "short" way to do this.

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

Than a little longer one maybe? :)

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

That's the one in the example.

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

It is in typescript. Can i translate it to JS, or i should stop trying, and user it as typescript?

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

Well, I would recommend you use TypeScript. But translation to JS isn't hard. You just remove the type annotations.

You can also start with one of the examples and just modify it. For example https://github.com/dsehnal/LiteMol/tree/master/examples/SimpleController and add the code from https://github.com/dsehnal/LiteMol/blob/master/examples/Commands/src/CustomTheme.ts and https://github.com/dsehnal/LiteMol/blob/master/examples/Commands/src/App.ts#L291

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

So i tried to follow the links you provided and got this far:

        let id = '5e0m';
        // this builds the transforms needed to create a molecule
        let action = LiteMol.Bootstrap.Tree.Transform.build()
            .add(plugin.context.tree.root, LiteMol.Bootstrap.Entity.Transformer.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif`, type: 'String', id })
            .then(LiteMol.Bootstrap.Entity.Transformer.Data.ParseCif, { id }, { isBinding: true })
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateFromMmCif, { blockIndex: 0 }, { isBinding: true })
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false, ref: 'model' })
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateMacromoleculeVisual, { polymer: true, polymerRef: 'polymer-visual', het: true, water: true });
             // can also add hetRef and waterRef; the refs allow us to reference the model and visual later.

        plugin.applyTransform(action);

        let visual = plugin.context.select('polymer-visual')[0];
        let model = plugin.context.select('model')[0];
        console.log(visual);
        console.log(model);

The molecule is loaded perfectly fine, however here visual and model are both undefined. What am i missing?

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

Yes, the applyTransform is a Promise so you need to await it or ".then"

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

Thanks, that helped a little more, got stuck a little further along the way:


        let id = '5e0m';
        // this builds the transforms needed to create a molecule
        let action = LiteMol.Bootstrap.Tree.Transform.build()
            .add(plugin.context.tree.root, LiteMol.Bootstrap.Entity.Transformer.Data.Download, {
                url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif`,
                type: 'String',
                id
            })
            .then(LiteMol.Bootstrap.Entity.Transformer.Data.ParseCif, {id}, {isBinding: true})
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateFromMmCif, {blockIndex: 0}, {isBinding: true})
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateModel, {modelIndex: 0}, {
                isBinding: false,
                ref: 'model'
            })
            .then(LiteMol.Bootstrap.Entity.Transformer.Molecule.CreateMacromoleculeVisual, {
                polymer: true,
                polymerRef: 'polymer-visual',
                het: true,
                water: true
            });
        // can also add hetRef and waterRef; the refs allow us to reference the model and visual later.

        plugin.applyTransform(action).then(function (result) {
            let visual = plugin.context.select('polymer-visual')[0];
            let model = plugin.context.select('model')[0];
            console.log(visual);
            console.log(model);
            let colors = {'A': LiteMol.Visualization.Color.fromRgb(125, 169, 12)};
        // etc.

            let theme = LiteMol.Bootstrap.Visualization.Molecule.createColorMapThemeProvider(
                // here you can also use m.atoms.residueIndex, m.residues.name/.... etc.
                // you can also get more creative and use "composite properties"
                // for this check Bootstrap/Visualization/Theme.ts and Visualization/Base/Theme.ts and it should be clear hwo to do that.
                //
                // You can create "validation based" coloring using this approach as it is not implemented in the plugin for now.
                m => ({ index: m.data.atoms.chainIndex, property: m.data.chains.asymId }),
                colors,
                // this a fallback color used for elements not in the set
                LiteMol.Visualization.Color.fromRgb(0, 0, 123))
                // apply it to the model, you can also specify props, check Bootstrap/Visualization/Theme.ts
                (model);

            LiteMol.Bootstrap.Command.Visual.UpdateBasicTheme.dispatch(plugin.context, { visual, theme });
            // if you also want to color the ligands and waters, you have to safe references to them and do it manually.

            });

Which is basically a direct copy of the script you provided. It yields:

LiteMol-plugin.min.js:50706 Uncaught (in promise) TypeError: this.map.get is not a function
    at e.setColor (LiteMol-plugin.min.js:50706)
    at Object.setColor (LiteMol-plugin.min.js:50642)
    at Object.setElementColor (LiteMol-plugin.min.js:50631)
    at a.applyColoring (LiteMol-plugin.min.js:55880)
    at a.applyThemeInternal (LiteMol-plugin.min.js:55903)
    at a.t.applyTheme (LiteMol-plugin.min.js:50941)
    at t._onNext (LiteMol-plugin.min.js:58827)
    at t.next (LiteMol-plugin.min.js:1871)
    at t.onNext (LiteMol-plugin.min.js:1833)
    at t (LiteMol-plugin.min.js:643)

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

colors needs to be a Map, not an object I think.

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

Thanks a lot!!!! I managed to color it, is there a chance you can lend me a last bit of help to show me how can i change this code to color lets say the 15th and 16th residue of the A chain?

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

Yes, use the code I sent you originally from https://github.com/dsehnal/LiteMol/blob/master/examples/Commands/src/CustomTheme.ts :)

@gerdos
Copy link
Author

gerdos commented Aug 7, 2019

After a long struggle, I was able to do it, thanks a lot! Do you mind if i post my solution here for future newbies like me?

@dsehnal
Copy link
Owner

dsehnal commented Aug 7, 2019

Cool. I don't mind.

@steveyu323
Copy link

After a long struggle, I was able to do it, thanks a lot! Do you mind if i post my solution here for future newbies like me?

Hiiiii there! I'm a newbie suffering the same question here and am wondering if you could post you solution here for reference. Thank you so much !

@gerdos
Copy link
Author

gerdos commented Feb 4, 2020

Hi!

I am not a 100% sure how this works as I completely forgot the stuff but my code looks like this:

function show_pdb(plugin, id, regions, chain, entity) {
    $("#pdb_link").attr("href", "https://www.ebi.ac.uk/pdbe/entry/pdb/" + id);
    var Bootstrap = LiteMol.Bootstrap;
    var Transformer = Bootstrap.Entity.Transformer;
    var Tree = Bootstrap.Tree;
    var Transform = Tree.Transform;
    LiteMol.Bootstrap.Command.Tree.RemoveNode.dispatch(plugin.context, plugin.context.tree.root);
    var action = Transform.build()
        .add(plugin.context.tree.root, Transformer.Data.Download, {
            url: "https://www.ebi.ac.uk/pdbe/static/entry/" + id + "_updated.cif",
            type: 'String',
            id: id
        })
        .then(Transformer.Data.ParseCif, {id: id}, {isBinding: true})
        .then(Transformer.Molecule.CreateFromMmCif, {blockIndex: 0}, {isBinding: true})
        .then(Transformer.Molecule.CreateModel, {modelIndex: 0}, {isBinding: false, ref: 'model'})
        .then(Transformer.Molecule.CreateMacromoleculeVisual, {
            polymer: true,
            polymerRef: 'polymer-visual',
            het: true,
            water: false
        });
    applyTransforms(action).then(function (result) {
        var model = plugin.selectEntities('model')[0];
        if (!model)
            return;
        var coloring = {
            base: {r: 210, g: 180, b: 140},
            entries: [

            ]
        };
        $.each(regions.split(','), function (n, elem) {
           coloring['entries'].push(
               {
                    entity_id: entity.toString(),
                    struct_asym_id: chain,
                    start_residue_number: Number(elem.split('-')[0]),
                    end_residue_number: Number(elem.split('-')[1]),
                    color: {r: 23, g: 162, b: 184}
                },
           )
        });
        console.log(coloring);
        var theme = LiteMolPluginInstance.CustomTheme.createTheme(model.props.model, coloring);
        LiteMolPluginInstance.CustomTheme.applyTheme(plugin, 'polymer-visual', theme);
    });
}

The variable regions is a string and contains multiple regions in the format of : "start1-end1,start2-end2...". I guess the rest are self explanatory, I hope this will help :)

@steveyu323
Copy link

Hi!

I am not a 100% sure how this works as I completely forgot the stuff but my code looks like this:

function show_pdb(plugin, id, regions, chain, entity) {
    $("#pdb_link").attr("href", "https://www.ebi.ac.uk/pdbe/entry/pdb/" + id);
    var Bootstrap = LiteMol.Bootstrap;
    var Transformer = Bootstrap.Entity.Transformer;
    var Tree = Bootstrap.Tree;
    var Transform = Tree.Transform;
    LiteMol.Bootstrap.Command.Tree.RemoveNode.dispatch(plugin.context, plugin.context.tree.root);
    var action = Transform.build()
        .add(plugin.context.tree.root, Transformer.Data.Download, {
            url: "https://www.ebi.ac.uk/pdbe/static/entry/" + id + "_updated.cif",
            type: 'String',
            id: id
        })
        .then(Transformer.Data.ParseCif, {id: id}, {isBinding: true})
        .then(Transformer.Molecule.CreateFromMmCif, {blockIndex: 0}, {isBinding: true})
        .then(Transformer.Molecule.CreateModel, {modelIndex: 0}, {isBinding: false, ref: 'model'})
        .then(Transformer.Molecule.CreateMacromoleculeVisual, {
            polymer: true,
            polymerRef: 'polymer-visual',
            het: true,
            water: false
        });
    applyTransforms(action).then(function (result) {
        var model = plugin.selectEntities('model')[0];
        if (!model)
            return;
        var coloring = {
            base: {r: 210, g: 180, b: 140},
            entries: [

            ]
        };
        $.each(regions.split(','), function (n, elem) {
           coloring['entries'].push(
               {
                    entity_id: entity.toString(),
                    struct_asym_id: chain,
                    start_residue_number: Number(elem.split('-')[0]),
                    end_residue_number: Number(elem.split('-')[1]),
                    color: {r: 23, g: 162, b: 184}
                },
           )
        });
        console.log(coloring);
        var theme = LiteMolPluginInstance.CustomTheme.createTheme(model.props.model, coloring);
        LiteMolPluginInstance.CustomTheme.applyTheme(plugin, 'polymer-visual', theme);
    });
}

The variable regions is a string and contains multiple regions in the format of : "start1-end1,start2-end2...". I guess the rest are self explanatory, I hope this will help :)

Thank you so much ! I'll look into it and maybe frame a tutorial style walkthrough once I manage to solve this.

@gerdos
Copy link
Author

gerdos commented Apr 27, 2020

@dsehnal Dear David!

I was able to create a small script than colors a structure for x given region, however for some reason it does not work on NMR structure. Can you please help me figure out whats going on?

I have a show_pdb function, that shows a given pdb, and colors regions from the argument regions_to_color in the form of "2-6;8-12" for example.

My code so far:

function show_pdb(plugin, id, regions_to_color, chain, entity, delta) {
    console.log(delta, chain, id);
    $("#pdb_link").attr("href", "https://www.ebi.ac.uk/pdbe/entry/pdb/" + id.toLowerCase());
    var Bootstrap = LiteMol.Bootstrap;

    var Transformer = Bootstrap.Entity.Transformer;
    var Tree = Bootstrap.Tree;
    var Transform = Tree.Transform;

    // this builds the transforms needed to create a molecule
    LiteMol.Bootstrap.Command.Tree.RemoveNode.dispatch(plugin.context, plugin.context.tree.root);
    var action = Transform.build()
        .add(plugin.context.tree.root, Transformer.Data.Download, {
            url: "https://www.ebi.ac.uk/pdbe/static/entry/" + id.toLowerCase() + "_updated.cif",
            type: 'String',
            id: id
        })
        .then(Transformer.Data.ParseCif, {id: id}, {isBinding: true})
        .then(Transformer.Molecule.CreateFromMmCif, {blockIndex: 0}, {isBinding: true})
        .then(Transformer.Molecule.CreateModel, {modelIndex: 0}, {isBinding: false, ref: 'model'})
        .then(Transformer.Molecule.CreateMacromoleculeVisual, {
            polymer: true,
            polymerRef: 'polymer-visual',
            het: true,
            water: false
        });
    // can also add hetRef and waterRef; the refs allow us to reference the model and visual later.
    applyTransforms(action).then(function (result) {
        var model = plugin.selectEntities('model')[0];
        if (!model)
            return;
        var coloring = {
            base: {r: 210, g: 180, b: 140},
            entries: [
            ]
        };
        $.each(regions_to_color.split(','), function (n, elem) {
           coloring['entries'].push(
               {
                    entity_id: entity.toString(),
                    struct_asym_id: chain,
                    start_residue_number: Number(elem.split('-')[0]) + Number(delta),
                    end_residue_number: Number(elem.split('-')[1]) + Number(delta),
                    color: {r: 23, g: 162, b: 184},
                   molecule: "1",
                },
           )
        });
        var theme = LiteMolPluginInstance.CustomTheme.createTheme(model.props.model, coloring);
        LiteMolPluginInstance.CustomTheme.applyTheme(plugin, 'polymer-visual', theme);

    });
}

var LiteMolPluginInstance;
(function (LiteMolPluginInstance) {
    var CustomTheme;
    (function (CustomTheme) {
        var Core = LiteMol.Core;
        var Visualization = LiteMol.Visualization;
        var Bootstrap = LiteMol.Bootstrap;
        var Q = Core.Structure.Query;
        var ColorMapper = /** @class */ (function () {
            function ColorMapper() {
                this.uniqueColors = [];
                this.map = Core.Utils.FastMap.create();
            }

            Object.defineProperty(ColorMapper.prototype, "colorMap", {
                get: function () {
                    var map = Core.Utils.FastMap.create();
                    this.uniqueColors.forEach(function (c, i) {
                        return map.set(i, c);
                    });
                    return map;
                },
                enumerable: true,
                configurable: true
            });
            ColorMapper.prototype.addColor = function (color) {
                var id = color.r + "-" + color.g + "-" + color.b;
                if (this.map.has(id))
                    return this.map.get(id);
                var index = this.uniqueColors.length;
                this.uniqueColors.push(Visualization.Color.fromRgb(color.r, color.g, color.b));
                this.map.set(id, index);
                return index;
            };
            return ColorMapper;
        }());

        function createTheme(model, colorDef) {
            var mapper = new ColorMapper();
            mapper.addColor(colorDef.base);
            var map = new Uint8Array(model.data.atoms.count);
            for (var _i = 0, _a = colorDef.entries; _i < _a.length; _i++) {
                var e = _a[_i];
                var query = Q.sequence(e.entity_id.toString(), e.struct_asym_id, {seqNumber: e.start_residue_number}, {seqNumber: e.end_residue_number}).compile();
                var colorIndex = mapper.addColor(e.color);
                for (var _b = 0, _c = query(model.queryContext).fragments; _b < _c.length; _b++) {
                    var f = _c[_b];
                    for (var _d = 0, _e = f.atomIndices; _d < _e.length; _d++) {
                        var a = _e[_d];
                        map[a] = colorIndex;
                    }
                }
            }
            var fallbackColor = {r: 0.6, g: 0.6, b: 0.6};
            var selectionColor = {r: 0, g: 0, b: 1};
            var highlightColor = {r: 1, g: 0, b: 1};
            var colors = Core.Utils.FastMap.create();
            colors.set('Uniform', fallbackColor);
            colors.set('Selection', selectionColor);
            colors.set('Highlight', highlightColor);
            var mapping = Visualization.Theme.createColorMapMapping(function (i) {
                return map[i];
            }, mapper.colorMap, fallbackColor);
            // make the theme "sticky" so that it persist "ResetScene" command.
            return Visualization.Theme.createMapping(mapping, {colors: colors, isSticky: true});
        }

        CustomTheme.createTheme = createTheme;

        function applyTheme(plugin, modelRef, theme) {
            var visuals = plugin.selectEntities(Bootstrap.Tree.Selection.byRef(modelRef).subtree().ofType(Bootstrap.Entity.Molecule.Visual));
            for (var _i = 0, visuals_2 = visuals; _i < visuals_2.length; _i++) {
                var v = visuals_2[_i];
                plugin.command(Bootstrap.Command.Visual.UpdateBasicTheme, {visual: v, theme: theme});
            }
        }

        CustomTheme.applyTheme = applyTheme;
    })(CustomTheme = LiteMolPluginInstance.CustomTheme || (LiteMolPluginInstance.CustomTheme = {}));
})(LiteMolPluginInstance || (LiteMolPluginInstance = {}));
/*
 * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
 */

function applyTransforms(actions) {
    return plugin.applyTransform(actions);
}

@dsehnal
Copy link
Owner

dsehnal commented Apr 27, 2020

And what would the expected behavior for NMR structure be?

I see you are passing molecule: "1" to the theme but that value isn't used anywhere.

If you want i-th NMR model, you have to edit this line: .then(Transformer.Molecule.CreateModel, {modelIndex: 0}, {isBinding: false, ref: 'model'}) (i.e. the modelIndex property).

@gerdos
Copy link
Author

gerdos commented Apr 27, 2020

The molecule: "1" was left in there by accident, it was unused.

As for the NMR, one model would be enough for me, lets say the very first one, with the apropriate region colored.

I am still not able to color the NMR structures even with by changing the modelIndex property of the line: .then(Transformer.Molecule.CreateModel, {modelIndex: 0}, {isBinding: false, ref: 'model'})
I tried all kinds of numbers but no luck :(

@dsehnal
Copy link
Owner

dsehnal commented Apr 28, 2020

And just showing the structure without the coloring works?

The { modelIndex: 0 } is correct, I thought you want to show colors on different models.

If it works on non-NRM structure there is no reason it wont work on these. These is no difference in the internal data models. What are the particular data you are trying this on?

@gerdos
Copy link
Author

gerdos commented Apr 29, 2020

So after some testing its nor about NMR structures, so I have no idea about the root of the problem.
I have these three buttons:

<button onclick="show_pdb(plugin, '1Z9I', '712-718', 'A', 1, -668);">1Z9I</button>
<button onclick="show_pdb(plugin, '2M20', '678-686', 'B', 1, -581);">2M20</button>
<button onclick="show_pdb(plugin, '2N5S', '676-686', 'A', 1, -600);">2N5S</button>

The first one (1Z9I) is colored correctly, but the rest is not colored. I have no idea why :(

@gerdos
Copy link
Author

gerdos commented May 22, 2020

@dsehnal Sorry to bother again, any idea why the mentioned scrip does not work? I tried to make sense of what happening, but failed countless times now :(

@dsehnal
Copy link
Owner

dsehnal commented May 22, 2020

Hi, sorry for the late reply. If you click on the 2nd or 3rd 1st, are they colored correctly?

Also, are you using "label" annotations as input? Because mmCif has both label_ and auth_ columns.

For example for 2m20, this is the B chain in mmCIF

ATOM 3113 N N . PRO B 1 3 ? 2.317 8.834 -26.569 1.00 0.00 ? 63 PRO B N 2 3
ATOM 3114 C CA . PRO B 1 3 ? 3.412 7.919 -26.205 1.00 0.00 ? 63 PRO B CA 2 3
ATOM 3115 C C . PRO B 1 3 ? 2.946 6.757 -25.327 1.00 0.00 ? 63 PRO B C 2 3
ATOM 3116 O O . PRO B 1 3 ? 2.070 6.923 -24.478 1.00 0.00 ? 63 PRO B O 2 3
ATOM 3117 C CB . PRO B 1 3 ? 4.386 8.816 -25.432 1.00 0.00 ? 63 PRO B CB 2 3
ATOM 3118 C CG . PRO B 1 3 ? 3.562 9.945 -24.919 1.00 0.00 ? 63 PRO B CG 2 3
ATOM 3119 C CD . PRO B 1 3 ? 2.470 10.159 -25.931 1.00 0.00 ? 63 PRO B CD 2 3

Notice that the label_seq_id is 1, but auth_seq_id is 63. The theme you are using is based on the label_ coordiantes, not auth_.

@gerdos
Copy link
Author

gerdos commented May 22, 2020

Thanks a lot, I ll look into this tomorrow!

@gerdos
Copy link
Author

gerdos commented May 27, 2020

@dsehnal Thanks a lot for the help, it is working, and I finally understand it!

One last question, and I promise I wont bother with this afterwards:

Where do I need to change the script to be able to use auth_asym_id and auth_sec_id?

@dsehnal
Copy link
Owner

dsehnal commented May 28, 2020

Changing

Q.sequence(e.entity_id.toString(), e.struct_asym_id, {seqNumber: e.start_residue_number}, {seqNumber: e.end_residue_number}).compile();

to

Q.sequence(e.entity_id.toString(), { authAsymId: e.struct_asym_id }, { authSeqNumber: e.start_residue_number}, { authSeqNumber: e.end_residue_number }).compile();

should do the trick. Using undefined in place of e.entity_id should work too.

The query is defined here: https://github.com/dsehnal/LiteMol/blob/master/src/lib/Core/Structure/Query/Queries.ts#L74

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants