Conversation
papillot
left a comment
There was a problem hiding this comment.
This ended-up being quite complex, not because of the labels per se, but more because of the way StructureSelection are laid out from the Query and Loci are defined from units.
I think there is probably an antipattern with the add_labels_to_selection_atoms example because we are trying to create on representation for each label and that makes 140+ representations in one go. There is a noticeable pause in the rendering.
It would be better to use a way to create the label that's more efficient and would serve as "The Way (™️)"
The add_label_to_selection_whole is working kind of by chance: the Query.generator.chains construct creates a grouping of the matches by chain id. Fortunately, this is the same mapping as when we use the label_asym_id property.
But this is not the case if we'd use the auth_asym_id property. In this case, we'd have 3-4 labels per "chain". Probably the best, in that case, is to use a groupBy callback with a Query.generators.atoms (not Query.generators.chains because this overwrites whatever groupBy property there is).
I guess such an example would be actually more generic.
|
|
||
| // A query defines the logic to select elements based on a predicate. | ||
| // The predicate is executed from a generator which updates the current element (here, an atom) | ||
| // The predicate is executed from a generator which updates the current element (here, a chain) |
There was a problem hiding this comment.
I do think it's an atom that's returned as the argument for the predicate, but that we are iterating only through the 1st one in each chain
There was a problem hiding this comment.
From the code in structure/query/queries/generators the chainTest is executed with the element corresponding to the chainSegment.start of each chain segment.
There was a problem hiding this comment.
Suggestion:
The predicate is executed from a generator that iterates over the structure hierarchy (chains, then residues, then atoms). At each iteration, the query context that is passed, is updated.
The chainTest predicate is executed once per chain. The element property represents the atom at the start of the current chain.
If the predicates return true, the entire chain segment is added to the selection.
| const ctx = new QueryContext(struct); | ||
| const selection = query(ctx); | ||
|
|
||
| // A StructureSelection is a Singleton if each iteration only adds a single element (atom) |
There was a problem hiding this comment.
"is a Singleton" is not correct. Notice that the type is StructureSelection.Singletons (plural)
Suggestion:
// A StructureSelection is made of Singletons if each iteration only...
| // The predicate is executed from a generator which updates the current element (here, a chain and an atom) | ||
| // in the query context, at each iteration. The predicate returns true if the element should be selected. |
There was a problem hiding this comment.
The predicate is executed from a generator that iterates over the structure hierarchy (chains, then residues, then atoms) and groups matches by residue. At each iteration, the query context that is passed, is updated.
The chainTest predicate is executed once per chain. The element property represents the atom at the start of the current chain.
The atomTest predicate is executed for each atom in the structure that passes the chainTest.
If both predicates return true, the atom is added to the selection.
| atomTest: ctx => StructureProperties.atom.auth_atom_id(ctx.element) === 'CA', | ||
| chainTest: ctx => StructureProperties.chain.label_asym_id(ctx.element) === 'A' |
There was a problem hiding this comment.
maybe start the list with the chainTest, then the atomTest.
I know that order does not matter in the dictionnary, but it will be easier to get the notion that the chainTest is actually run first for efficiency purposes.
There was a problem hiding this comment.
Sounds good, done
| structure.units.forEach(unit => { | ||
| for (let i = 0; i < unit.elements.length; i++) { // Iterate over each atom in the unit (each alpha carbon) | ||
| // Create a Loci using the unit and the index of the atom | ||
| const indices = OrderedSet.ofSingleton(i as StructureElement.UnitIndex); | ||
| const loci = StructureElement.Loci(struct, [{unit, indices: indices}]); | ||
| // Create a location to retrieve the atom's compID (residue name) | ||
| const location = StructureElement.Location.create(struct, unit, unit.elements[i]); | ||
| const resName = StructureProperties.atom.auth_comp_id(location); | ||
| // Add label to the loci | ||
| plugin.managers.structure.measurement.addLabel(loci, {labelParams: { | ||
| // Set label parameters, in this case the text and size | ||
| customText: 'Alpha Carbon '+resName, | ||
| textSize: 1 | ||
| }}); | ||
| } | ||
| }) |
There was a problem hiding this comment.
This works but is inefficient, probably because it's creating 140+ representations serially. Most of the code I've stumbled upon is using special construct with a LabeProvider.
I haven't dug out more, but I suspect this is actually an antipattern.
| // A StructureSelection is a Singleton if each iteration only adds a single element (atom) | ||
| // A StructureSelection is a Sequence if any iteration adds multiple elements (atoms) |
There was a problem hiding this comment.
A StructureSelection is made of Singletons if there is no grouping (e.g. when using Queries.generators.atoms) or when every group only contains a single element (atom). Matched elements are merged in a single unit within a unique structure in the StructureSelection var.
A StructureSelection is a Sequence if it contains at least one group with more than one element. Each group is its own Structure object in the structures array property of the StructureSelection var.
In this query, Queries.generators.chains creates a grouping at the chain level, that contains elements from the entire chains: selection is of type StructureSelection.Sequence.
| // A StructureSelection is a Singleton if each iteration only adds a single element (atom) | ||
| // A StructureSelection is a Sequence if any iteration adds multiple elements (atoms) | ||
| const loci: Loci[] = []; | ||
| if (StructureSelection.isSingleton(selection)) { // Singleton if each chain only has 1 atom |
There was a problem hiding this comment.
Singletons if grouping by atoms (no grouping)
| // A StructureSelection is a Sequence if any iteration adds multiple elements (atoms) | ||
| const loci: Loci[] = []; | ||
| if (StructureSelection.isSingleton(selection)) { // Singleton if each chain only has 1 atom | ||
| // Iterate over each Unit in the selection and create a Loci for each Unit |
There was a problem hiding this comment.
Iterate over each Unit in the structure. By default the units in the struct initial object were segmented by chain identifiers. Each Unit corresponds to a distinct chain.
There was a problem hiding this comment.
Don't take it for granted that each unit corresponds to a whole or single chain. Best to use selections!
| // Iterate over each Unit in the selection and create a Loci for each Unit | ||
| selection.structure.units.forEach(unit => { | ||
| // Create an OrderedSet of indicies for the length of unit.elements | ||
| const indices = OrderedSet.ofBounds(0 as StructureElement.UnitIndex, unit.elements.length as StructureElement.UnitIndex) |
There was a problem hiding this comment.
const indices = OrderedSet.ofBounds(0, unit.elements.length)
| // Iterate over each Structure in the selection and create a Loci for each SubStructure | ||
| selection.structures.forEach(structure => { | ||
| loci.push(Structure.toSubStructureElementLoci(struct, structure)); | ||
| }) |
There was a problem hiding this comment.
// Iterate over each Structure in the selection (one per chain) and create a Loci
...
loci.push(Structure.toStructureElementLoci(structure));
There was a problem hiding this comment.
We have a label structure representation, which can do many use-cases much more efficiently (and happy to see more params added as needed)
Overview
This PR creates 2 new examples for creating labels based on selections.
Changes made
How to test
Ensure the selection is visible
Specific review requests
For each of the examples: