Nicholas
Nicholas

Reputation: 3737

Matplotlib - Move text label right by 'x' points

I have the following code which produces a bubble chart, and then adds the labels as text to the plot:

fig, ax = plt.subplots(figsize = (5,10))

# create data
x = [1,1,1,1,1,1,1,1,1,1]
y = ['A','B','C','D',
     'E','F','G','H','I','']
z = [10,20,80,210,390,1050,2180,4690,13040,0]

labels = [1,2,8,21,39,105,218,469,1304]

plt.xlim(0.9,1.1)

for i, txt in enumerate(labels):
    ax.annotate(txt, (x[i], y[i]), ha='center', va='center', )

plt.scatter(x, y, s=z*4000, c="#8C4799", alpha=0.3)

enter image description here

I have the text labels centered vertically and horizontally (i.e. the 1304,469 etc), but ideally I want it shifted to the right so it is away from the bubble. I have tried ha=right, but it only nudges it a tiny bit.

Is there anything I can use to move it completely away from the bubble? I.e. code I can put it the following for loop:

for i, txt in enumerate(labels):
    ax.annotate(txt, (x[i], y[i]), ha='center', va='center', )

Upvotes: 5

Views: 9162

Answers (3)

Juan C
Juan C

Reputation: 6132

the parameter xytext of ax.annotate lets you do this:

fig, ax = plt.subplots(figsize = (5,10))

# create data
x = [1,1,1,1,1,1,1,1,1,1]
y = ['A','B','C','D',
     'E','F','G','H','I','']
z = [10,20,80,210,390,1050,2180,4690,13040,0]

labels = [1,2,8,21,39,105,218,469,1304]

plt.xlim(0.9,1.1)

for i, txt in enumerate(labels):
    ax.annotate(txt, (x[i], y[i]), ha='center', va='center', xytext=(1.05,y[i]) )

plt.scatter(x, y, s=z*4000, c="#8C4799", alpha=0.3)

Brings this:

enter image description here

Edit: if you want the labels to be just to the right of every circle, you'll have to create an array of positions and then loop through it

Upvotes: 2

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339350

Since the size s of the bubbles is s=z*4000, a bubble's radius is np.sqrt(z*4000)/2. (For an explanation see scatter plot marker size).

You would hence create an annotation which is positionned at the center of the bubbles in data coordinates and offset it by np.sqrt(z*4000)/2 in units of points (or possibly 2 or 3 points more to have it look nicely).

This would be done using

annotate("text", xy=(x[i],y[i]), 
         xytext=(np.sqrt(z[i]*4000)/2+2, 0),  textcoords="offset points")

Complete example:

import matplotlib.pyplot as plt
import numpy as np


fig, ax = plt.subplots(figsize = (5,10))

# create data
x = [1,1,1,1,1,1,1,1,1,1]
y = ['A','B','C','D',
     'E','F','G','H','I','']
z = [10,20,80,210,390,1050,2180,4690,13040,0]

labels = [1,2,8,21,39,105,218,469,1304]

plt.xlim(0.9,1.1)


sc = plt.scatter(x, y, s=z*4000, c="#8C4799", alpha=0.3)

for txt, size, xi, yi in zip(labels, sc.get_sizes(), x,y):
    ax.annotate(txt, xy=(xi,yi), xytext=(np.sqrt(size)/2+2, 0),
                textcoords="offset points",
                ha='left', va='center', )

plt.show()

enter image description here

Upvotes: 7

Sheldore
Sheldore

Reputation: 39062

I would simply use an offset percentage (20% for example) to reposition the x-coordinate of the text. Additionally you can turn off the manual setting of x-limits.

fig, ax = plt.subplots(figsize=(4, 10))

x = [1,1,1,1,1,1,1,1,1,1]
y = ['A','B','C','D',
     'E','F','G','H','I','']
z = [10,20,80,210,390,1050,2180,4690,13040,0]

labels = [1,2,8,21,39,105,218,469,1304]

for i, txt in enumerate(labels):
    ax.annotate(txt, (x[i]*1.2, y[i]), ha='center', va='center', )

plt.scatter(x, y, s=z*4000, c="#8C4799", alpha=0.3) 

enter image description here

Upvotes: 3

Related Questions