pbfy0 / visvis

Automatically exported from code.google.com/p/visvis
Other
0 stars 0 forks source link

Gui widget versus Figure creation #52

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Under some circumstances, an application that embeds visvis might want to delay 
the creation of a widget object. For instance when the call to create a new 
figure is not done from the main thread. 

This was an issue when Robert implemented visvis for reinteract. We discussed 
this at EuroScipy and the code to fix this seems limited and relatively clean. 
Therefore we should look into fixing this in visvis, so that others may benefit 
from it too.

Original issue reported on code.google.com by almar.klein@gmail.com on 27 Aug 2012 at 10:42

GoogleCodeExporter commented 9 years ago

Original comment by almar.klein@gmail.com on 27 Aug 2012 at 10:47

GoogleCodeExporter commented 9 years ago
Here's what the changes to the GTK backend would look like.  As you see it's 
not much.  I expect the other backends to be similar, though I haven't checked.

Two bits of ugliness:
1) In Figure.__init__, I look for create_widget in kw.  A more natural approach 
might be Figure.__init__(self, create_widget=True, *args, **kw), but I didn't 
want to change the signature.  That said, the signature to Figure() is 
backend-dependent already, and the GTK backend doesn't do anything with these 
args, so I doubt there's any code relying on this signature.  Other backends 
(FLTK, I notice) would have to decide what to do here.

2) Figure._GetPosition() gets called before widget creation in my Reinteract 
setup, so it has to return something.  Returning (0,0,0,0) seems to work in 
brief testing.  (In my previous system with Reinteract, I could return at least 
the anticipated figure size, but we don't know that in general.)  But maybe we 
ought to figure out if this has the potential to cause problems.  As best I can 
figure out, the problem is the Wibjects try to work out their position on the 
figure as soon as they are created, so they need to know about the figure size. 
 Here's a traceback of what happens if _GetPosition doesn't return anything:
  File "/home/rschroll/.reinteract/modules/revis.py", line 429, in func
    vfunc(*args, **kw)
  File "/home/rschroll/lib/python/visvis/functions/plot.py", line 149, in plot
    axes = vv.gca()
  File "/home/rschroll/lib/python/visvis/functions/gca.py", line 23, in gca
    a = vv.Axes(f)
  File "/home/rschroll/lib/python/visvis/core/axes.py", line 159, in __init__
    parent = AxesContainer(figure)
  File "/home/rschroll/lib/python/visvis/core/axes.py", line 92, in __init__
    Box.__init__(self, parent, *args, **kwargs)
  File "/home/rschroll/lib/python/visvis/core/baseWibjects.py", line 30, in __init__
    Wibject.__init__(self, parent)
  File "/home/rschroll/lib/python/visvis/core/base.py", line 556, in __init__
    self._position = Position( 10,10,50,50, self)
  File "/home/rschroll/lib/python/visvis/core/base.py", line 882, in __init__
    self._CalculateInPixels()
  File "/home/rschroll/lib/python/visvis/core/base.py", line 1001, in _CalculateInPixels
    ppos = owner.parent.position
  File "/home/rschroll/lib/python/visvis/core/baseFigure.py", line 506, in fget
    self._position._x, self._position._y = thepos[0], thepos[1]
TypeError: 'NoneType' object has no attribute '__getitem__'

Original comment by rschr...@gmail.com on 21 Oct 2012 at 11:33

Attachments:

GoogleCodeExporter commented 9 years ago
The diff seems simple and as far as I can tell will result in the exact same 
behavior unless "create_widget=False" is given as a kw-argument.

> 1) In Figure.__init__, I look for create_widget in kw.

I think that in earlier versions of Python (2.6?) you cannot specify a keyword 
argument before the *args. So the current approach is fine. 

> 2) Figure._GetPosition() gets called before widget creation ...

The widgets are very eager to know their position. In many cases (especially in 
interactive mode) the Figure can be assumed to be fully initialized. I see two 
options here to resolve this issue.

The first is to let _GetPosition return (0,0,0,0) as you suggest. Maybe we 
should also specify that this signifies an uninitialized figure. The second is 
to change the "eagerness" of wibjects for wanting to know the figure position. 
In theory they should only need it at draw-time.

I fear that implementing the second option takes quite a lot of change, and a 
lot of care+testing should be taken to make sure everything keeps working as 
intended. Since you indicated that the first option seems to work, I propose we 
go with that.

Original comment by almar.klein@gmail.com on 24 Oct 2012 at 12:43

GoogleCodeExporter commented 9 years ago
I just pushed a set of changes to split widget creation from Figure creation in 
all the backends.  I've tested all of them with a simple test program, and they 
all seem to work.  (In the FLTK backend, the figure shows up in a separate 
window, though.  I don't know if that's a problem with the changes or with my 
test program.  Since I've never used FLTK before, I'll let you take a look at 
it if you're concerned.)  However, only the GTK backend has been tested to 
ensure it works with multiple threads.  (That is, you can create the figure in 
a secondary thread and then call CreateWidget() in the main thread.)  I know 
nothing about threading in the other toolkits.

One change from my previous patch is that the CreateWidget() method now returns 
the widget.  I realized when writing the test programs that you generally want 
the widget as soon as you create it, so why not pass it to the user?

Original comment by rschr...@gmail.com on 1 Nov 2012 at 9:42

GoogleCodeExporter commented 9 years ago
Thanks Robert. Looks good. I'll have a look at the fltk backend soon.

The system to enable threading is now in place. I have no real test-case for it 
though, so lets worry about that once someone needs it.

Original comment by almar.klein@gmail.com on 2 Nov 2012 at 2:59

GoogleCodeExporter commented 9 years ago
If you care, here's the test script I used for the FLTK backend that produced a 
separate window.

Original comment by rschr...@gmail.com on 4 Nov 2012 at 11:55

Attachments:

GoogleCodeExporter commented 9 years ago
I changed the show_plot method to embed the GlWidget in the main widget:

    def show_plot(self, event):
        w=self.fig.CreateWidget()
        self.add(w)   
        w.show()

However, this produced OpenGl errors. Turned out the Axes still has a position 
with 0 width and height. I pushed a commit that calls position._Changed() in 
CreateWidget to force recalculation. 

Original comment by almar.klein@gmail.com on 12 Nov 2012 at 10:54

GoogleCodeExporter commented 9 years ago
Can we close this issue?

Original comment by almar.klein@gmail.com on 11 Dec 2012 at 12:13