Problem: Multiple plots with same variables plot incorrectly.

I have some simple code (I've cut it down a lot, but kept the problem) that tries to plot two sets of data using the same variables. It appears that re-using the variables from the first plot for the second plot affects the first plot. In fact the two plots become identical. I am guessing that the variables used in the 1st plot are pointed to by other matplotlib internal variables (but not plotted until Show() is called -- a guess on my part). In Python fashion when I change a variable in preparation for the 2nd plot, the values in the 1st plot change, too.

Here is sample code based on some code sent to me by Jeremy O'Donoghue as an example of how to embed matplotlib in wxPython. The problem is in the method plot_data in the PlotFigure class. Note how x and y are reused for the 2nd plot. The output should be an 'X' shape, but only one line shows up, the 2nd plot line. If you add new variables to do the 2nd plot (e.g. u=zeroes((2,),Float), v=zeroes((2,),Float)) and replace the x and y in the 2nd plot with those variables, then it works correctly.

Is this good matplotlib behavior? Is it necessary to use new variables for each call of plot?

I am using wxPython wx-2.6-mac-unicode, matplotlib 0.82, Python 2.4, on a Macintosh Powerbook G4, OS X 10.4

--------------------------------- The code (self contained as run from BBEdit through the Terminal):

#!/usr/local/bin/pythonw

from Numeric import *
import matplotlib
matplotlib.use('WX')
from matplotlib.backends.backend_wx import Toolbar, FigureCanvasWx,\
     FigureManager

from matplotlib.figure import Figure
from matplotlib.axes import Subplot
import matplotlib.numerix as numpy
import wx
   class PlotFigure(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Test embedded wx.Figure")

        self.fig = Figure((10,8), 75)
        self.canvas = FigureCanvasWx(self, -1, self.fig)
        self.toolbar = Toolbar(self.canvas)
        self.toolbar.Realize()

        # On Windows, default frame size behaviour is incorrect
        # you don't need this under Linux
        tw, th = self.toolbar.GetSizeTuple()
        fw, fh = self.canvas.GetSizeTuple()
        self.toolbar.SetSize(wx.Size(fw, th))

        # Create a figure manager to manage things
        self.figmgr = FigureManager(self.canvas, 1, self)
        # Now put all into a sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        # This way of adding to sizer allows resizing
        sizer.Add(self.canvas, 1, wx.LEFT|wx.TOP|wx.GROW)
        # Best to allow the toolbar to resize!
        sizer.Add(self.toolbar, 0, wx.GROW)
        self.SetSizer(sizer)
        self.Fit()

    # *** HERE'S THE PROBLEM PART ***
    def plot_data(self):
        # Use ths line if using a toolbar
        a = self.fig.add_subplot(111)
               # Or this one if there is no toolbar
        #a = Subplot(self.fig, 111)
        x=zeros((2,),Float)
        y=zeros((2,),Float)
               # 1st Plot .................
        x[0]= 1.0
        y[0]= 1.0
        x[1]=-1.0
        y[1]=-1.0
        a.plot(x,y)

        # 2nd Plot .................
        x[0]=-1.0
        y[0]= 1.0
        x[1]= 1.0
        y[1]=-1.0
        a.plot(x,y)
               self.toolbar.update()

    def GetToolBar(self):
        # You will need to override GetToolBar if you are using an
        # unmanaged toolbar in your frame
        return self.toolbar
       if __name__ == '__main__':
    # Plot
    app = wx.PySimpleApp(0)
    frame = PlotFigure()
    frame.plot_data()
    frame.Show()
    app.MainLoop()

···

--
Cheers,

Lou Pecora

Code 6362
Naval Research Lab
Washington, DC 20375
USA
Ph: +202-767-6002
email: pecora@...1125...

Is this good matplotlib behavior?

I think so. It is Python behavior.
You are using a mutable object,
and the plot of this object changes
when you chage the object.

Is it necessary to use new variables for each call of
plot?

No. Just assign a new object to the name,
rather than changing the existing object.

hth,
Alan Isaac

···

On Wed, 31 May 2006, Louis Pecora wrote:

Louis,

This is standard num* array behavior: arrays are mutable, and MPL is not making copies of them when you plot, which is a good thing.

by the way, slices of arrays are references too, which is different than python lists, so it can be surprising, but also useful

             # 1st Plot .................
       x[0]= 1.0
       y[0]= 1.0
       x[1]=-1.0
       y[1]=-1.0
       a.plot(x,y)

       # 2nd Plot .................

now you need copies. You can make brand new ones, or use the copy() method:
x = x.copy()
y = y.copy()

you could also pass a copy into the plot method:

a.plot(x.copy(), y.copy())

which is perhaps the behavior you were expecting.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...

Christopher Barker wrote:

Louis,

This is standard num* array behavior: arrays are mutable, and MPL is not making copies of them when you plot, which is a good thing.

by the way, slices of arrays are references too, which is different than python lists, so it can be surprising, but also useful

             # 1st Plot .................
       x[0]= 1.0
       y[0]= 1.0
       x[1]=-1.0
       y[1]=-1.0
       a.plot(x,y)

       # 2nd Plot .................

now you need copies. You can make brand new ones, or use the copy() method:
x = x.copy()
y = y.copy()

you could also pass a copy into the plot method:

a.plot(x.copy(), y.copy())

which is perhaps the behavior you were expecting.

-Chris

Thanks, Chris. I sort of figured this out, but you put it clearer and I like the copy suggestion. I'll use it. It sure drove me nuts for a while. :slight_smile:

···

--
Cheers,

Lou Pecora

Code 6362
Naval Research Lab
Washington, DC 20375
USA
Ph: +202-767-6002
email: pecora@...1125...