Matplotlib: make a legend square

I work with matplotlib and would like to change the keys in my legends as squares instead of rectangles when I do, for example, line art. Is there any way to indicate this?

What I have now:

enter image description here

What I want:

enter image description here

Thanks!

+3
python matplotlib
source share
3 answers

You can define your own legend keys.

The line in my answer is created using matplotlib barchart demo . (I deleted the error lines). The matplotlib usage guide explains how to define a class to replace legend keys with ellipses. I modified this class to use squares (using rectangular patches ).

import numpy as np from matplotlib.legend_handler import HandlerPatch import matplotlib.pyplot as plt import matplotlib.patches as mpatches # Define square (rectangular) patches # that can be used as legend keys # (this code is based on the legend guide example) class HandlerSquare(HandlerPatch): def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): center = xdescent + 0.5 * (width - height), ydescent p = mpatches.Rectangle(xy=center, width=height, height=height, angle=0.0) self.update_prop(p, orig_handle, legend) p.set_transform(trans) return [p] # this example is the matplotlib barchart example: N = 5 menMeans = (20, 35, 30, 35, 27) ind = np.arange(N) # the x locations for the groups width = 0.35 # the width of the bars fig, ax = plt.subplots() rects1 = ax.bar(ind, menMeans, width, color='r') womenMeans = (25, 32, 34, 20, 25) rects2 = ax.bar(ind+width, womenMeans, width, color='y') # add some text for labels, title and axes ticks ax.set_ylabel('Scores') ax.set_title('Scores by group and gender') ax.set_xticks(ind+width) ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') ) # append the new patches to the legend-call: ax.legend( (rects1[0], rects2[0]), ('Men', 'Women'), handler_map={rects1[0]: HandlerSquare(), rects2[0]: HandlerSquare()}) plt.show() 

Having defined the class HandlerSquare , you can now apply this to each legend entry as the third argument to invoke ax.legend . Note the syntax:

 handler_map={rects1[0]: HandlerSquare(), rects2[0]: HandlerSquare()} 

handler_map must be a dictionary.

This will give you this plot:

enter image description here

+1
source share

If you need a very quick and dirty solution to get an approximate square (which may require some tweaking depending on your schedule), you can configure handlelength kwarg in the legend call. Following Schorsch's decision (i.e., as soon as you have a list of rectangular legend artists and associated labels):

 ax.legend((rects1[0], rects2[0]), ('Men', 'Women'), handlelength=0.7) 

See matplotlib legend() docs for more details.

+5
source share

Changing the handlelength globally affects the width of other markers in the legend. Therefore, this solution will be incompatible with, for example, a combination of points and lines. Instead, you can simply add a square dot marker to the legend using Line2D . You just need to set the associated string to zero width:

 rect1 = mlines.Line2D([], [], marker="s", markersize=30, linewidth=0, color="r") rect2 = mlines.Line2D([], [], marker="s", markersize=30, linewidth=0, color="y") ax.legend((rect1, rect2), ('Men', 'Women')) 
+2
source share

All Articles