#831 closed enhancement (fixed)
Allow methods to access current changes to a specific Structure
| Reported by: | Tristan Croll | Owned by: | Eric Pettersen |
|---|---|---|---|
| Priority: | blocker | Milestone: | |
| Component: | Core | Version: | |
| Keywords: | Cc: | Tom Goddard | |
| Blocked By: | Blocking: | ||
| Notify when closed: | Platform: | all | |
| Project: | ChimeraX |
Description
At the moment in ISOLDE I have four different types of annotations to do with structural quality and/or restraints, which need to update their position/colour/visibility as their associated model changes. These are all illustrated in the attached image:
- position restraints (the 'pin' on the left);
- Ramachandran scores (CA colours);
- cis and twisted peptide bonds (pseudo-trapezoid filling the "cup" from CA to CA);
- torsion restraints ("calipers" around each axial bond indicating the distance from the target by both colour and angle)
At present I have the position and torsion restraint graphical updates slaved to the atomic "changes" trigger, and I should have the other two doing the same (but for now they only update during live simulations). The problem I face is that unless I'm missing something, the change handler offers no fast way to determine if any of the changes are coming from a specific model - it's faster to just update the drawings every time "display changed" or "coord changed" appears in changes.atom_reasons().
What I think would be nice is to be able to avoid unnecessary recalculations b querying the target Structure directly to see if it has any relevant changes. This could be achieved as simply as adding the line:
self.current_changes = gc
at line 309 of structure.py to provide an outward-visible copy of the current change mask, or a little more complex by splitting the changes out into individual boolean variables (self.coords_changed, self.display_changed etc.). That would allow me to use essentially the same logic pipeline that's used in structure.py itself for these updates.
Attachments (1)
Change History (13)
by , 8 years ago
| Attachment: | image11.png added |
|---|
comment:1 by , 8 years ago
I looked at combining the Structure._graphics_changed and Structure "changes" trigger (in atomic/changes.py) into one change tracking mechanism since they do nearly the same thing. But there is one key difference that _graphics_changed is per-structure while the "changes" trigger is aggregated for all structures. The graphics updating had to have the per-structure change info for efficient rendering. This is the same issue that Tristan raises in this ticket.
I don't see how the proposed fix of "self.current_changes = self._graphics_changed" is going to work because there is no way to be sure that value will be updated before your custom annotation drawing gets the "graphics update" trigger. This is because there is no way to say that your drawing "graphics update" trigger callback should be called after the "graphics update" trigger callback that is supposed to set "self.current_changes".
Some more thought should be given to whether structure change tracking should be done at the individual structure level in general.
comment:2 by , 8 years ago
A fair point on the lack of control over trigger timing. A potential alternative approach: provide a dict within the Structure class itself to which custom callbacks (taking the structure object and the changes as arguments) can be added (via e.g. add_redraw_callback(name, func) and remove_redraw_callback(name)). Then have it run all callbacks in the dict at the end of _update_graphics_if_needed(). Then you have control at the Structure level, you know exactly when they run and what information they get, and there's minimal need for adjustment of the existing system. On 2017-09-14 19:32, ChimeraX wrote:
follow-up: 2 comment:3 by , 8 years ago
... and I realised about a minute after posting that I'd just described the existing TriggerSet functionality... On 2017-09-14 19:54, ChimeraX wrote:
follow-up: 3 comment:4 by , 8 years ago
| Component: | Unassigned → Core |
|---|---|
| Status: | assigned → accepted |
comment:5 by , 8 years ago
| Cc: | added; removed |
|---|---|
| Owner: | changed from to |
| Status: | accepted → assigned |
Deciding whether there should be per-structure triggers for this purpose seems like it would be in Tom's purview, so reassigned ticket t him.
comment:6 by , 8 years ago
Just bumping this since I'm currently working on rotamer validation/annotation (and improving my implementation of validation tasks in general), and running into the same issue.
comment:7 by , 8 years ago
Eric and I just discussed have per-structure triggers. Basically these would work just like the current triggers that apply to all structures. Instead of using session.triggers.add_handler("changes", ...) you would use structure.triggers.add_handler("changes", ...) for the specific structure you want to monitor. The attractiveness of this approach is that it avoids creating different mechanisms to be notified of changes. In fact potentially this new mechanism could replace the current graphics change code that was written before the trigger changes were available.
I'm concerned though that your problem is simply performance, and the new triggers may also not have the performance you need. So I'm interested to know exactly how you expect to use the triggers. Do you plan on simply getting a per-structure "changes" trigger, seeing that it lists reason "coords changed", then you just update everything? Or are you going to try to see which specific atoms moved and only update the annotations effected? The latter approach is likely to be just as slow as the current global "changes" trigger.
comment:8 by , 8 years ago
Thanks, that sounds perfect! And yep, I’d plan to use it as per your first suggestion. A query: would you fire the trigger before or after the Structure has calculated its own drawing? Before would have some advantages, I think - e.g. allowing the triggered methods to change atom/bond colors there rather than on the next redraw. Tristan Croll Research Fellow Cambridge Institute for Medical Research University of Cambridge CB2 0XY
follow-up: 8 comment:9 by , 8 years ago
| Cc: | added; removed |
|---|---|
| Owner: | changed from to |
comment:10 by , 8 years ago
The per-structure triggers would fire before graphics is drawn so graphics can be changed and appear in the next rendered frame. So any molecular structure changes can update the graphics so they appear in the first rendered frame after the structure change was made.
comment:11 by , 8 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
Per-structure change triggers are now implemented.
comment:12 by , 8 years ago
For the convenience of my other user (Greg), the data given as the trigger argument is now a 2-tuple of (structure, changes) rather than just changes.
--Eric
Annotations used in ISOLDE