olga.bio
olga.bio

Reputation: 281

Align labels in a circle

I have difficulties with text alignment in pyplot. I am trying to annotate points arranged in a circular fashion in a circular dendrogram, so it is important that the labels are pointing away from the dots and keeping the right angle. Here is the relevant part of what I have so far. dots in a circle

The horizontal labels work like a charm, but the vertical ones are obviously off. It seems that horizontalalignment / verticalalignment is applied on the original coordinates and on the bounding box. Is there any option / way to correctly align the labels without performing some crazy stunts like figuring out the text hight and moving the labels accordingly. I was wondering if it would make sense to overlay a second plot / axis with polar coordinates and put the text on it, but I am not sure if this will lead me anywhere. Or wether I am missing something really obvious...

Here is a minimal working example:

import matplotlib.pyplot as plt

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

def kex(N):
    alpha = 360. / N
    coordX = []
    coordY = []
    alphas = []
    for i in range(0,N):
        alpha_loop = alpha * i
        coordX.append( math.cos(math.radians(alpha_loop)) )
        coordY.append( math.sin(math.radians(alpha * i)) )
        alphas.append(alpha_loop)
    return [coordX, coordY, alphas]

N = 10
points = kex(N)
ax.scatter(points[0], points[1])
for i in range(0,N):
    x = points[0][i]
    y = points[1][i]
    a = points[2][i]
    if x > 0:
        ax.text(x + x * 0.1, y + y * 0.1, "AAA", rotation = a,
                    bbox=dict(facecolor = "none", edgecolor ="red"))
    else:
        ax.text(x + x * 0.1, y + y * 0.1, "AAA", rotation = a - 180,
                    bbox=dict(facecolor = "none", edgecolor ="red"), ha = "right")

ax.axis("off")

plt.show()

Any help is appreciated!

Upvotes: 2

Views: 1588

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339430

You may offset the text enough not to have it overlap with the points. The idea is then to center-align (ha="center", va="center") the text, such that will be sitting on an extended (virtual) line between the graph's midpoint and the dot it annotates.

import matplotlib.pyplot as plt
import numpy as np

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

def kex(N):
    alpha=2*np.pi/N
    alphas = alpha*np.arange(N)
    coordX = np.cos(alphas)
    coordY = np.sin(alphas)

    return np.c_[coordX, coordY, alphas]

N = 10
r = 1.2
points = kex(N)
ax.scatter(points[:,0], points[:,1])

for i in range(0,N):
    a = points[i,2] 
    x,y = (r*np.cos(a), r*np.sin(a))
    if points[i,0] < 0: a = a - np.pi
    ax.text(x,y, "AAA", rotation = np.rad2deg(a), ha="center", va="center",
                    bbox=dict(facecolor = "none", edgecolor ="red"))

ax.axis("off")

plt.show()

enter image description here

Upvotes: 4

Related Questions