How to Improve the Label Placement in Scatter Plot

Scatter plot move labels

You can use the xytext parameter to adjust the text position:

plt.annotate(text[i],xy=(x[i],y[i]),xytext=(x[i]+10,y[i]+10), ha='right')

Here I added 10 to your xy position.
For more you can look up the suggestions here:
https://matplotlib.org/users/annotations_intro.html

Label data when doing a scatter plot in python

Here is the best way of doing it I found :

plt.figure()
plt.scatter(a,b)
labels = ['Variable {0}'.format(i+1) for i in range(n)]
for i in range (0,n):
xy=(a[i],b[i])
plt.annotate(labels[i],xy)
plt.plot()

More infos : Matplotlib: How to put individual tags for a scatter plot

How to annotate point on a scatter automatically placed arrow

Basically, no, there isn't.

Layout engines that handle placing map labels similar to this are surprisingly complex and beyond the scope of matplotlib. (Bounding box intersections are actually a rather poor way of deciding where to place labels. What's the point in writing a ton of code for something that will only work in one case out of 1000?)

Other than that, due to the amount of complex text rendering that matplotlib does (e.g. latex), it's impossible to determine the extent of text without fully rendering it first (which is rather slow).

However, in many cases, you'll find that using a transparent box behind your label placed with annotate is a suitable workaround.

E.g.

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
x, y = np.random.random((2,500))

fig, ax = plt.subplots()
ax.plot(x, y, 'bo')

# The key option here is `bbox`. I'm just going a bit crazy with it.
ax.annotate('Something', xy=(x[0], y[0]), xytext=(-20,20),
textcoords='offset points', ha='center', va='bottom',
bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0.5',
color='red'))

plt.show()

Sample Image

Non-overlapping scatter plot labels using matplotlib

You can draw all the annotates first, and then use a mask array to check the overlap and use set_visible() to hide. Here is an example:

import numpy as np
import pylab as pl
import random
import string
import math
random.seed(0)
np.random.seed(0)
n = 100
labels = ["".join(random.sample(string.ascii_letters, random.randint(4, 10))) for _ in range(n)]
x, y = np.random.randn(2, n)

fig, ax = pl.subplots()

ax.scatter(x, y)

ann = []
for i in range(n):
ann.append(ax.annotate(labels[i], xy = (x[i], y[i])))

mask = np.zeros(fig.canvas.get_width_height(), bool)

fig.canvas.draw()

for a in ann:
bbox = a.get_window_extent()
x0 = int(bbox.x0)
x1 = int(math.ceil(bbox.x1))
y0 = int(bbox.y0)
y1 = int(math.ceil(bbox.y1))

s = np.s_[x0:x1+1, y0:y1+1]
if np.any(mask[s]):
a.set_visible(False)
else:
mask[s] = True

the output:

Sample Image



Related Topics



Leave a reply



Submit