Search code examples
pythonmatplotlibsubplotarrows

GridSpec and ConnectionPatch Issues


I'm trying to have one large plot, and then use arrows to connect outliers to smaller plots. I used gridspec to create my plots, and on their own they show up perfectly.

However, when I try to use ConnectionPatch to add an artist for the arrows, it changes the size of all the subplots.

Here is my code setting up the figure and subplots using gridspec:

fig2 = plt.figure(constrained_layout=True)
gs = fig2.add_gridspec(ncols=3, nrows=9, figure=fig2)

f2_ax1 = fig2.add_subplot(gs[0:-4, :-1])

f2_ax2 = fig2.add_subplot(gs[2:-4, 2])


f2_ax3 = fig2.add_subplot(gs[5:-1, 0])


f2_ax4 = fig2.add_subplot(gs[5:-1, 1])


f2_ax5 = fig2.add_subplot(gs[5:-1,2])

This creates the plots I want (see picture):

enter image description here

Here is how I'm adding arrows to the plots, using a for loop to iterate through each subplot:

coordsA = "data" #The arrows are plotting using the same coordinates as the data points
coordsB = "data"
i = 0
for sub_plot in sub_plot_list: #Adding the arrows to the subplots
    xy1 = (x_oulier_list[i], y_outlier_list[i]) #Fetches coordinates for beginning of arrow 
    xy2 = arrow_end_list[i] #Fetches coordinates for the pointy end of arrow 
    con = ConnectionPatch(xyA=(x_outlier_list[i],y_outlier_list[i]), xyB=arrow_end_list[i], 
                          coordsA=coordsA, coordsB=coordsB,
                          axesA=f2_ax1, axesB=sub_plot,
                          arrowstyle="->", shrinkB=5)

    f2_ax1.add_artist(con) #Adds arrow to plot
    i += 1 

Both versions use fig2.tight_layout().

Here is the plot after adding arrows:

enter image description here

Any idea how I can fix it so that the dimensions of the plot don't change when I add arrows?


Solution

  • Looks like the problem is with constrained_layout, which does not seem to handle ConnectionPatch very well (constrained_layout is still experimental, maybe it is worth raising an issue on matplotlib's github in case someone can figure the problem out).

    An easy fix is to request that the ConnectionPatch objects are not taken into account when calculating the layout using:

    (...)
        con = ConnectionPatch(xyA=(x_outlier_list[i],y_outlier_list[i]), xyB=arrow_end_list[i], 
                              coordsA=coordsA, coordsB=coordsB,
                              axesA=f2_ax1, axesB=sub_plot,
                              arrowstyle="->", shrinkB=5)
        con.set_in_layout(False)
    (...)