What I want is like this:

What I get is this:
I also found this link very useful (code below), it's an easier way to handle this issue. It's basically using a list of legend handles to make one of the markers of the first handle invisible and overplot it with the marker of the second handle. This way, you have both markers next to each other with one label.
fig, ax = plt.subplots() p1 = ax.scatter([0.1],[0.5],c='r',marker='s') p2 = ax.scatter([0.3],[0.2],c='b',marker='o') l = ax.legend([(p1,p2)],['points'],scatterpoints=2)With the above code, a
TupleHandleris used to create legend handles which simply overplot two handles (there are red squares behind the blue circles if you look carefylly. What you want to do is make the second marker of first handle and the first marker of the second handle invisible. Unfortunately, theTupleHandleris a rather recent addition and you need a special function to get all the handles. Otherwise, you can use theLegend.legendHandlesattribute (it only show the first handle for theTupleHandler).def get_handle_lists(l): """returns a list of lists of handles. """ tree = l._legend_box.get_children()[1] for column in tree.get_children(): for row in column.get_children(): yield row.get_children()[0].get_children()handles_list = list(get_handle_lists(l)) handles = handles_list[0] # handles is a list of two PathCollection. # The first one is for red squares, and the second # is for blue circles. handles[0].set_facecolors(["r", "none"]) # for the fist # PathCollection, make the # second marker invisible by # setting their facecolor and # edgecolor to "none." handles[0].set_edgecolors(["k", "none"]) handles[1].set_facecolors(["none", "b"]) handles[1].set_edgecolors(["none", "k"]) fig