3

I am trying to put a specific unicode marker entry in the legend list, in matplotlib.

I want a symbol which looks like: |---| (one continuous line, and not so tall pipes maybe), in order to put this annotation in the legend list:

ax.annotate('', xy=(0, 1), xytext=(5, 1), arrowprops={'arrowstyle':'|-|'})

What I have tried is the following:

ax.scatter([], [], c='red', marker="$|---|$", s=120, label='my marker')

This works but it looks kind of bad with the spacing between each character. I found this unicode character which kinda looks similar to what I want. Anyone know something which may look better? I want a combination of long left tack and long right tack, but don't know if that exists.

How do I use unicode as the legend entry? I tried:

ax.scatter([], [], c='red', marker=u"$\U0001D129$", s=120, label='my marker')
user33236
  • 33
  • 3
  • Possible duplicate of [Use text but not marker in matplotlib legend](https://stackoverflow.com/questions/47372459/use-text-but-not-marker-in-matplotlib-legend) – Guangyang Li Mar 13 '18 at 16:32
  • It is not clear to me if you want a unicode symbol in the legend or the annotation? – ImportanceOfBeingErnest Mar 13 '18 at 17:12
  • I want it in the legend. The annotation is already created with the first line of code. The legend entry for the annotation is added using the second line of code. However, the `marker="$|---|$"` does not look very like the annotation created by `arrowprops={'arrowstyle':'|-|'}`. – user33236 Mar 13 '18 at 17:18

2 Answers2

3

It seems the use of unicode symbols is only a workaround for placing the actual annotation arrow in the legend. This can be achieved by using a custom legend handler. To that end one may subclass the legend handler for lines and place an annotation arrow in it. Then calling this would look like

annotate = ax.annotate(..., label="marker")
ax.legend(handles = [annotate], 
          handler_map={type(annotate) : AnnotationHandler(5)})

Here the 5 is the mutation scale, denoting how long the vertical lines in the arrow.

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerLine2D
from matplotlib.patches import FancyArrowPatch

class AnnotationHandler(HandlerLine2D):
    def __init__(self,ms,*args,**kwargs):
        self.ms = ms
        HandlerLine2D.__init__(self,*args,**kwargs)
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize,
                       trans):
        xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
                                             width, height, fontsize)
        ydata = ((height - ydescent) / 2.) * np.ones(xdata.shape, float)
        legline = FancyArrowPatch(posA=(xdata[0],ydata[0]),
                                  posB=(xdata[-1],ydata[-1]),
                                  mutation_scale=self.ms,
                                  **orig_handle.arrowprops)
        legline.set_transform(trans)
        return legline,



fig, ax = plt.subplots()
ax.axis([-1,6,0,3])
ax.plot([1.5,1.5], label="plot")
# create annotations in the axes
annotate = ax.annotate('', xy=(0, 1), xytext=(5, 1), 
                       arrowprops={'arrowstyle':'|-|'}, label="endline")
annotate2 = ax.annotate('', xy=(1, 2), xytext=(3, 2), 
                       arrowprops=dict(arrowstyle='->',color="crimson"), label="arrow")
# create legend for annotations
h, l = ax.get_legend_handles_labels()
ax.legend(handles = h +[annotate,annotate2], 
          handler_map={type(annotate) : AnnotationHandler(5)})

plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
0

I found an all right solution.

ax.scatter([], [], c='red', marker=u'$\u22a2\!\u22a3$', s=150, label='my marker')

This uses a right (\u22a2) and left (\u22a3) tack along with a negative space (\!) to join the two characters into one.

user33236
  • 33
  • 3