bizarre legend behavior

John, First things first. Thanks for all your help. I

    > wasn't aware of the figlegend command (even though it is
    > clearly in the documentation). I can do what I want with
    > figlegends althought it takes some fiddling to get the
    > positions right. I have to use explicit coordinates because
    > the legends are referenced to the figure not the axes so
    > the boxes don't default to lying inside the graphs and
    > cross over the axes boundaries. In addition the legends
    > are in separate boxes with figlegend, which is acceptable,
    > but not necessarily optimal. I did run into another problem
    > using figlegend, namely that I can't get a handle to the
    > legend text so I'm not able to set the fontsize. I'd
    > appreciate it if you could illuminate me with how to set
    > fontsize in a figlegend.

The way to come to this knowledge is:

  1) look at the return value of the figlegend command - in this case
     the docs don't say what they are, but you can always print
     type(ret) or simply print(ret) where ret is the return value of
     figlegend to get an idea. I've updated the docs to state

    A matplotlib.legend.Legend instance is returned

  2) Go to the class documentation, either by doing

     help(ret) from the python shell or going to
     http://matplotlib.sourceforge.net/classdocs.html and clicking on
     the legend link
     http://matplotlib.sourceforge.net/matplotlib.legend.html.

  3) Peruse the docs for Legend: in this case you'll see

        get_frame(self)
           return the Rectangle instance used to frame the legend

        get_lines(self)
           return a list of lines.Line2D instances in the legend

        get_patches(self)
           return a list of patch instances in the legend

        get_texts(self)
           return a list of text.Text instance in the legend

So you can do

  leg = figlegend(blah, blah)
  texts = leg.get_texts() # get a sequence of legend texts
  lines = leg.get_lines() # get a sequence of legend lines
  patches = leg.get_patches() # get a sequence of legend patches

I don't mind you asking - I'm just trying to give you some pointers
for future reference.

    > In addition the legends are in separate boxes with
    > figlegend, which is acceptable, but not necessarily
    > optimal.

Not sure exactly what you mean. You can put them in the same box by
controlling the list of handles and text strings you pass figlegend,
or you can turn the legend frames off....

  leg.draw_frame(False)

    > So, on to other things. I cooked up an example that shows
    > what I was originally trying to do. I have two routines,
    > doPlots1 and doPlots2, that do exactly the same thing. The
    > only difference is in the default arguments, which I don't
    > actually set, I just use the default. Figure 1 has the
    > effect I was looking for, although I for the life of me
    > don't understand why the two routines give difference
    > answers, or for that matter, why figure 1 works the way it
    > does.

    > In any case. Figure 1 is what I was shooting for. If you
    > want to post some reliable code that does this, I'd
    > appreciate it.

See my comments below:

from matplotlib.matlab import *
import Numeric as N

# It is bad form to import Numeric or numarray after importing
# matplotlib. This is what numerix is for. You should use import
# matplotlib.numerix as N if you want to namespace Numeric. The
# command from matplotlib.matlab import * already imports all the
# numerix symbols.

def doPlots1(const,color,legendList=,legendTextList=):

# In passing the empty list as a default argument, you are sharing the
# list between function calls. This explains why doPlots1 *works* and
# doPlots2 doesn't. This is a well know gotcha. The default
# arguments are evaluated *only once* at module load time, so
# legendList and legendText list are *the same* lists between function
# calls

  y1=N.arange(0., 10, 1)+ const
  x = arange(len(y1))
  
   ln1 = plot(x,y1,color+'+-')
  legendList.append(ln1)

# ln1 is a length 1 list, not a line! You should do (note the comma)

···

#
# ln1, = plot(x,y1,color+'+-')
#
# to unpack the length one sequence. You only get a way with it
# because legend flattens the list for you

  legendTextList.append('line1')
  
  y2 = y1 + 1
  ln2 = plot(x,y2,color+'^-')
  legendList.append(ln2)
  legendTextList.append('line2')

  legend(legendList,legendTextList)
  show()

# You should only call "show" once per script. I repeat, you should
# only call "show" once per script. If you want to force a redraw use
# get_current_fig_manager().canvas.draw(). The next matplotlib
# release defines a "draw" function for this purpose.
  
def doPlots2(const,color):
  legendList=
  legendTextList=

# Here legendList and legendTextList are local to the function, not
# shared between function calls

  y1=N.arange(0., 10, 1)+ const
  x = arange(len(y1))
  
  ln1 = plot(x,y1,color+'+-')
  legendList.append(ln1)
  legendTextList.append('line1')
  
  y2 = y1 + 1
  ln2 = plot(x,y2,color+'^-')
  legendList.append(ln2)
  legendTextList.append('line2')

  legend(legendList,legendTextList)
  show()

figure(1)
doPlots1(0,'r')
doPlots1(5,'b')

figure(2)
doPlots2(0,'r')
doPlots2(5,'b')

    > In any case. Figure 1 is what I was shooting for. If you
    > want to post some reliable code that does this, I'd
    > appreciate it.

While I don't know exactly what you are shooting for, the code below
replicates what Figure 1 looks like after your second call to
doPlots1.

from matplotlib.matlab import *

handles =
labels =

for const, color in ( (0, 'r'), (5, 'b') ):
    y1 = arange(0., 10, 1)+ const
    x = arange(len(y1))

    y2 = y1 + 1
    lines = plot(x, y1, color+'+-', x, y2, color+'^-' )
    handles.extend(lines)
    labels.extend(('line1', 'line2'))

legend(handles, labels, 'upper left')
show()

Here's another approach using the label keyword arg

from matplotlib.matlab import *

handles =
labels =

for const, color in ( (0, 'r'), (5, 'b') ):
    y1 = arange(0., 10, 1)+ const
    x = arange(len(y1))
    y2 = y1 + 1
    plot(x, y1, color+'+-', label='line1')
    plot(x, y2, color+'^-', label='line2' )

legend()
show()

Hope this helps!

JDH