I am trying to draw a graph where every node is automatically placed 1 unit below its parent. Here is an example:
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?