LiteMol icon indicating copy to clipboard operation
LiteMol copied to clipboard

Simplest way to... color/style a particular selection?

Open sillitoe opened this issue 8 years ago • 9 comments

Morning - another doc request.

Given the starting point from the FAQ:

plugin.loadMolecule({
    id: '1tqn',
    url: 'https://www.ebi.ac.uk/pdbe/static/entry/1tqn_updated.cif',
    format: 'cif' // default
});

What's the simplest, stand-alone way to style a selection, e.g.

  • colour chain 'A' red?
  • display residues x,y,z as ball-and-stick?

I can do this by adjusting the code from the examples and creating my own plugin, but that's a lot of internal machinery to (sort of) understand before I can achieve what looks like it should be a fairly simple task.

Would be useful to be able to isolate simple, stand-alone JS code (i.e. when the full source is not available) for casual users to interact with their own components rather than require a full source build.

sillitoe avatar Nov 17 '16 12:11 sillitoe

I will create an utility function that creates the corresponding theme and show how to apply it in the commands example.

As you point out currently the only way is to do it "low level".

dsehnal avatar Nov 17 '16 12:11 dsehnal

Sounds great, thanks.

Those utility functions (i.e. the "external" facing functions) would be a great place to start if you're still looking at generating API docs from source. The "internal" API docs would obviously be useful for reference too, but TypeScript is generally pretty readable.

sillitoe avatar Nov 17 '16 12:11 sillitoe

I didn't have a look at the generated docs yet, but yes I agree. In that case tho this should probably be a "standalone" project that wraps the plugin. Tho this adds another maintenance cost... will think about it.

dsehnal avatar Nov 17 '16 12:11 dsehnal

I have spent some time thinking about how to do this (i.e. color the molecule loaded using loadMolecule and make selection on it) so that it does not cause any trouble down the road ... and I didn't find one.

The issue is that LiteMol does not represent the state the same way you typical web viewer does. There is no single object that would store the molecule and all of its selections/visual representations/etc. Instead, it is required to query the state tree and find what you are looking for.

When you call loadMolecule, it creates a state transform composed of these transforms:

  • DownloadData { url, type: string/binary }
  • CreateMoleculeFromData { format }
  • CreateMolel { modelIndex: 0 }
  • CreateMacromoleculeVisual { polymer: true, het: true, water: true }
    • This applies further transforms that decompose the molecule into Polymer, HET atoms, and water, using a "CreateSelection" transforms. Only then the visuals are created separately for each selection.

This results in a tree of entities

String/BinaryData (depending on format)
  |_ Molecule
     |_ MoleculeModel
        |_ Macromolecule Visuals
           |_ Polymer
              |_ Visual (cartoons)
           |_ HET
              |_ Visual (balls and sticks)
           |_ Water
              |_ Visual (balls and sticks)

So to be able to make the "simple" selection work, I would have to store somewhere the references to the different parts of the molecule, because "color chain X" needs to be applied to the "Visual (cartoons)" entity and "create balls and sticks of residues A, B, C" needs to be created by creating a selection on MoleculeModel and then creating a visual on that selection.

Of course I can store the names to enable this particular use case. But then you come and ask "how do I also do X starting from the loadMolecule function?" and the code would need to be modified again. It becomes a tangled mess really fast. I have added the loadMolecule for the single use case where you only want to show a molecule and don't care about it any more.

Having said all that, I really need to write a design goals/principles documents for LiteMol :)


Now to the issue of the simplest way to accomplish what you need. (note: this requires you to update to the latest version of LiteMol because I've removed a behavior from the default spec that automatically creates molecule visuals when a MoleculeModel entity is created and instead added it to the loadMolecule function)

  • Create the state "by hand" by applying the appropriate transforms. This will allow you to reference parts of the tree.
// import Transformer = LiteMol.Bootstrap.Entity.Transformer
let t = plugin.createTransform();
t.add(plugin.root, Transformer.Data.Download, { url: "https://...", type: "String" })
  .then(Transformer.Molecule.CreateFromData, { format: Core.Formats.Molecule.SupportedFormats.mmCIF }, { })
  .then(Transformer.Molecule.CreateModel, { modelIndex: 0 }, { ref: 'model' })
  .then(Transformer.Molecule.CreateMacromoleculeVisual, { polymer: true, polymerRef: 'polymer-visual', het: true, water: true });

plugin.applyTransform(t);

Notice the ref and polymerRef properties. This generates a state tree:

String/BinaryData (depending on format)
  |_ Molecule
     |_ MoleculeModel [ref = "model"]
        |_ Macromolecule Visuals
           |_ Polymer
              |_ Visual (cartoons) [ref = "polymer-visual"]
           |_ HET
              |_ Visual (balls and sticks)
           |_ Water
              |_ Visual (balls and sticks)
  • The easiest way to color chain 'A' red is to apply a selection to the the visual. It will use the "selection" color to color the selected atoms/residues, which is red by default. [You can actually remove this functionality by removing the behavior Bootstrap.Behaviour.ApplySelectionToVisual from the plugin spec.]
let query = LiteMol.Core.Structure.Query.chains({ authAsymId: 'A' });
let t = plugin.createTransform();
t.add('polymer-visual', Transformer.Molecule.CreateSelectionFromQuery, { query, name: 'Chain A' }, { }))
plugin.applyTransform(t);

Alternatively, have a look at the Commands example. It shows how to create a theme that color a chain with a different color. (Altho there is currently a very annoying drawback to doing this: using the "Reset Scene" command, i.e. the "refresh" button in top right corner, will remove any themes applied by the Command.Visual.UpdateBasicTheme command; it is something I am working on to fix)

  • To show residues X, Y, Z as balls and sticks, you need to select them on a MoleculeModel entity and then create the visual:
let query = LiteMol.Core.Structure.Query.residues({ authAsymId: 'A', authSeqNumber: 132 }, { authAsymId: 'A', authSeqNumber: 144 }, ...);
let t = plugin.createTransform();
t.add('polymer-visual', Transformer.Molecule.CreateSelectionFromQuery, { query, name: 'Residues' }, { }))
  .then(Transformer.Molecule.CreateVisual, { style: Bootstrap.Visualization.Molecule.Default.ForType.get('BallsAndSticks') });
plugin.applyTransform(t);  

This is also shown in the Commands example.

dsehnal avatar Nov 17 '16 20:11 dsehnal

Thanks very much for taking the time to answer this so thoroughly. I think this may well be useful documentation for others too.

I'm in a meeting all day tomorrow (discussing all this with the Genome3D consortium amongst other things) - I'll have a go implementing this and writing it up after the weekend.

sillitoe avatar Nov 18 '16 00:11 sillitoe

I'm getting a bit stuck with type casting:

The above worked okay - though I found that I needed to change the line...

let data = t.add( plugin.root, Transformer.Data.Download, { url: url, type: 'String', id: id })

to...

let data = t.add( plugin.root,
    <Bootstrap.Tree.Transformer.To<Entity.Data.String | Entity.Data.Binary>>Transformer.Data.Download,
    { url: url, type: 'String', id: id })

Which seems a bit of a mouthful (and makes me think I'm probably doing something wrong).

Perhaps related - I thought I should be able to get the molecule displaying as C-alpha trace (rather than cartoon)...

let data = t.add( plugin.root,
    <Bootstrap.Tree.Transformer.To<Entity.Data.String | Entity.Data.Binary>>Transformer.Data.Download,
    { url: url, type: 'String', id: id })
    .then(Transformer.Molecule.CreateFromData, { format: Core.Formats.Molecule.SupportedFormats.PDB, customId: id }, { isBinding: true, ref: 'mol-'+id })
    .then(Transformer.Molecule.CreateModel, { modelIndex: 0 }, { isBinding: false, ref: 'model-'+id })
    .then(Transformer.Molecule.CreateVisual, { style: Bootstrap.Visualization.Molecule.Default.ForType.get('Calpha') }, {} );

However the final line complains with:

Argument of type 'Transformer<Model | Selection, Visual, CreateVisualParams>' is not assignable to parameter of type 'Transformer<Model, Visual, CreateVisualParams>'

Any pointers?

sillitoe avatar Nov 22 '16 00:11 sillitoe

Ah yes, sorry. The types are indeed messed up a bit at the moment.

When I was designing the type system, unfortunately discriminated unions were not yet available, but the basic union types (type T = A | B) were. And I foolishly assumed that the compiler will be able to interfere the correct type. And when I found out that was not the case, it was "too late" and I had to resort to the ugly type annotation to resolve the issue.

<Bootstrap.Tree.Transformer.To<Entity.Data.String | Entity.Data.Binary>>

is "correct" workaround.

For the visual, using the type

<Bootstrap.Tree.Transformer.To<Entity.Molecule.Visual>>

should do the trick.

Sorry for the inconvenience, I will try to fix it using the discriminated unions as soon as possible (tho it will probably introduce a minor breaking change when creating custom entities).

dsehnal avatar Nov 22 '16 00:11 dsehnal

Thanks - that sheds a bit more light on coercions as well.

On Tue, 22 Nov 2016, 00:14 David Sehnal, [email protected] wrote:

Ah yes, sorry. The types are indeed messed up a bit at the moment.

When I was designing the type system, unfortunately discriminated unions https://basarat.gitbooks.io/typescript/content/docs/types/discriminated-unions.html were not yet available, but the basic union types (type T = A | B) were. And I foolishly assumed that the compiler will be able to interfere the correct type. And when I found out that was not the case, it was "too late" and I had to resort to the ugly type annotation to resolve the issue.

<Bootstrap.Tree.Transformer.To<Entity.Data.String | Entity.Data.Binary>>

is "correct" workaround.

For the visual, using the type

<Bootstrap.Tree.Transformer.To<Entity.Molecule.Visual>>

should do the trick.

Sorry for the inconvenience, I will try to fix it using the discriminated unions as soon as possible (tho it will probably introduce a minor breaking change when creating custom entities).

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dsehnal/LiteMol/issues/10#issuecomment-262108919, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJVeuquQbPUNyZdUe9ZBXt0kX1k5Ew8ks5rAjPdgaJpZM4K1Od3 .

sillitoe avatar Nov 22 '16 01:11 sillitoe

I have changed the Builder class so that the type annotations should not be needed (and removed the Transformer.To type).

dsehnal avatar Nov 22 '16 12:11 dsehnal