Текст аннотации Matplotlib расширяется за пределы осей

У меня есть диаграмма рассеяния с несколькими точками, иногда перекрывающимися, поэтому в каждой точке есть аннотация наведения (используется решение здесь для ее создания). Чтобы справиться с несколькими точками и иногда длинными описаниями, в аннотации есть разрыв строки. Проблема заключается в том, что с несколькими строками поле аннотации строится, а не опускается, заставляя его выходить за пределы оси, как показано ниже. Есть ли способ, чтобы текст начинался со строки прямо под осью, а затем встраивался в сюжет?

Соответствующий код:

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

x = np.random.rand(15)
y = np.random.rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)

norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn

fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)

annot = ax.annotate("", xy=(0.05, 0.95), xycoords='axes fraction',
                    bbox=dict(boxstyle = "round", fc = "w"),
                    zorder=1000)
annot.set_visible(False)

def update_annot(ind):

    pos = sc.get_offsets()[ind["ind"][0]]
    annot.xy = pos
    text = "{}".format("\n".join([f"{n}: {names[n]}" for n in ind["ind"]]))
    annot.set_text(text)
    annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont, ind = sc.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()

Как это выглядит с однострочным текстом в аннотации

Текст аннотации Matplotlib расширяется за пределы осей

Как это выглядит с двухстрочным текстом в аннотации (точка наведения перекрывает две точки). В идеале иметь 0: A, где 8: I, а затем 8: I под ним.

Текст аннотации Matplotlib расширяется за пределы осей

Вы пытались изменить pos = sc.get_offsets()[ind["ind"][0]] annot.xy = pos на обратный?

Julian Silvestri 07.02.2019 22:05

Я предполагаю, что обходным путем является использование xy=(0.05, 0.05) в аннотации, чтобы поместить его в нижний левый угол и встроить в график.

TomNash 07.02.2019 22:09

своего рода хакерский способ, да, это может сработать

Julian Silvestri 07.02.2019 22:10
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
1 197
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Это делается через аргумент verticalalignment или va (или horizontalalignment / ha). Установите его на "top", чтобы выровнять текст сверху.

Используйте аргументы xytext и textcoords (так же, как и в связанном коде), чтобы дать тексту некоторое смещение в пунктах (т.е. независимо от размера фигуры).

import matplotlib.pyplot as plt

fig,ax = plt.subplots()

annot = ax.annotate("Three\nLine\nText", xy=(0, 1), xycoords='axes fraction',
                    xytext=(5,-5), textcoords = "offset points",
                    bbox=dict(boxstyle = "round", fc = "w"), va = "top")

plt.show()

Спасибо, не знал об аргументе verticalalignment, но это именно то, что нужно.

TomNash 08.02.2019 15:04

Другие вопросы по теме