Python matplotlib получает размеры ограничивающей рамки

Я пытаюсь нарисовать график, в котором каждый узел автоматически помещается на 1 единицу ниже своего родителя. Вот пример:

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

Каждый узел представляет собой некоторый текст, окруженный ограничивающей рамкой, которая может иметь разный размер и содержать множество значений (например, рамка 3 очень длинная). Мне нужно получить нижнюю координату каждого родительского узла и нарисовать дочерний узел на 1 единицу ниже этого. Однако моя проблема в том, что сообщаемые координаты ограничивающих рамок неверны. В приведенном выше примере я ожидаю, что поле 4 будет на 1 единицу ниже поля 3, но нижняя координата поля 3 сообщается как -1,5 вместо -2,3. Блок 4 теперь нарисован слишком близко к своему родителю. Я использую Python 2.7.13. Вот мой код:

import matplotlib.pyplot as plt

#instantiate plot
plt.axes()
ax = plt.gca()
ax.cla()

#simple setup: draw some nodes at predefined positions
t1 = ax.text(0, 0, '1', ha='center', va='top', color='black', bbox=dict(facecolor='#ccfff5', edgecolor='black',boxstyle='round,pad=0.5'),fontsize=8)
t2 = ax.text(-1, -1, '2', ha='center', va='top', color='black', bbox=dict(facecolor='#ccfff5', edgecolor='black',boxstyle='round,pad=0.5'),fontsize=8)
t3 = ax.text(1, -1, '3\n\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM', ha='center', va='top', color='black', bbox=dict(facecolor='#ccfff5', edgecolor='black',boxstyle='round,pad=0.5'),fontsize=8)

#draw edges between the nodes
plt.plot([0, 0],[0,0], zorder=1, color='#404040', linewidth=1)
plt.plot([0, -1],[0,-1], zorder=1, color='#404040', linewidth=1)
plt.plot([0, 1],[0,-1], zorder=1, color='#404040', linewidth=1)

#Obtain the dimensions of box 3 so that we can place box 4 properly underneath box 3
canvas = ax.figure.canvas
r = canvas.get_renderer()
transf = ax.transData.inverted()
bb = t3.get_window_extent(renderer = r)
bb_datacoords = bb.transformed(transf)

#The y0 coordinate of box 3 is not the expected bottom
print "box coordinates: ", bb_datacoords #Bbox(x0=0.978654233871, y0=-1.5130952381, x1=1.02134576613, y1=-1.0)
print "bottom of box 3: ", bb_datacoords.y0 #-1.5130952381

#define the top y coordinate of box 4
newY = (bb_datacoords.y0 - 1)
print "top position of box 4: ", newY #-2.5130952381
#the bottom coordinate of box 3
newPreviousY = bb_datacoords.y0
print "bottom position of box 3: ", newPreviousY #-1.5130952381

#Add box 4 1 unit below box 3
t4 = ax.text(1, newY, '4', ha='center', va='top', color='black', bbox=dict(facecolor='#ccfff5', edgecolor='black',boxstyle='round,pad=0.5'),fontsize=8)
plt.plot([1, 1],[newPreviousY,newY], zorder=1, color='#404040', linewidth=1)

plt.show()

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

plt.xlim(-1, 1)
plt.ylim(-6, 1)
plt.autoscale(False)

Блок 4 все еще не отрисован точно на 1 единицу ниже блока 3 (но я думаю, что это проблемы с заполнением), но он работает почти так, как ожидалось. Однако заранее задавать пределы оси не идеально, потому что мне нужно рисовать деревья автоматически, и я не знаю, какими должны быть пределы графика в этой точке.

Как я могу получить правильную нижнюю координату каждого ящика и разместить новый ящик на 1 единицу ниже него?


person pm47582    schedule 17.02.2017    source источник
comment
Пробовали ли вы решение этого вопроса? ? (tl; dr : text Bbox не является окончательным, пока не будет отрендерен, а бэкенды отрисовываются по-разному; требуются некоторые хаки).   -  person cphlewis    schedule 17.08.2017