Opened 7 years ago

Closed 7 years ago

#1717 closed defect (fixed)

QResizeEvent can break graphics under some circumstances

Reported by: Tristan Croll Owned by: Tom Goddard
Priority: moderate Milestone:
Component: Graphics Version:
Keywords: Cc:
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

I've stumbled on a (very specific) combination of circumstances where triggering a QResizeEvent breaks things due to deleted drawings still somehow being in the View drawing tree. In brief, if I:

  • load a model
  • start ISOLDE (which triggers the model to be briefly removed from the session, re-instated subordinate to a higher-level "Data manager" model, and then redrawn on the next 'frame drawn' trigger to change the cartoon style using the method below - If I run this before loading the model, it gets overridden)
def set_to_default_cartoon(session, model = None):
    '''
    Adjust the ribbon representation to provide information without
    getting in the way.
    '''
    from chimerax.core.commands import atomspec
    from chimerax.std_commands import cartoon
    from chimerax.atomic.nucleotides.cmd import nucleotides
    from chimerax.atomic import AtomicStructures
    try:
        if model is None:
            atoms = None
            models = AtomicStructures([model])
        else:
            models = None
            atoms = model.atoms
            atoms.displays=False
            atoms[atoms.idatm_types!='HC'].displays=True
            arg = atomspec.AtomSpecArg('thearg')
            aspec= arg.parse('#' + model.id_string, session)[0]
        cartoon.cartoon(session, atoms = aspec, suppress_backbone_display=False)
        cartoon.cartoon_style(session, atoms = aspec, width=0.4, thickness=0.1, arrows_helix=True, arrow_scale = 2)
        cartoon.cartoon_tether(session, structures=models, opacity=0)
        nucleotides(session, 'atoms')
        from chimerax.std_commands import color
        color.color(session, model, color='bychain', target='ac')
        color.color(session, model, color='byhetero', target='a')
  • while the above is processing, I drag the ISOLDE window to dock into the GUI triggering a QResizeEvent, then I get a traceback:
Traceback (most recent call last):
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/ui/graphics.py", line 80, in resizeEvent
    v.draw(check_for_changes = False)
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/view.py", line 159, in draw
    self._draw_scene(camera, drawings)
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/view.py", line 218, in _draw_scene
    draw_opaque(r, opaque_drawings)
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/drawing.py", line 1394, in draw_opaque
    _draw_multiple(drawings, renderer, Drawing.OPAQUE_DRAW_PASS)
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/drawing.py", line 1405, in _draw_multiple
    d.draw(renderer, draw_pass)
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/drawing.py", line 699, in draw
    if not self.display:
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/drawing.py", line 324, in get_display
    raise e
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/core/graphics/drawing.py", line 319, in get_display
    return self._any_displayed_positions and len(self._positions) > 0
TypeError: object of type 'NoneType' has no len()

... and if I open the shell and start typing, then every keypress triggers:

/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/IPython/core/history.py:226: UserWarning: IPython History requires SQLite, your history will not be saved
warn("IPython History requires SQLite, your history will not be saved")
Traceback (most recent call last):
  File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/qtconsole/completion_html.py", line 152, in eventFilter
    key = event.key()
AttributeError: 'QResizeEvent' object has no attribute 'key'

AttributeError: 'QResizeEvent' object has no attribute 'key'

File "/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/qtconsole/completion_html.py", line 152, in eventFilter
key = event.key()

I've done some preliminary tracking down to try to work out if this is a ChimeraX bug or an ISOLDE bug. Editing Drawing with the following changes:

    def remove_drawings(self, drawings, delete=True):
        '''Remove specified child drawings.'''
        dset = set(drawings)
        self._child_drawings = [d for d in self._child_drawings
                                if d not in dset]
        for d in drawings:
            #d.parent = None
            pass
        if delete:
            for d in drawings:
                d.delete()
        self.redraw_needed(shape_changed=True, highlight_changed=True)

    def get_display(self):
        try:
            return self._any_displayed_positions and len(self._positions) > 0
        except TypeError as e:
            lineage = '; '.join([d.name for d in self.drawing_lineage])
            print("Failed drawing: {}".format(lineage))
            print("Was deleted: {}".format(self.was_deleted))
            raise e

Gives me:

Failed drawing: root; Data manager (6iqg.pdb); 6iqg.pdb; ribbon; 6iqg.pdb /A GLY 237 ribbons
Was deleted: True

... and if I revert the edit to remove_drawings() then the lineage collapses to just 6iqg.pdb /A GLY 237 ribbons.

Yet if I edit view.py at line 218 to put a try...except around draw_opaque() and list opaque_drawings on an exception, then all the deleted ribbon drawings are still in the list.

That's as far as I've gotten. It can of course be trivially avoided by changing Drawing.get_display() to

    def get_display(self):
        return not self.was_deleted and self._any_displayed_positions and len(self._positions) > 0

... but deleted drawings not being immediately removed from the View seems like the sort of thing that could trigger nasty bugs in the future.

Change History (4)

comment:1 by Tristan Croll, 7 years ago

... and yes, before you mention it I realise now the logic on set_to_default_cartoon() was a bit messed up (not sure what I was thinking there) - but fixing that has no bearing on the problem.

comment:2 by Tom Goddard, 7 years ago

Please give me a test case I can reproduce. The Python code isn't legal. I spent 15 minutes fixing it, then it does not produce any error when I drop the log panel into main window while it is running that python function.

I tested on Mac. I guess you are on Linux.

I don't know what ChimeraX version you used because you did not use Report a Bug.

It appears the error is because a deleted ribbon is being drawn. Of course that should not be possible. There is some bug here but I need a test case.

comment:3 by Tom Goddard, 7 years ago

With much snooping I found the problem and a test case to reproduce it. Ribbon gets recomputed during the rendering which deletes the ribbon drawing. It should not be recomputed during drawing but a bounds() calculation causes it to be recomputed. Should be easy to fix.

comment:4 by Tom Goddard, 7 years ago

Resolution: fixed
Status: assignedclosed

Fixed.

Window resize causes error when ribbon changed since last redraw and shadows are shown. Error occurs because bounds() calculation causes graphics update, which causes ribbon recompute which deletes ribbon drawing that is part of the draw tree. Fix was to make window resize use the standard update loop draw call which updates graphics.

Note: See TracTickets for help on using tickets.