Discussion:
matplotlib - wx backend empty canvas
Werner
2014-09-25 13:40:07 UTC
Permalink
Hi,

I have been digging a bit on the matplotlib issues.

The problem when using the 'wx' backend, instead of the 'wxagg' backend
is that for some reason this is not working (as of wxPython 2.9).

In FigureCanvasWx.gui_repaint we have this call:

drawDC.DrawBitmap(self.bitmap, 0, 0)

If I set a breakpoint and then do 'self.bitmap.SaveFile' I see the
information which should be shown on the screen, but the screen is
showing an empty canvas instead and after the above is called we go into
an 'idle' state, so I don't think it is being cleared later on.

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Werner
2014-09-26 09:56:40 UTC
Permalink
Post by Werner
Hi,
I have been digging a bit on the matplotlib issues.
The problem when using the 'wx' backend, instead of the 'wxagg'
backend is that for some reason this is not working (as of wxPython 2.9).
drawDC.DrawBitmap(self.bitmap, 0, 0)
If I set a breakpoint and then do 'self.bitmap.SaveFile' I see the
information which should be shown on the screen, but the screen is
showing an empty canvas instead and after the above is called we go
into an 'idle' state, so I don't think it is being cleared later on.
Searching more I came across this:
http://wiki.wxpython.org/wxPython%20Platform%20Inconsistencies#wxDC.DrawBitmap.28.29

So, to test this I tried this in gui_repaint:
mdc = wx.MemoryDC()
mdc.SelectObject(self.bitmap)

and I do get an exception:
wx._core.PyAssertionError: C++ assertion "Assert failure" failed at
..\..\src\msw\dcmemory.cpp(130) in wxMemoryDCImpl::DoSelect(): Couldn't
select a bitmap into wxMemoryDC

Am I right to now think that 'drawDC.DrawBitmap(self.bitmap, 0, 0)' is
silently failing (only on Windows with wxPython 2.9+) because the bitmap
is still held by something?

I searched but GraphicsContextWx is always doing a
"SelectObject(wx.NullBitmap)" after it used the dc, could that somehow
silently fail or what else might hang on to the bitmap?

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Werner
2014-09-26 10:22:43 UTC
Permalink
Hi,

It seems that it is a problem that dc.SelectObject(wx.NullBitmap) is not
working correctly on 2.9+ and Windows.

In gui_repaint instead of doing:

drawDC.DrawBitmap(self.bitmap, 0, 0)

doing this:

img = self.bitmap.ConvertToImage()
bmp = img.ConvertToBitmap()
drawDC.DrawBitmap(bmp, 0, 0)

makes it work.

I'll try to make a minimal sample to show the problem and then do a trac
ticket.

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Werner
2014-09-26 12:00:42 UTC
Permalink
Post by Werner
Hi,
It seems that it is a problem that dc.SelectObject(wx.NullBitmap) is
not working correctly on 2.9+ and Windows.
drawDC.DrawBitmap(self.bitmap, 0, 0)
img = self.bitmap.ConvertToImage()
bmp = img.ConvertToBitmap()
drawDC.DrawBitmap(bmp, 0, 0)
makes it work.
I'll try to make a minimal sample to show the problem and then do a
trac ticket.
Doing the minimal sample I narrowed it down to mpl using '_cache =
weakref.WeakKeyDictionary()' which stores the 'MemoryDC' and the
'GraphicsContext' and in the minimal sample if I move the line
dc.SelectObject to below the line where the cache is updated the problem
goes away.

But the same trick doesn't do it in mpl - anyone any ideas?

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Chris Barker
2014-09-26 21:55:47 UTC
Permalink
Werner,

Thanks for digging into this. Sorry I don't have more time to look at the
MPL code right now but an idea:

drawDC.DrawBitmap(self.bitmap, 0, 0)

There are indeed issues with doing that is self.bitmap is selected into a
DC at the time. Is that the issue at hand? My understanding is that DCs are
not designed to be "kept around", ie. you really want to create the DC,
use it, then delete it, right in the same code.

IN practice, I've never seen keeping a DC around cause any problems other
than this one.

So if it's ingrained into the MPL wx back-end to keep that MemoryDC around
then the alternative is to use it, instead of teh DrawBitmap call,
somethign like:

drawDC.Blit(0, 0, self.width, self.height, the_memoryDC)

Assuming you have access to the memoryDC in this part of the code.

-Chris
Post by Werner
Post by Werner
Hi,
It seems that it is a problem that dc.SelectObject(wx.NullBitmap) is not
working correctly on 2.9+ and Windows.
drawDC.DrawBitmap(self.bitmap, 0, 0)
img = self.bitmap.ConvertToImage()
bmp = img.ConvertToBitmap()
drawDC.DrawBitmap(bmp, 0, 0)
makes it work.
I'll try to make a minimal sample to show the problem and then do a trac
ticket.
Doing the minimal sample I narrowed it down to mpl using '_cache =
weakref.WeakKeyDictionary()' which stores the 'MemoryDC' and the
'GraphicsContext' and in the minimal sample if I move the line
dc.SelectObject to below the line where the cache is updated the problem
goes away.
But the same trick doesn't do it in mpl - anyone any ideas?
Werner
--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
For more options, visit https://groups.google.com/d/optout.
--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

***@noaa.gov
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Werner
2014-09-27 08:40:00 UTC
Permalink
Hi Chris,
Post by Chris Barker
Werner,
Thanks for digging into this.
It is over my head but I like challenges:)
Post by Chris Barker
Sorry I don't have more time to look at the MPL code right now but an
drawDC.DrawBitmap(self.bitmap, 0, 0)
There are indeed issues with doing that is self.bitmap is selected
into a DC at the time. Is that the issue at hand? My understanding is
that DCs are not designed to be "kept around", ie. you really want to
create the DC, use it, then delete it, right in the same code.
I narrowed it down to the MemoryDC which is used in
backend_wx.GraphicsContextWx, there the DC is assigned to 'gfx_ctx =
wx.GraphicsContext.Create(dc)', and then 'gfx_ctx' is kept in a cache
within that GraphicsContextWx class "_cache = weakref.WeakKeyDictionary()'.
Post by Chris Barker
IN practice, I've never seen keeping a DC around cause any problems
other than this one.
It is strange that this did not cause a problem in 2.8, and that it
fails silently in 2.9+ (only on Windows), I think it should give an
error/warning.
Post by Chris Barker
So if it's ingrained into the MPL wx back-end to keep that MemoryDC
around then the alternative is to use it, instead of teh DrawBitmap
drawDC.Blit(0, 0, self.width, self.height, the_memoryDC)
Assuming you have access to the memoryDC in this part of the code.
It is accessible, but not that nicely 'dc, gc =
self.renderer.gc._cache.pop(self.bitmap)'.

I asked the question on the PR why MPL is keeping a cache of the GC's,
in my tests there is always only one Bitmap in play and therefore only
one cache entry. So I tried to get rid of it by changing
'RendererWx.new_gc' to only create a new GC if there isn't one and just
return the existing one. The graph shows but can't get the tick labels
to show for some reason.

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Nathan McCorkle
2014-09-29 06:09:16 UTC
Permalink
Post by Werner
Hi Chris,
Werner,
Thanks for digging into this.
It is over my head but I like challenges:)
Sorry I don't have more time to look at the MPL code right now but an
drawDC.DrawBitmap(self.bitmap, 0, 0)
There are indeed issues with doing that is self.bitmap is selected into
a DC at the time. Is that the issue at hand? My understanding is that DCs
are not designed to be "kept around", ie. you really want to create the
DC, use it, then delete it, right in the same code.
I narrowed it down to the MemoryDC which is used in
backend_wx.GraphicsContextWx, there the DC is assigned to 'gfx_ctx =
wx.GraphicsContext.Create(dc)', and then 'gfx_ctx' is kept in a cache
within that GraphicsContextWx class "_cache = weakref.WeakKeyDictionary()'.
Sorry to jump in not having tested the code (btw how would I reproduce the
actual mpl error?), but is it possible to simply get rid of the storing and
retrieving of the DC, and just create a new one or queue operations until
the OnPaint method is called?
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Werner
2014-09-29 07:33:42 UTC
Permalink
Hi Nathan,
Post by Werner
Hi Chris,
Post by Chris Barker
Werner,
Thanks for digging into this.
It is over my head but I like challenges:)
Post by Chris Barker
Sorry I don't have more time to look at the MPL code right now
drawDC.DrawBitmap(self.bitmap, 0, 0)
There are indeed issues with doing that is self.bitmap is
selected into a DC at the time. Is that the issue at hand? My
understanding is that DCs are not designed to be "kept around",
ie. you really want to create the DC, use it, then delete it,
right in the same code.
I narrowed it down to the MemoryDC which is used in
backend_wx.GraphicsContextWx, there the DC is assigned to 'gfx_ctx
= wx.GraphicsContext.Create(dc)', and then 'gfx_ctx' is kept in a
cache within that GraphicsContextWx class "_cache =
weakref.WeakKeyDictionary()'.
Sorry to jump in not having tested the code (btw how would I reproduce
the actual mpl error?),
Run the 'embedding_in_wx2.py' which is one of the samples included with
mpl and activate the 'matplotlib.use('WX') lines and comment the 'WXAgg'
lines. The problem only shows on Windows with wxPython 2.9+, it works
with 2.8.
Post by Werner
but is it possible to simply get rid of the storing and retrieving of
the DC, and just create a new one or queue operations until the
OnPaint method is called?
The caching is done for speed optimization (according to the comment) to
handle multiple bitmaps/DC's/GC's, in my tests I haven't been able to
come up with a case where multiple cache entries are created.

I tried getting rid of the caching and just returning the existing one
when needed (which is many times for a simple graph like the one in the
example), and then deleting it from within the OnPaint event, but
couldn't get that to work fully.

A work around is to pop the bitmap etc from the cache in the OnPaint
event, that works but feels like a hack.

Werner
--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+***@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...