Вот код:

import itertools
import pandas as pd
import matplotlib.pyplot as plt

# reuse these colors
colors = itertools.cycle(["r", "b", "g"])

# some random data
df = pd.DataFrame({'x':[1,2,3,4,5],
                   'y':[2,4,5,2,4],
                   'area': [100, 200, 400, 500, 800],
                   'label': ['blah1','blah2','blah3','blah4','blah5']
                  })

# draw a scatter plot
def draw_scatter_plot(
    x,
    y,
    marker_size,
    marker_color: itertools.cycle,
    labels
):


    fig, ax = plt.subplots(figsize=(12, 8))

    if marker_size:
        i = 0
        while i<len(x):
            ax.scatter(x[i], y[i], color = next(marker_color), s = marker_size[i])
            ax.annotate(
                    labels[i],
                    (x[i], y[i]), # adjust y[i] here
                    fontproperties=cur_font,
                    fontsize=14,
                    ha="center",
                    va="top",
                )
            i+=1


    plt.show()

draw_scatter_plot(df.x.tolist(),
                  df.y.tolist(),
                  df.area.tolist(),
                  colors,
                  df.label.tolist())

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

Как видите, метки перекрываются с нижней частью круга. Как я могу рассчитать нижнее значение y круга, чтобы я всегда мог расположить метки так, чтобы они не перекрывались с кругами?

0
Cheng 2 Июл 2019 в 09:48

3 ответа

Лучший ответ

Идея состоит в том, чтобы сместить текст на половину диаметра точек разброса, np.sqrt(marker_size[i])/2.. Затем вы можете добавить еще 2 пункта, чтобы текст не касался маркеров.

ax.annotate(labels[i],
            xy=(x[i], y[i]), 
            xytext=(0, -np.sqrt(marker_size[i])/2. - 2),
            textcoords="offset points",                    
            ha="center",
            va="top")

enter image description here

0
ImportanceOfBeingErnest 2 Июл 2019 в 13:40

Одним из решений является использование textcoords, как показано в этом ответе. Вы можете отключить галочки в оригинальном ответе.

ax.annotate(labels[i],(x[i], y[i]), xytext=(0, -15),
            textcoords='offset points', fontsize=14,ha="center",va="top",)

enter image description here

0
Sheldore 2 Июл 2019 в 07:25

Вы можете изменить свою аннотацию следующим образом:

[plt.annotate("{}, {}".format(x,y), xy=(x,y), xytext=(x-.1,y-.16)) for x, y in zip(x, y)]

Используя это, вы должны масштабировать координаты yxtext в зависимости от масштаба вашей оси x, y.

Еще один комментарий: поскольку вы используете его в цикле while, вы можете изменить это на:

plt.annotate("{}, {}".format(x[i],y[i]), xy=(x[i],y[i]), xytext=(x[i]-.1,y[i]-.16))
0
philoez98 2 Июл 2019 в 07:35