7

I am trying to draw a graph where every node is automatically placed 1 unit below its parent. Here is an example:

enter image description here

Each node is some text surrounded by a bounding box, which can have a different size and may contain a lot of values (for example, box 3 is very long). I need to obtain the bottom coordinate of each parent node and draw the child node 1 unit below that. However, my problem is that the reported coordinates of the bounding boxes are not correct. In the above example, I expect box 4 to be 1 unit below box 3, but the bottom coordinate of box 3 is reported as -1.5 instead of -2.3. Box 4 is now drawn too close to its parent. I am using Python 2.7.13. Here is my code:

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()

I have been able to get closer to solving this problem by disabling axis limits before drawing anything in the plot and setting manual limits as:

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

Box 4 is then still not drawn exactly 1 unit below box 3 (but I think that’s padding issues), but it works almost as expected. However, setting the axis limits beforehand is not ideal, because I need to draw the trees automatically and do not know what the plot limits should be at that point.

How can I obtain the correct bottom coordinate of every box and place a new box 1 unit below it?

1
  • Have you tried the solution to this question? (tl;dr : text Bbox isn't final until rendered, and backends render differently; some hacks required). Commented Aug 17, 2017 at 20:04

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.