Reputation: 2157
This site shows many (all?) rc parameters that can be adjusted in Matplotlib plots, either through the matplotlibrc
file or using matplotlib.rcParams[]
in a Python script. I can see no way to adjust the width of the border box of a legend using the parameters listed in that site. I know it is possible to change the line width of the box "manually", i.e., in the script (for example), but I'm hoping for a way to set it using matplotlib.rcParams[]
or in a matplotlibrc
file. How could I do this?
The reason I care to have an automated, external (or at least easily copy-and-pastable) is because I have several figures, with several different Python scripts producing these several figures, and I would like as easy a way as possible to maintain a standard look between each of these figures, across the different Python scripts.
In some scripts I call for a legend as pyplot.legend()
and in others I call for it as ax.legend()
.
Upvotes: 3
Views: 4465
Reputation: 114350
Depending on what you are trying to do, it may in fact be possible to set the width of the legend border via rcParams
.
TL;DR
Set patch.linewidth
in matplotlibrc
or better yet, write a two-line wrapper function for legend
and use that instead in your scripts.
Long Version
Looking at the code for legend
, you can see that the frame stored as a matplotlib.patched.FancyBBoxPatch
object, which is a type of matplotlib.patches.Patch
. Patch
objects get their default line width from matplotlib.rcParams['patch.linewidth']
. This means that if you set patch.linewidth
in matplotlibrc
, the size of the legend border will change.
A similar modification to patch.edgecolor
will change the border color, but patch.facecolor
will be ignored for legends.
Here is a code sample to illustrate the change, with some outputs:
>>> import matplotlib as mpl
>>> from matplotlib import pyplot as plt
>>> mpl.rcParams['patch.linewidth']
1.0
>>> plt.plot((0, 1), label='a')[0].axes.legend()
<matplotlib.legend.Legend object at 0x7f6d7b0a0e48>
>>> mpl.rcParams['patch.linewidth'] = 15
>>> plt.plot((0, 1), label='a')[0].axes.legend()
<matplotlib.legend.Legend object at 0x7f6d7ae20908>
The obvious issue here is that if you draw any other patches on your charts, the default line width will be thrown off. You can of course mitigate this by "manually" changing the line width back to 1 for all the patches you create. Clearly this is not an optimal solution.
A Better Way
A much better solution would be to create a small script that you would share between all your chart generation scripts. Here is a sample of such a script:
from matplotlib.axes import Axes
def add_legend(ax, *args, **kwargs):
"""
Adds a legend to the specified axes, along with some common formatting. All additional arguments are the same as for `ax.legend`.
"""
legend = _originalFn(ax, *args, **kwargs)
legend.set_linewidth(15)
return legend
if Axes.legend is not add_legend:
_originalFn = Axes.legend
Axes.legend = add_legend
This script is structured in such a way that you do not ever need to call add_legend
manually. Just importing the script subclasses matplotlib.axes.Axes
so that calling ax.legend(...)
as before will set the default legend border width to 15 points.
The script above will work for calls to ax.legend
where ax
is an Axes
instance and on plt.legend
, since plt.legend
really just delegates to gca().legend
with some additional processing.
This subclassing mechanism will work even if your program consists of multiple scripts/modules which import the shared script. This is because Python will not actually reload the module after the first time, and will instead just return a reference to it, with all attributes intact. Things will break if you start using importlib.reload
, but that is only a very remote possibility.
Upvotes: 5