14

I'm using the following code to create a custom matplotlib legend.

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
colors = ["g", "w"]
texts = ["Green Data Description", "RedData Description"]
patches = [ mpatches.Patch(color=colors[i], label="{:s}".format(texts[i]) ) for i in range(len(texts)) ]
plt.legend(handles=patches, bbox_to_anchor=(0.5, 0.5), loc='center', ncol=2 )

The resulted legend is as follows:

enter image description here

1 - The white symbol in the legend is not shown because that the default legend background is white as well. How can I set the legend background to other color ?

2 - How to change the rectangular symbols in the legend into circular shape ?

Hesham Eraqi
  • 2,444
  • 4
  • 23
  • 45

3 Answers3

24

Try this:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
from matplotlib.legend_handler import HandlerPatch
colors = ["g", "w"]
texts = ["Green Data Description", "RedData Description"]
class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=width + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]


c = [ mpatches.Circle((0.5, 0.5), 1, facecolor=colors[i], linewidth=3) for i in range(len(texts))]
plt.legend(c,texts,bbox_to_anchor=(0.5, 0.5), loc='center', ncol=2, handler_map={mpatches.Circle: HandlerEllipse()}).get_frame().set_facecolor('#00FFCC')
plt.show()

output:

enter image description here

Update:

To circle, set width equals to height, in mpatches.Ellipse

Remove the outer black line, set edgecolor="none" in mpatches.Circle

code:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
from matplotlib.legend_handler import HandlerPatch
colors = ["g", "w"]
texts = ["Green Data Description", "RedData Description"]
class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=height + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]


c = [ mpatches.Circle((0.5, 0.5), radius = 0.25, facecolor=colors[i], edgecolor="none" ) for i in range(len(texts))]
plt.legend(c,texts,bbox_to_anchor=(0.5, 0.5), loc='center', ncol=2, handler_map={mpatches.Circle: HandlerEllipse()}).get_frame().set_facecolor('#00FFCC')
plt.show()

New Picture:

enter image description here

Tiny.D
  • 6,466
  • 2
  • 15
  • 20
  • Thant's exactly what I needed. Thank you. But how to edit the ellipse dimensions to make it a circle ? How to remove its outer black outline ? – Hesham Eraqi May 21 '17 at 22:06
15
  1. Setting the legend's background color can be done using the facecolor argument to plt.legend(),

     plt.legend(facecolor="plum")
    
  2. To obtain a circular shaped legend handle, you may use a standard plot with a circular marker as proxy artist,

     plt.plot([],[], marker="o", ms=10, ls="")
    

Complete example:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
colors = ["g", "w"]
texts = ["Green Data Description", "RedData Description"]
patches = [ plt.plot([],[], marker="o", ms=10, ls="", mec=None, color=colors[i], 
            label="{:s}".format(texts[i]) )[0]  for i in range(len(texts)) ]
plt.legend(handles=patches, bbox_to_anchor=(0.5, 0.5), 
           loc='center', ncol=2, facecolor="plum", numpoints=1 )

plt.show()

(Note that mec and numpoints arguments are only required for older versions of matplotlib)

enter image description here

For more complicated shapes in the legend, you may use a custom handler map, see the legend guide or e.g. this answer as an example

Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
3

As the other answers did not work for me, I am adding an answer that is super simple and straight forward:

import matplotlib.pyplot as plt
handles = []
for x in colors:
    handles.append(plt.Line2D([], [], color=x, marker="o", linewidth=0))

You can adjust marker size and whatever else you want (maybe a star etc) and the linewidth removes the line to leave you with only the marker. Works perfectly and is super simple!

Even simpler:

import matplotlib.pyplot as plt
handles = [(plt.Line2D([], [], color=x, marker="o", linewidth=0)) for x in colors]
Seth
  • 1,769
  • 4
  • 26
  • 39