Assertion triggered in wxMemory DC

The example I created was the smallest sample code I could make to reproduce
the problem.

The code below is more true to my application. It does not use the matlab
interface. It does however mimick the matlab interface. I did not have the
src distribution so I created this from reading the code. Note the main
frame calls the draw command on the canvas (MatlabFigure) 100 times. This
triggers the problem as well.

I'll take a look at the source distribution.

Thank you for the help

Johan

import wx
import matplotlib
import numarray
matplotlib.use('WX')

from matplotlib.figure import Figure
from matplotlib.backends.backend_wx import FigureCanvasWx
from matplotlib.backend_bases import FigureManagerBase, error_msg
from matplotlib.axes import Axes
from matplotlib.cbook import flatten, is_string_like, exception_to_str
import matplotlib.mlab as mlab

···

#---------------------------------------------------------------------------
class MatlabFigure(FigureCanvasWx):

    def __init__(self, parent):
        self.fig = Figure()
        FigureCanvasWx.__init__(self, parent, -1, self.fig)
        
        self.figmgr = FigureManagerBase(self, 0)
        self.gca = self.figmgr.get_current_axis()
    # end def

    def GetXY(self, event):
        screenPos= numarray.array( event.GetPosition())
        ymin, height = self.fig.bbox.intervaly().get_bounds()
        x, y = screenPos[0], height-screenPos[1]
        if self.gca.in_axes(x, y):
            xy = self.gca.transData.inverse_xy_tup((x, y))
            return xy
        else:
            return None
        # end if
    # end def
    
    def axis(self, *v):
        if len(v)==1 and is_string_like(v[0]):
            s = v[0]
            if s.lower()=='on': self.gca.set_axis_on()
            elif s.lower()=='off': self.gca.set_axis_off()
            else:
                error_msg('Unrecognized string %s to axis; try on or off' %
s)
            return
        # end if
    
        try: v[0]
        except IndexError:
            xlim = self.gca.get_xlim()
            ylim = self.gca.get_ylim()
            return [xlim[0], xlim[1], ylim[0], ylim[1]]
        # end except
    
        v = v[0]
        if len(v) != 4:
            error_msg('v must contain [xmin xmax ymin ymax]')
            return
        # end if
        self.gca.set_xlim([v[0], v[1]])
        self.gca.set_ylim([v[2], v[3]])
    # end def

    def axes(self, *args, **kwargs):
        nargs = len(args)
        if len(args)==0: return subplot(111, **kwargs)
        if nargs>1:
            error_msg('Only one non keyword arg to axes allowed')
            return
        # end if
    
        arg = args[0]
        if isinstance(arg, Axes):
            self.figmgr.set_current_axes(arg)
            ret = arg
        else:
            rect = arg
            ret = self.figmgr.add_axes(rect, **kwargs)
        # end if
        return ret
    # end def

    def bar(self, *args, **kwargs):
        try: patches = self.gca.bar(*args, **kwargs)
        except Exception, msg:
            s = exception_to_str(msg)
            error_msg(s)
            raise RuntimeError(msg)
        # end except
        return patches
    # end def

    def cla(self):
        self.gca.cla()
    # end def

    def clf(self):
        self.figmgr.clf()
    # end def

    def errorbar(self, x, y, yerr=None, xerr=None, fmt='b-', ecolor='k',
capsize=3):
        try: ret = self.gca.errorbar(x, y, yerr, xerr, fmt, ecolor,
capsize)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
        else:
            return ret
        # end try
    # end def

    def figlegend(self, handles, labels, loc):
        l = self.legend(handles, labels, loc)
        return l
    # end def

    def fill(self, *args, **kwargs):
        try: patch = self.gca.fill(*args, **kwargs)
        except Exception, msg:
            s = exception_to_str(msg)
            error_msg(s)
            raise RuntimeError('Could not exectute fill')
        # end except
        return patch
    # end def

    def grid(self, b):
        self.gca.grid(b)
    # end def

    def hist(self, x, bins=10, noplot=0, normed=0, bottom=0):
        if noplot: return mlab.hist(x, bins, normed)
        else:
            try:
                ret = self.gca.hist(x, bins, normed, bottom)
            except ValueError, msg:
                msg = raise_msg_to_str(msg)
                error_msg(msg)
                raise RuntimeError, msg
            return ret
        # end if
    # end def

    def legend(self, *args, **kwargs):
        ret = self.gca.legend(*args, **kwargs)
        return ret
    # end def
        
    def plot(self, *args, **kwargs):
        try: lines = self.gca.plot(*args, **kwargs)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
        return lines
    # end def

    def savefig(self, *args, **kwargs):
        for key in ('dpi', 'facecolor', 'edgecolor'):
            if not kwargs.has_key(key):
                kwargs[key] = rcParams['savefig.%s'%key]

        self.print_figure(*args, **kwargs)
    # end def

    def scatter(self, *args, **kwargs):
        try: patches = self.gca.scatter(*args, **kwargs)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
            raise RuntimeError, msg
        return patches
    # end def

    def scatter_classic(self, *args, **kwargs):
        try: patches = self.gca.scatter_classic(*args, **kwargs)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
            raise RuntimeError, msg
        return patches
    # end def

    def stem(self, *args, **kwargs):
        try: ret = self.gca.stem(*args, **kwargs)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
        else:
            return ret
    # end def

    def subplot(self, *args, **kwargs):
        try:
            self.figmgr.add_subplot(*args, **kwargs)
            self.gca = self.figmgr.get_current_axis()
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
            raise RuntimeError, msg
        return self.gca
    # end def

    def text(self, x, y, label, fontdict=None, **kwargs):
        t = self.gca.text(x, y, label, fontdict, **kwargs)
        return t
    # end def

    def title(self, s, *args, **kwargs):
        l = self.gca.set_title(s, *args, **kwargs)
        return l
    # end def

    def vlines(self, *args, **kwargs):
        try: lines = self.gca.vlines(*args, **kwargs)
        except ValueError, msg:
            msg = raise_msg_to_str(msg)
            error_msg(msg)
            raise RuntimeError, msg
        return lines
    # end def

    def xlabel(self, s, *args, **kwargs):
        l = self.gca.set_xlabel(s, *args, **kwargs)
        return l
    # end def

    def ylabel(self, s, *args, **kwargs):
        l = self.gca.set_ylabel(s, *args, **kwargs)
        return l
    # end def

#---------------------------------------------------------------------------
# class MatFrame(wx.MDIChildFrame):
class MatFrame(wx.Frame):
    
    def __init__(self, parent):
        #wx.MDIChildFrame.__init__(self, parent, -1, "Matlab WX interface",
        # size=(600,600))
        wx.Frame.__init__(self, None, -1, "Matlab WX interface",
                          size=(600,600))

        self.figure = figure = MatlabFigure(self)
        # histg = figure.hist([1,2,3,4,5,6,7,7,8,9,1,23,4,5,5,6])
        histg = figure.bar([1,2,3,4], [10,15, 7, 3], width=1)
        line1 = figure.plot([1,2,3,4], [2,3,6,7], 'b-')
        line2 = figure.plot([0,10,20], [0,10,20], 'g')
        figure.axis([0,30,0,20])
        
        figure.grid(1)
        figure.xlabel('Confidence', {'fontsize': 'small'})
        figure.ylabel('Count', {'fontsize': 'small'})
        figure.legend((line1, line2, histg),
                      ('line1', 'line2', 'histg'),
                      'upper right')
        figure.title('Confidence Histogram')
        
        figure.Bind(wx.EVT_LEFT_DOWN, self.OnSelectBucket)
    # end def
        
    def OnSelectBucket(self, event):
        xy = self.figure.GetXY(event)
        print xy
    # end def

#---------------------------------------------------------------------------
class MatlabMDI(wx.MDIParentFrame):

    def __init__(self):
        wx.MDIParentFrame.__init__(self, None, -1, "Matlab
MDI",size=(900,700))
        MatFrame(self)
        self.Show()
    # end def

class App(wx.App):
    """Application class."""

    def OnInit(self):
        #MatlabMDI()
        frame = MatFrame(self)
        frame.Show()

        for i in range(100):
            frame.figure.draw()
        # end for
        
        #self.xframe = MatFrame()
        #self.xframe.Show()
        #self.xframe.grid(0)
        return True
    # end def

#---------------------------------------------------------------------------
if __name__ == '__main__':
    app = App()
    app.MainLoop()

-----Original Message-----
From: John Hunter [mailto:jdhunter@…4…]
Sent: Tuesday, June 29, 2004 10:47 AM
To: Schalkwyk, Johan
Cc: matplotlib-users@lists.sourceforge.net
Subject: Re: [Matplotlib-users] Assertion triggered in wxMemory DC

"Schalkwyk," == Schalkwyk, Johan <Johan.Schalkwyk@...227...>

writes:

    Schalkwyk,> Thank you for the help I removed the show() command
    Schalkwyk,> from the loop. Now just calling grid(True) multiple
    Schalkwyk,> times. On my machine I narrowed the loop to 57 and it
    Schalkwyk,> started happening. At 50 it did not.

Perhaps I didn't make myself clear. The way you are using matplotlib
does not make sense. matplotlib has two modes: a "matlab interface"
and an embedded interface. You should not embed the matlab interface
directly into a GUI. The matlab interface does a lot of stuff under
the hood, like creating and managing figures and figure windows,
managing redraws, etc. When you create your own figure window outside
this framework, and then try to use the framework, the result is
undefined. If you are using matplotlib in a GUI, *do not import
matplotlib.matlab*. You need to follow the example of
embedding_in_wx2.py.

Below is your example translated to the GUI interface - on my system,
calling grid until the sun sets presents no problems, and it really
couldn't because all it does is set a boolean. In the matlab
interface, if you have interactive: True in your rc file, calling grid
does a lot more, including repainting the figure. Try running this
example, shaking it, resizing it, etc... and see if you can crash it;
I was unable to cause any problems.

If you have trouble, please let me know, but also consider trying
replacing wx for wxagg, which uses antigrain for drawing and is
probably more stable than wx, which does occasionally show dc related
errors.

By the way, there was an error in your legend code

You had

  legend('line', blahblah)

and you need

  legend( ('line',), blahblah)

That is, legend expects a list or tuple of strings, not a string.

    Schalkwyk,> By the way Kudos for matplotlib. Amazing. I had to dig
    Schalkwyk,> around the code and news groups to figure out how to
    Schalkwyk,> find the user coordinates of a mouse click. Reading
    Schalkwyk,> the code opens your eyes the wonderful design that is
    Schalkwyk,> backend dependent.

Thanks. Do you have the src distribution? There is an example in the
examples directory examples/coords_demo.py (works with Tk, GTK and WX)
that shows you how to get the mouse click coordinates. The examples
dir is your first line of defense when you want to figure out
something new. Unfortunately, I forgot to upload the zip file with
the 0.54.2 release, so look here

http://matplotlib.sf.net/examples

Here's the example:

#!/usr/bin/env python
"""
An example of how to use wx or wxagg in an application w/o the toolbar
"""

from matplotlib.numerix import arange, sin, pi
import matplotlib
matplotlib.use('WX')
from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas

from matplotlib.figure import Figure

from wxPython.wx import *

class CanvasFrame(wxFrame):
    
    def __init__(self):
        wxFrame.__init__(self,None,-1,
                         'CanvasFrame',size=(550,350))

        self.SetBackgroundColour(wxNamedColor("WHITE"))

        self.figure = Figure(figsize=(5,4), dpi=100)
        self.ax = self.figure.add_subplot(111)
        t = arange(0.0, 2.0, 0.01)
        s = sin(2*pi*t)
        l = self.ax.plot(t, s, linewidth=1.0)
        self.ax.set_xlabel('time (s)')
        self.ax.set_ylabel('voltage (mV)')
        self.ax.set_title('About as simple as it gets, folks')
        self.ax.legend(('line',), loc='upper right')

        for i in range(100):
            self.ax.grid(True)
        self.canvas = FigureCanvas(self, -1, self.figure)

        self.sizer = wxBoxSizer(wxVERTICAL)
        self.sizer.Add(self.canvas, 1, wxTOP | wxLEFT | wxEXPAND)
        # Capture the paint message
        EVT_PAINT(self, self.OnPaint)

    def OnPaint(self, event):
        self.canvas.draw()
        
class App(wxApp):
    
    def OnInit(self):
        'Create the main window and insert the custom frame'
        frame = CanvasFrame()
        frame.Show(true)

        return true

app = App(0)
app.MainLoop()