placing legend outside of plot area

Hi All,

How would I go about placing the legend outside the plot area?

All the parameters to legend seem to place the legend somewhere within the plot and I'd like to place it outside the plot, either above, below or, most commonly, to the right, in the same way as the Excel legend positions allow.

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hello Chris,

I'm not sure if there was an example in matplotlib, but the following works
for me:

···

---------------------------------------------------------------------
from pylab import *
figure()
subplot(111)
subplots_adjust(right=0.7)
plot(arange(10), label='linear')
plot(arange(10)**2, label='quadratic')
legend(loc=(1.1,0.5))
show()
------------------------------------------------------------------------

I hope this is useful to you.

best regards
Matthias

On Monday 17 March 2008 12:42, Chris Withers wrote:

Hi All,

How would I go about placing the legend outside the plot area?

All the parameters to legend seem to place the legend somewhere within
the plot and I'd like to place it outside the plot, either above, below
or, most commonly, to the right, in the same way as the Excel legend
positions allow.

cheers,

Chris

Hi Matthias,

Matthias Michler wrote:

I'm not sure if there was an example in matplotlib, but the following works for me:
---------------------------------------------------------------------
from pylab import *
figure()
subplot(111)
subplots_adjust(right=0.7)
plot(arange(10), label='linear')
plot(arange(10)**2, label='quadratic')
legend(loc=(1.1,0.5))
show()
------------------------------------------------------------------------

Thanks for this. This is exactly what I was after except that the legend now appears about 25% off the right hand of the screen or whatever I save the figure to.

How can I have the legend as placed above but with the whole of it showing?

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hi Chris,

sorry I don't understand what you are exactly looking for. Maybe you could
explain it once more.
In general I think all one can do is to play around with the parameters
in 'subplots_adjust' and the location in 'legend' to get the best result.
I'm not an expert but I think there's no default behaviour covering all needs
(outside the axes and best located), because for example the legend width is
influenced by the length of the labels.

much effort and best regards
Matthias

···

On Monday 17 March 2008 17:13, Chris Withers wrote:

Hi Matthias,

Matthias Michler wrote:
> I'm not sure if there was an example in matplotlib, but the following
> works for me:
> ---------------------------------------------------------------------
> from pylab import *
> figure()
> subplot(111)
> subplots_adjust(right=0.7)
> plot(arange(10), label='linear')
> plot(arange(10)**2, label='quadratic')
> legend(loc=(1.1,0.5))
> show()
> ------------------------------------------------------------------------

Thanks for this. This is exactly what I was after except that the legend
  now appears about 25% off the right hand of the screen or whatever I
save the figure to.

How can I have the legend as placed above but with the whole of it showing?

cheers,

Chris

Matthias Michler wrote:

sorry I don't understand what you are exactly looking for. Maybe you could explain it once more.

Well, what you provided was pretty close, it's just that the legend was partly placed outside the figure...

In general I think all one can do is to play around with the parameters in 'subplots_adjust' and the location in 'legend' to get the best result. I'm not an expert but I think there's no default behaviour covering all needs (outside the axes and best located), because for example the legend width is influenced by the length of the labels.

Right, this is the problem. The location your example provided is perfect, except that I may have no control over the length of the legend text, and so need to find a way to make sure the figure size is such that the legend doesn't end up being half off the figure...

Anyone know how to do that?

(and thanks to Matthias for all his help! :slight_smile: )

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

It sounds like what you want it the pyplot figlegend command:
def figlegend(handles, labels, loc, **kwargs):
     """
     Place a legend in the figure. Labels are a sequence of
     strings, handles is a sequence of line or patch instances, and
     loc can be a string r an integer specifying the legend
     location

     USAGE:
       legend( (line1, line2, line3),
               ('label1', 'label2', 'label3'),
               'upper right')

     See help(legend) for information about the location codes

     A matplotlib.legend.Legend instance is returned
     """

or you could directly use the Figure.legend method. The relevant part of the docstring regarding placement in the figure is here:

         The LOC location codes are

           'best' : 0, (currently not supported for figure legends)
           'upper right' : 1,
           'upper left' : 2,
           'lower left' : 3,
           'lower right' : 4,
           'right' : 5,
           'center left' : 6,
           'center right' : 7,
           'lower center' : 8,
           'upper center' : 9,
           'center' : 10,

         loc can also be an (x,y) tuple in figure coords, which
         specifies the lower left of the legend box. figure coords are
         (0,0) is the left, bottom of the figure and 1,1 is the right,
         top.

Eric

Chris Withers wrote:

···

Matthias Michler wrote:

sorry I don't understand what you are exactly looking for. Maybe you could explain it once more.

Well, what you provided was pretty close, it's just that the legend was partly placed outside the figure...

In general I think all one can do is to play around with the parameters in 'subplots_adjust' and the location in 'legend' to get the best result. I'm not an expert but I think there's no default behaviour covering all needs (outside the axes and best located), because for example the legend width is influenced by the length of the labels.

Right, this is the problem. The location your example provided is perfect, except that I may have no control over the length of the legend text, and so need to find a way to make sure the figure size is such that the legend doesn't end up being half off the figure...

Anyone know how to do that?

(and thanks to Matthias for all his help! :slight_smile: )

cheers,

Chris

Eric Firing wrote:

It sounds like what you want it the pyplot figlegend command:
def figlegend(handles, labels, loc, **kwargs):

This feels like what I should be wanting except:

- why does it need explicit parameters? why can't it pick up its lines and labels automatically, like legend does?

- it places the legend over the top of the current chart, I want it to the right, so it doesn't obscure the information on the chart...

or you could directly use the Figure.legend method.

How does this differ from the normal legend command?
How do I get hold of a figure to call its legend method?
How does figure.legend interact with subplots?

I have a bout 6 subplots on the same figure(?) and they each need to have a legend which is not obscuring the data plotted and isn't obscuring any other figure...

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Eric Firing wrote:
> It sounds like what you want it the pyplot figlegend command:
> def figlegend(handles, labels, loc, **kwargs):

This feels like what I should be wanting except:

- why does it need explicit parameters? why can't it pick up its lines
and labels automatically, like legend does?

- I think this could be a good improvement, but i'm not sure if it is easy to
expand the functionality of the axes-legend (pyplot.legend or ax.legend) to
that of a figure-legend(pyplot.figlegend or fig.legend with fig as a figure
instance) without missing something, because there is no axes specified and
therefore it is not obvious which lines should be displayed. In that case the
default behaviour might become to take all lines from all axes and that's not
what one always needs, or isn't it?

In this case one should do it autonomous like:

ax1 = subplot(111)
# some plotting commands
labels =
for line in ax1.lines:
     label = line.get_label()
     labels.append(label)
# or in one line:
# labels = [line.get_label() for line in ax1.lines]
figlegend(ax1.lines, labels, 'upper right')

- it places the legend over the top of the current chart, I want it to
the right, so it doesn't obscure the information on the chart...

That's true and I have no idea how to overcome that (except for example
subplot_adjust(top=0.8)).

> or you could directly use the Figure.legend method.

How does this differ from the normal legend command?
How do I get hold of a figure to call its legend method?

fig=figure()
fig.legend( ... )
and it is wrapped by
figlegend( ... )
and therefore has the same functionality / arguments

and it differs from the axes-legend like explained above ...

How does figure.legend interact with subplots?

I'm don't know, but maybe it doesn't interact with the axes / subplots at all.

I have a bout 6 subplots on the same figure(?) and they each need to
have a legend which is not obscuring the data plotted and isn't
obscuring any other figure...

I think in that case the axes-legend is the preferred one, but I have no idea
how to ensure that nothing is cover by the legend without difficult tuning of
the parameters or at least ensure that all labels have the same widths.

best regards
Matthias

···

On Tuesday 18 March 2008 10:50, Chris Withers wrote:

Matthias Michler wrote:

- I think this could be a good improvement, but i'm not sure if it is easy to expand the functionality of the axes-legend (pyplot.legend or ax.legend) to that of a figure-legend(pyplot.figlegend or fig.legend with fig as a figure instance) without missing something, because there is no axes specified and therefore it is not obvious which lines should be displayed.

True, although if there's only one axes, it's obvious :wink:
(and if there's more than one, it should take an axes as a keyword parameter)

In that case the default behaviour might become to take all lines from all axes and that's not what one always needs, or isn't it?

Who knows, maybe someone would want that? The joy of building generic tools :wink:

ax1 = subplot(111)
# some plotting commands
labels =
for line in ax1.lines:
     label = line.get_label()
     labels.append(label)
# or in one line: # labels = [line.get_label() for line in ax1.lines]
figlegend(ax1.lines, labels, 'upper right')

Yes, you see, it just feels to me like figlegend should have this code in it as it's likely to be duplicated every time I need to call figlegend.

Why not just?

figlegend(axes=ax1,'upper right')

- it places the legend over the top of the current chart, I want it to
the right, so it doesn't obscure the information on the chart...

That's true and I have no idea how to overcome that (except for example subplot_adjust(top=0.8)).

Yes, I'm just making do with this for now, but it would be really nice if MPL supported legends outsite the axes properly.

It would also be good if you didn't have to manually fiddle with subplot_adjust because you rotated the labels for the x-axis through 90 degrees :frowning:

How does figure.legend interact with subplots?

I'm don't know, but maybe it doesn't interact with the axes / subplots at all.

'badly' I think is the best summary of the interaction :wink:

I think in that case the axes-legend is the preferred one, but I have no idea how to ensure that nothing is cover by the legend without difficult tuning of the parameters or at least ensure that all labels have the same widths.

Yeah :-/ This is where I am... If anyone has any magic code or suggestions, I'd love to hear 'em :wink:

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk