Search code examples
matplotlibzooming

Customizing inset_zoom connector lines


Hey I'm new here and also relatively new to coding and plotting in Python,

I tried to use the inset_zoom feature of matplolib but have some difficulties with the customization of the connector lines. I already managed to change the linestyle and linewidth of my connector lines. Now I'm trying to change the choice of default lines plotted by settting set.visible() to True or False. But instead of not showing the set False connector lines at all, they are plotted in their original linestyle. Furthermore I would rather like it, if the lines didn't connect the same corners of the rectangles but the parallel side corners (see below).

The plots are for my bachelor thesis and I'm kind of runnig out of time so thank you in advance for your help!

Here is a code snippet:

#inset axes
x1,x2,y1,y2 = 0, 0.2, 0, 0.2 # subregion of origanal image
axin1 = ax[1].inset_axes([0.56, 0.04, 0.4, 0.4], xlim=(x1,x2), ylim=(y1,y2), xticks=[], yticks=[], xticklabels=[], yticklabels=[])

axin1.plot(x_H2_real_test, x_H2_pred_test, '.', markersize = 4)
axin1.plot(x_NH3_real_test, x_NH3_pred_test, '.', markersize = 4)
axin1.plot([0, 1], [0, 1], "-", color = 'crimson',lw=1,zorder=1 )
axin1.plot([bounds[0],bounds[1]], [bounds[0] * 1.1, bounds[1] * 1.1], "k--", lw=1)
axin1.plot([bounds[0],bounds[1]], [bounds[0] * 0.9, bounds[1] * 0.9], "k--", lw=1)

box, c1 = ax[1].indicate_inset_zoom(axin1, edgecolor="black", alpha=1,lw=0.7)
c1[0].set_visible(False)
c1[1].set_visible(True)
c1[2].set_visible(True)
c1[3].set_visible(False)
ax[1].indicate_inset_zoom(axin1, edgecolor="black", alpha=1,lw=0.7)
plt.setp([c1[:]], linestyle=":", lw=0.7)

#plt.legend()
#fig.suptitle("Parity Plot")
plt.tight_layout()
plt.show()

The Plot right now:

The read line marks, where I'd like my connector lines to connect:


Solution

  • One option is to create your own connections using some ConnectionPatch instances, since you can then control exactly where they are drawn.

    Since we don't want the original connections any more, we can now use indicate_inset rather than indicate_inset_zoom; to do this we need to define the bounds of the box that gets drawn ourselves, which we can do using the x and y limits of the inset axes.

    Taking your example (without the data plotting parts), this method would look like this:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.patches import ConnectionPatch
    
    fig, ax = plt.subplots(ncols=2)
    
    #inset axes
    x1,x2,y1,y2 = 0, 0.2, 0, 0.2 # subregion of origanal image
    axin1 = ax[1].inset_axes([0.56, 0.04, 0.4, 0.4], xlim=(x1,x2), ylim=(y1,y2), xticks=[], yticks=[], xticklabels=[], yticklabels=[])
    
    rect = (x1, y1, x2 - x1, y2 - y1)
    
    box = ax[1].indicate_inset(rect, edgecolor="black", alpha=1,lw=0.7)
    
    cp1 = ConnectionPatch(xyA=(0.2, 0.0), xyB=(0, 0), axesA=ax[1], axesB=axin1,
                          coordsA="data", coordsB="axes fraction", lw=0.7, ls=":")
    cp2 = ConnectionPatch(xyA=(0.2, 0.2), xyB=(0, 1), axesA=ax[1], axesB=axin1,
                          coordsA="data", coordsB="axes fraction", lw=0.7, ls=":")
    
    ax[1].add_patch(cp1)
    ax[1].add_patch(cp2)
    
    plt.tight_layout()
    plt.show()
    

    which yields:

    enter image description here