Radar Plot Matplotlib Python: как настроить выравнивание меток

Я пытаюсь выровнять метки моего радиолокационного графика с осью, и я сталкиваюсь с трудностями.

Без выравнивания меток мои метки располагаются по центру и выходят за линию оси введите здесь описание изображения.

Когда я устанавливаю для первой половины моих меток (правая сторона рисунка) выравнивание по левому краю, а для второй половины — выравнивание по правому краю, я получаю не «круговое» выравнивание введите здесь описание изображения

Для этого я зациклился на xticklabels и установил горизонтальное выравнивание.

# Draw one axe per variable + add labels labels yet
plt.xticks(angles, categories)
for label,i in zip(ax.get_xticklabels(),range(0,len(angles))):
    if i<len(angles)/2:
        angle_text=angles[i]*(-180/pi)+90
        #label.set_horizontalalignment('left')

    else:
        angle_text=angles[i]*(-180/pi)-90
        #label.set_horizontalalignment('right')
    label.set_rotation(angle_text)

Я предполагаю, что есть правильный способ сделать это, и я не могу понять это, так как я не знаю, следует ли учитывать смещение, перевод или как адаптировать полярную координату для этого.

Спасибо за вашу помощь

Павел

Здесь следует полный код для получения дополнительной информации

from math import pi
import matplotlib.pyplot as plt
%matplotlib inline
import pandas as pd

## Generate Data
labels_test=[]
for i in range(0,40):
    labels_test.append("Fooooooooo"+str(i))
pd_radar=pd.DataFrame(data=np.random.randint(low=0, high=10, size=(2, 40)),columns=labels_test)

# number of variable
categories=list(pd_radar)
N = len(categories)

# What will be the angle of each axis in the plot? (we divide the plot / number of variable)
angles = [n / float(N) * 2 * pi for n in range(N)]

# Initialise the spider plot
fig=plt.figure(figsize=(20,10))
ax = plt.subplot(111, polar=True)

# If you want the first axis to be on top:
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)

# Draw one axe per variable + add labels labels yet
plt.xticks(angles, categories)
for label,i in zip(ax.get_xticklabels(),range(0,len(angles))):
    if i<len(angles)/2:
        angle_text=angles[i]*(-180/pi)+90
        label.set_horizontalalignment('left')

    else:
        angle_text=angles[i]*(-180/pi)-90
        label.set_horizontalalignment('right')
    label.set_rotation(angle_text)
# Draw ylabels
ax.set_rlabel_position(0)


# ------- PART 2: Add plots

# Plot each line of the data 

# Ind1
values0=pd_radar.iloc[0].values.flatten().tolist()
ax.plot(angles, values0, linewidth=1, linestyle='solid', label="Label 1",color='yellow')
ax.fill(angles, values0, 'r', alpha=0.1,color='yellow')

# Ind2
values1=pd_radar.iloc[1].values.flatten().tolist()
ax.plot(angles, values1, linewidth=1, linestyle='solid', label="Label 2",color='deepskyblue')
ax.fill(angles, values1, 'r',color='deepskyblue', alpha=0.1)

# Add legend
plt.show()

person Paulbd    schedule 26.03.2018    source источник
comment
ок, спасибо, надеюсь стало понятнее   -  person Paulbd    schedule 26.03.2018
comment
Да, за исключением того, что я в настоящее время не могу воспроизвести это. Какую версию matplotlib вы используете?   -  person ImportanceOfBeingErnest    schedule 26.03.2018
comment
matplotlib.__version__='2.0.2'   -  person Paulbd    schedule 26.03.2018


Ответы (2)


В настоящее время код не работает с matplotlib 2.2. Однако следующее решение работает с версией 2.0.2, которую использует OP. Обходной путь с использованием более новых версий см. в этом вопросе. .

Тексты в matplotlib имеют режим вращения.

Режим вращения может быть "default", и в этом случае текст сначала поворачивается, а затем выравнивается.

введите здесь описание изображения

или это может быть "anchor", и в этом случае текст сначала выравнивается, а затем поворачивается.

введите здесь описание изображения

Таким образом, чтобы метки меток на полярном графике указывали наружу, необходимо установить выравнивание текста на "left", а затем установить режим вращения на "anchor".

for label,rot in zip(ax.get_xticklabels(),ticks):
    label.set_rotation(rot*180./np.pi)
    label.set_horizontalalignment("left")
    label.set_rotation_mode("anchor")

Полный пример:

import numpy as np
import matplotlib.pyplot as plt

fig=plt.figure(figsize=(5,5))
ax = plt.subplot(111, polar=True)

ticks = np.linspace(0, 2*np.pi, 20, endpoint=False)
text = lambda : "".join(np.random.choice(list("manuladefil"), size=10))
labels = [text() for _ in range(len(ticks))]

plt.xticks(ticks, labels, size=16)
for label,rot in zip(ax.get_xticklabels(),ticks):
    label.set_rotation(rot*180./np.pi)
    label.set_horizontalalignment("left")
    label.set_rotation_mode("anchor")

plt.tight_layout()
plt.show()

введите здесь описание изображения

person ImportanceOfBeingErnest    schedule 26.03.2018

Я нашел решение, которое не кажется элегантным. Основная идея заключалась в том, чтобы установить как вертикальное, так и горизонтальное выравнивание в зависимости от угла.

введите здесь описание изображения

from math import pi
import matplotlib.pyplot as plt
%matplotlib inline
import pandas as pd
import numpy as np

## Generate Data
labels_test=[]
for i in range(0,40):
    labels_test.append("Fooooooooo"+str(i))
pd_radar=pd.DataFrame(data=np.random.randint(low=0, high=10, size=(2, 40)),columns=labels_test)


# number of variable
categories=list(pd_radar)
N = len(categories)

# What will be the angle of each axis in the plot? (we divide the plot / number of variable)
angles = [n / float(N) * 2 * pi for n in range(N)]

# Initialise the spider plot
fig=plt.figure(figsize=(20,10))
ax = plt.subplot(111, polar=True)

# If you want the first axis to be on top:
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)

# Draw one axe per variable + add labels labels yet
# idea is to add both vertical and horizontal alignment as a function of pi

plt.xticks(angles, categories)
for label,i in zip(ax.get_xticklabels(),range(0,len(angles))):

    angle_rad=angles[i]
    if angle_rad <= pi/2:
        ha= 'left'
        va= "bottom"
        angle_text=angle_rad*(-180/pi)+90
    elif pi/2 < angle_rad <= pi:
        ha= 'left'
        va= "top"
        angle_text=angle_rad*(-180/pi)+90
    elif pi < angle_rad <= (3*pi/2):
        ha= 'right'
        va= "top"  
        angle_text=angle_rad*(-180/pi)-90
    else:
        ha= 'right'
        va= "bottom"
        angle_text=angle_rad*(-180/pi)-90
    label.set_rotation(angle_text)
    label.set_verticalalignment(va)
    label.set_horizontalalignment(ha)


# Draw ylabels
ax.set_rlabel_position(0)


# ------- PART 2: Add plots

# Plot each line of the data 

# Ind1
values2=pd_radar.iloc[0].values.flatten().tolist()
ax.plot(angles, values2, linewidth=1, linestyle='solid', label="Label 1",color='yellow')
ax.fill(angles, values2, 'r', alpha=0.1,color='yellow')

# Ind2
values3=pd_radar.iloc[1].values.flatten().tolist()
ax.plot(angles, values3, linewidth=1, linestyle='solid', label="Label 2",color='deepskyblue')
ax.fill(angles, values3, 'r',color='deepskyblue', alpha=0.1)

# Add legend
plt.show()
person Paulbd    schedule 26.03.2018