Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotate several points with one text in matplotlib

I want to use single annotation text to annotate several data points with several arrows. I made a simple workaround:

ax = plt.gca()
ax.plot([1,2,3,4],[1,4,2,6])
an1 = ax.annotate('Test',
  xy=(2,4), xycoords='data',
  xytext=(30,-80), textcoords='offset points',
  arrowprops=dict(arrowstyle="-|>",
                  connectionstyle="arc3,rad=0.2",
                  fc="w"))
an2 = ax.annotate('Test',
  xy=(3,2), xycoords='data',
  xytext=(0,0), textcoords=an1,
  arrowprops=dict(arrowstyle="-|>",
                  connectionstyle="arc3,rad=0.2",
                  fc="w"))
plt.show()

Producing following result: enter image description here

But I don't really like this solution because it is... well, an ugly dirty hack.

Besides that, it affects the appearance of annotation (mainly if using semi-transparent bboxes etc).

So, if anyone got an actual solution or at least an idea how to implement it, please share.

like image 419
MnZrK Avatar asked Jan 26 '13 22:01

MnZrK


People also ask

Can you label points in Matplotlib?

annotate() to label a single point. Call matplotlib. pyplot. annotate(s, xy) to add a label string s to a point, where xy is a tuple of the point coordinates.

How do I annotate text in Matplotlib?

The annotate() function in pyplot module of matplotlib library is used to annotate the point xy with text s. Parameters: This method accept the following parameters that are described below: s: This parameter is the text of the annotation. xy: This parameter is the point (x, y) to annotate.

How do you label all points in a scatter plot in Python?

Labelling All Points Some situations demand labelling all the datapoints in the scatter plot especially when there are few data points. This can be done by using a simple for loop to loop through the data set and add the x-coordinate, y-coordinate and string from each row.


1 Answers

I guess the proper solution will require too much effort - subclassing _AnnotateBase and adding support for multiple arrows all by yourself. But I managed to eliminate that issue with second annotate affecting visual appearance simply by adding alpha=0.0. So the updated solution here if no one will provide anything better:

def my_annotate(ax, s, xy_arr=[], *args, **kwargs):
  ans = []
  an = ax.annotate(s, xy_arr[0], *args, **kwargs)
  ans.append(an)
  d = {}
  try:
    d['xycoords'] = kwargs['xycoords']
  except KeyError:
    pass
  try:
    d['arrowprops'] = kwargs['arrowprops']
  except KeyError:
    pass
  for xy in xy_arr[1:]:
    an = ax.annotate(s, xy, alpha=0.0, xytext=(0,0), textcoords=an, **d)
    ans.append(an)
  return ans

ax = plt.gca()
ax.plot([1,2,3,4],[1,4,2,6])
my_annotate(ax,
            'Test',
            xy_arr=[(2,4), (3,2), (4,6)], xycoords='data',
            xytext=(30, -80), textcoords='offset points',
            bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
            arrowprops=dict(arrowstyle="-|>",
                            connectionstyle="arc3,rad=0.2",
                            fc="w"))
plt.show()

Resulting picture: enter image description here

like image 184
MnZrK Avatar answered Sep 28 '22 04:09

MnZrK