Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib: hide subplot and fill space with other subplots

I've got a figure that contains three subplots which are arranged vertically. Once I click into the figure, I want the second subplot ax2 to be hidden and the other plots to fill the space. A second click into the figure should restore the original plot and layout.

Hiding the subplot ax2 isn't a problem, but how can I rearrange the positions of the other subplots?

I've tried creating a new GridSpec, using the set_position and set_subplotspec methods, but nothing worked out. I'm sure I'm missing something here, any help would be appreciated.

This is my code:

import matplotlib.pyplot as plt
from matplotlib import gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

visible = True

def toggle_ax2(event):
    global visible
    visible = not visible
    ax2.set_visible(visible)
    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()
like image 237
Felix Avatar asked May 12 '17 11:05

Felix


2 Answers

You can define two different GridSpecs. One would have 3 subplots, the other 2. Depending on the visibility of the middle axes, you change the position of the other two axes to obey to the first or second GridSpec.
(There is no need for any dummy figure or so, like other answers might suggest.)

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1], hspace=0.3)
gs2 = gridspec.GridSpec(2,1, height_ratios=[5,3])

ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

ax1.plot([1,2,3], [1,2,3], color="crimson")
ax2.plot([1,2,3], [2,3,1], color="darkorange")
ax3.plot([1,2,3], [3,2,1], color="limegreen")

visible = True

def toggle_ax2(event):
    global visible
    visible = not visible
    ax2.set_visible(visible)
    if visible:
        ax1.set_position(gs[0].get_position(fig))
        ax3.set_position(gs[2].get_position(fig))
    else:
        ax1.set_position(gs2[0].get_position(fig))
        ax3.set_position(gs2[1].get_position(fig))

    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()

Left: original; right: after clicking

enter image description here

like image 85
ImportanceOfBeingErnest Avatar answered Sep 21 '22 11:09

ImportanceOfBeingErnest


You can create a new gridspec instance, and use that to create some dummy figures in a second figure (you can close this before you plt.show, so you never actually see it, we just want to grab some positions from the axes here).

By storing the two possible positions for ax1 and ax3 from that dummy figure and the original figure, then you can use ax.set_position() in your toggle_ax2 function to change the positions of the remaining two axes.

import matplotlib.pyplot as plt
from matplotlib import gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

# Store the original positions of ax1 and ax3
pos1_1 = ax1.get_position()
pos3_1 = ax3.get_position()

# Create a second gridspec for when ax2 is hidden. Keep 5:1 ratio
gs2 = gridspec.GridSpec(2, 1, height_ratios=[5, 1])
fig2 = plt.figure()
ax1_2 = fig2.add_subplot(gs2[0])
ax3_2 = fig2.add_subplot(gs2[1])

# Store the positions of ax1 and ax3 in the new gridspec
pos1_2 = ax1_2.get_position()
pos3_2 = ax3_2.get_position()

# Close the dummy figure2
plt.close(fig2)

visible = True

def toggle_ax2(event):
    global visible

    visible = not visible
    ax2.set_visible(visible)

    # Use the stored positions to switch between 
    # different arrangements of ax1 and ax3
    if visible:
        ax1.set_position(pos1_1)
        ax3.set_position(pos3_1)
    else:
        ax1.set_position(pos1_2)
        ax3.set_position(pos3_2)
    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()

Original configuration: enter image description here

After removing ax2: enter image description here

like image 20
tmdavison Avatar answered Sep 19 '22 11:09

tmdavison