Как выровнять два текстовых поля matplotlib рядом в правом верхнем углу?

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

Ниже приведен код для вывода минимального рабочего примера:

import numpy as np
import matplotlib.pyplot as plt

# data
x = np.linspace(-10, 10, 51)
shrink_factors = np.linspace(1, 0, x.size)
y1 = shrink_factors*np.sin(np.exp(-x))
y2 = shrink_factors*np.cos(np.exp(-x))

# get plot parameters
xlim = [np.min(x), np.max(x)]
ylim = [0, 1.125*np.max([np.max(y1), np.max(y2)])]
facecolors = ("red", "blue")
(color1, color2) = facecolors
label1 = "Label 1"
label2 = "Label 2"
text1 = "RED 1"
text2 = "BLUE 2"
text_background_color = "gainsboro"
text_size = 12
figsize = (12, 7)
# figsize = (7, 12)

# initialize plot
fig, ax = plt.subplots(
    figsize=figsize)

# plot data
ax.plot(x, y1, color=color1, label=label1)
ax.plot(x, y2, color=color2, label=label2)
ax.grid(color = "black", linestyle = ":", alpha=0.3)
ax.set_xlim(xlim)
ax.set_ylim(ylim)
fig.legend(mode = "expand", loc = "lower center", ncol=2)

# add text-boxes side-by-side
text_box1 = ax.text(0.95, 0.95, text1, 
                    color=color1, 
                    fontsize=text_size,
                    horizontalalignment = "right", 
                    verticalalignment = "top", 
                    transform=ax.transAxes)
text_box1.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})
text_box1_pos = text_box1.get_position()
text_box2 = ax.text(text_box1_pos[0], 0.95, text2, 
                    color=color2, 
                    fontsize=text_size, 
                    horizontalalignment = "left", 
                    verticalalignment = "top", 
                    transform=ax.transAxes)
text_box2.set_bbox({"facecolor": text_background_color, "edgecolor": "black"})

# finish plot
plt.show()
plt.close()
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы хотите выровнять по правому краю левое поле по левому значению x правого поля. Итак, вам нужно нарисовать прямоугольники вокруг текстовых полей. Они дополняются значением pad, масштабируемым с помощью масштабного коэффициента мутации. Чтобы получить эти значения, вам сначала нужно нарисовать фигуру (вы можете сделать это без рендеринга, чтобы немного ускорить).

Вот минимальный пример, предполагающий, что оба текста используют один и тот же (по умолчанию) отступ:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

bbox_kwds = dict(fc = "gainsboro", ec = "black")
text_box1 = ax.text(0.95, 0.95, "RIGHT", ha = "right", va = "top", transform=ax.transAxes, bbox=bbox_kwds)

fig.draw_without_rendering()
pad = text_box1.get_bbox_patch().get_boxstyle().pad * text_box1.get_bbox_patch().get_mutation_scale()
x = ax.transAxes.inverted().transform(text_box1.get_bbox_patch().get_window_extent().p0 - [pad, 0])[0]

text_box2 = ax.text(x, 0.95, "LEFT", ha = "right", va = "top", transform=ax.transAxes, bbox=bbox_kwds)

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

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

  1. Обновите позицию x первого текстового поля на 0.9, чтобы обе метки находились в пределах графика.
  2. После того, как первое текстовое поле будет построено, добавьте приведенный ниже код. Это похоже на то, что объясняется в сообщении, которое я упомянул. Обратите внимание, что я использую transAxes, чтобы у нас везде были одинаковые координаты. Подробнее здесь. Обратите внимание, что bb_datacoords теперь будет иметь координаты x и y первого текстового поля.
#text_box1_pos = text_box1.get_position()  --> You code, not required anymore

r = fig.canvas.get_renderer()
transf = ax.transAxes.inverted()
bb = text_box1.get_window_extent(renderer = r)
bb_datacoords = bb.transformed(transf)
  1. Используйте позицию x1 из bbox в качестве начальной точки для второго текстового поля, как показано ниже...
    bb_datacoords.x1+0.01, #text_box1_pos[0],

Обратите внимание, что, как упоминалось в приведенном выше ответе SO, точное положение неизвестно до тех пор, пока график не будет готов, поэтому есть небольшая дельта 0,01, которую вы можете добавить, чтобы они не перекрывались. Вы можете увеличить его (скажем, 0,02), если хотите увидеть небольшой зазор между двумя прямоугольниками.

Результирующий сюжет выглядит так... Надеюсь, это поможет.

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