Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify matplotlib legend after it has been created?

I have access to the figure instance fig = pylab.gcf(). I know that in this figure there is a legend and I can access it via myLegend = fig.gca().legend_. Now I want to change the properties of the legend. Some of them I have access via setters like myLegend.set_frame_on(True).

When the legend is created it accepts a number of keyword arguments:

class matplotlib.legend.Legend(parent, handles, labels, loc=None, numpoints=None, markerscale=None, scatterpoints=None, scatteryoffsets=None, prop=None, fontsize=None, borderpad=None, labelspacing=None, handlelength=None, handleheight=None, handletextpad=None, borderaxespad=None, columnspacing=None, ncol=1, mode=None, fancybox=None, shadow=None, title=None, framealpha=None, bbox_to_anchor=None, bbox_transform=None, frameon=None, handler_map=None)

How can I modify all the keyword arguments in the legend after the legend is created?

One of the problematic ones is numpoints (number of markers in a legend, default is 2). Below is the example how I want to change it:

This shows how I want to program it

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")
# no modifications above this line
setattr(pylab.gcf().gca().legend_, 'numpoints',1)
pylab.show()

This shows how I want it to look like

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(numpoints = 1, loc = "lower left")
pylab.show()

I have cheked the source code, there is a numpoint variable that is changed, but the upper case is not updated to screen. What am I missing?

like image 789
Juha Avatar asked May 15 '14 22:05

Juha


1 Answers

I've written a function modify_legend which modifies a legend after it has been created. It basically reads all the parameters from the already created legend, updates it with the key-value parameters you provided and calls legend(...) with all possible parameters again.

Your problem would then be solved with:

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")

modify_legend(numpoints = 1)

pylab.show()

Here's the code for modify_legend:

def modify_legend(**kwargs):
    import matplotlib as mpl

    l = mpl.pyplot.gca().legend_

    defaults = dict(
        loc = l._loc,
        numpoints = l.numpoints,
        markerscale = l.markerscale,
        scatterpoints = l.scatterpoints,
        scatteryoffsets = l._scatteryoffsets,
        prop = l.prop,
        # fontsize = None,
        borderpad = l.borderpad,
        labelspacing = l.labelspacing,
        handlelength = l.handlelength,
        handleheight = l.handleheight,
        handletextpad = l.handletextpad,
        borderaxespad = l.borderaxespad,
        columnspacing = l.columnspacing,
        ncol = l._ncol,
        mode = l._mode,
        fancybox = type(l.legendPatch.get_boxstyle())==mpl.patches.BoxStyle.Round,
        shadow = l.shadow,
        title = l.get_title().get_text() if l._legend_title_box.get_visible() else None,
        framealpha = l.get_frame().get_alpha(),
        bbox_to_anchor = l.get_bbox_to_anchor()._bbox,
        bbox_transform = l.get_bbox_to_anchor()._transform,
        frameon = l._drawFrame,
        handler_map = l._custom_handler_map,
    )

    if "fontsize" in kwargs and "prop" not in kwargs:
        defaults["prop"].set_size(kwargs["fontsize"])

    mpl.pyplot.legend(**dict(defaults.items() + kwargs.items()))

Notes on the code:

  • Some parameters could easily be read from the Legend object, others (like title, fancybox) required some 'artistics'. You could check matplotlib.legend.Legend.__init__ to see how and why it's done.
  • The extra condition on the fontsize parameter is used for overriding the font size when the legend was originally created with a prop, as prop usually overwrites fontsize.
  • I did not test all the cases as I don't have much time (especially the bbox_to_anchor and bbox_transform-parameters), so feel free to try out and improve the code :)
like image 75
Peater de Xel Avatar answered Oct 22 '22 04:10

Peater de Xel