Skip to content

[Bug]: Zorder issue for lines drawn with ConnectionPatch over inset_axes/plot axes #30308

Open
@ericasaw

Description

@ericasaw

Bug summary

If ConnectionPatch zorder is not set to 0, the line drawn will always be on top of the inset_axes axes or the primary plot axes (in this example the x-axis on the plots) even if the zorder of the plot axes is higher than that of the ConnectionPatch. In this example, the line draws on top of the x-axis text for both the inset_axes and the primary plot even if the zorder of the axis is changed with plt.setp to be higher than that of the ConnectionPatch.

Code for reproduction

fig, ax = plt.subplots(1,1, figsize = (20, 5), facecolor = "k")

#----- main axis -------
#plot set up
ax.set_facecolor('k')
ax.tick_params(axis='both', colors='w', labelsize = 20, size = 5, width = 2)
ax.spines[['left', 'right', 'top', 'bottom']].set_color('w')
ax.spines[['left', 'right', 'top', 'bottom']].set_lw(3)
ax.tick_params(axis = 'both', pad = 5, labelfontfamily = 'sans-serif')


#setting plot limits
ax.set_xlim(15000, 17000)
ax.set_ylim(0, 1.1)

#changing unit of x-tick labels
ax.set_xticklabels(ax.get_xticks()/10000)
#----- end main axis -------

#----- top plot -------
#inset axis drawing
x1, x2, y1, y2 = 16360, 16555, 0.45, 1.06
axins_1 = ax.inset_axes([15850, 1.22, 1150, 0.7], xlim=(x1, x2), ylim=(y1, y2), 
                      transform = ax.transData, facecolor = 'k')

#setting tick params
axins_1.tick_params(axis='both', direction = 'inout', color='w', labelsize = 14, size = 7, width = 2)
axins_1.spines[['top','bottom','left','right']].set_linewidth(2)
axins_1.spines[['left', 'right', 'top', 'bottom']].set_color('w')

#changing unit of x-tick labels
axins_1.set_xticklabels(axins_1.get_xticks()/10000)

#drawing the connection to the area on the plot
box, connectors = ax.indicate_inset_zoom(axins_1, edgecolor="w", lw = 2, alpha = 0.75)

#top box LH
connectors[0].set_visible(False)
verts_box_top_LH = connectors[0].get_path().vertices
#top axis LH
connectors[1].set_visible(False)
verts_ax_bottom_LH = connectors[1].get_path().vertices

#drawing the line from the bottom left corner of axins_1 to the top left hand corner of the inset box
con_1 = ConnectionPatch(xyA = (verts_box_top_LH[0]), xyB = (verts_ax_bottom_LH[2]),
                      coordsA = ax.transData, coordsB = ax.transData,
                      color ="w", lw = 2, alpha = 0.75, zorder = 1)

#adding line to figure
fig.add_artist(con_1)

#top box RH
connectors[3].set_visible(False)
verts_box_top_RH = connectors[3].get_path().vertices
#bottom axis RH
connectors[2].set_visible(False)
verts_ax_bottom_RH = connectors[2].get_path().vertices

#drawing the line from the bottom right corner of axins_1 to the top right hand corner of the inset box
con_2 = ConnectionPatch(xyA = (verts_box_top_RH[2]), xyB = (verts_ax_bottom_RH[0]),
                      coordsA = ax.transData, coordsB = ax.transData,
                      color ="w", lw = 2, alpha = 0.75, zorder = 1)

fig.add_artist(con_2)
#----- end top plot -------

#----- bottom plot -------
#inset axis drawing
x1, x2, y1, y2 = 15675, 15850, 0.57, 1.06
axins_2 = ax.inset_axes([15000, -1.07, 2000, 0.7], xlim=(x1, x2), ylim=(y1, y2), 
                      transform = ax.transData, facecolor = 'k')

#setting tick params
axins_2.tick_params(axis='both', direction = 'inout', color='w', labelsize = 14, size = 7, width = 2)
axins_2.spines[['top','bottom','left','right']].set_linewidth(2)
axins_2.spines[['left', 'right', 'top', 'bottom']].set_color('w')

#changing unit of x-tick labels
axins_2.set_xticklabels(axins.get_xticks()/10000)

#drawing the connection to the area on the plot
box, connectors = ax.indicate_inset_zoom(axins_2, edgecolor="w", lw = 2, alpha = 0.75)

#bottom box LH
connectors[1].set_visible(False)
verts_box_bottom_LH = connectors[1].get_path().vertices
#top axis LH
connectors[0].set_visible(False)
verts_ax_top_LH = connectors[0].get_path().vertices

#drawing the line from the top left of axins_2 to the bottom left hand corner of the inset box
con_3 = ConnectionPatch(xyA = (verts_box_bottom_LH[0]), xyB = (verts_ax_top_LH[2]),
                      coordsA = ax.transData, coordsB = ax.transData,
                      color ="w", lw = 2, alpha = 0.75, zorder = 1)

#adding line to figure
fig.add_artist(con_3)

#bottom box RH
connectors[2].set_visible(False)
verts_box_bottom_RH = connectors[2].get_path().vertices
#top axis RH
connectors[3].set_visible(False)
verts_ax_top_RH = connectors[3].get_path().vertices

#drawing the line from the bottom right of axins to the top horizontal x-axis ax line
con_4 = ConnectionPatch(xyA = (verts_box_bottom_RH[2]), xyB = (verts_ax_top_RH[0]),
                      coordsA = ax.transData, coordsB = ax.transData,
                      color ="w", lw = 2, alpha = 0.75, zorder = 1)

fig.add_artist(con_4)
#----- end of bottom plot -------

#----- surrounding the axes labels with a black box for each axis -----
plt.setp(ax.get_yticklabels(), backgroundcolor="k", color = 'w')
plt.setp(ax.get_xticklabels(), backgroundcolor="k", color = 'w')

plt.setp(axins_1.get_yticklabels(), backgroundcolor="k", color = 'w')
plt.setp(axins_1.get_xticklabels(), backgroundcolor="k", color = 'w')

plt.setp(axins_2.get_yticklabels(), backgroundcolor="k", color = 'w')
plt.setp(axins_2.get_xticklabels(), backgroundcolor="k", color = 'w')
#----- end of surrounding the axes labels with a black box for each axis -----

Actual outcome

Image

Expected outcome

When using ConnectionPatch to change the lines drawn between the box drawn with indicate_zoom_inset and the inset_axes I had hoped that there was a way have the line drawn in front of the box from indicate_zoom_inset (e.g. on top of ax in the example) but behind the axis for the inset axis (e.g. behind the x-axis on axins_1 in the example). Like this:

Image

Additional information

If zorder of the ConnectionPatch(es) is set to 0, the line drawn is totally behind the axes which is expected, but when zorder = 1 the ConnectionPatch(es) always moves to the very top of the figure even if the zorder of the axes for the primary plot or inset axes are higher (e.g. the x-axes in this example).

I also tried putting text over the labels that were intercepted with the line using plt.text and found the same issue, the ConnectionPatch(es) always sit over the text, even when the zorder of the text was higher than the ConnectionPatch. Additionally, I tried moving where plt.setp adds the background color to the axes and/or changes the zorder axes for each of the plots, but found none of the places I put it in the code produced the result I wanted. Usually I would put the plt.setp commands where I am setting up the visuals of the axis, but in this case putting it at the end of the code produced the best results.

The only fix I could find for this was drawing two separate lines for each connection between the inset axes and the box from the indicate_zoom_inset (which is how I generated the plot for the expected outcome) but this adds a lot of code and requires a bit of fiddling to get the lines right. The first line I drew was zorder = 0 and disappears behind the primary plot axes (under the x-axes of the plots), the second line would sit on top of the primary axis and draw from the corner of the box from indicate_zoom_inset to the x-axis line on the primary plot (either on the top or bottom depending on the inset axis I was drawing for--I can provide a code example of this if it is helpful but I didn't think it would be).

I'm not sure if this is intended behavior for ConnectionPatch, I know the lines I am drawing are not typical for indicate_zoom_inset since the connected axes are not matching, but I thought I would raise it because I've been struggling with this for a little bit and didn't see any discussion of this behavior anywhere.

Operating system

Mac OS 15.5 (24F74)

Matplotlib Version

3.9.2

Matplotlib Backend

N/A

Python version

Python 3.9.23

Jupyter version

4.4.3

Installation

conda

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions