How to separate the last subplot line and the last subplot column in a figure

Question:

Using matplotlib, I plotted n x n subplots (n=8 in this example):

fig, ax = plt.subplots(8,8, figsize=(18,10), sharex='col', sharey='row')
fig.subplots_adjust(hspace=0, wspace=0)

enter image description here

And I would like to separate the last line and the last column to obtain something like this :

enter image description here

Must I use Gridspec (as in the answer https://stackoverflow.com/a/54747473/7462275) with a for loop because n is a parameter or is there a simpler solution ?
Thanks for answer.

Edit1

Following answer https://stackoverflow.com/a/54747473/7462275, I wrote this code.

import matplotlib
n=7
m=5
outer_gs = matplotlib.gridspec.GridSpec(2,2, height_ratios=[n,1], width_ratios=[m,1], hspace=0.1, wspace=0.1)
inner_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,m, subplot_spec=outer_gs[0,0], hspace=0, wspace=0)
line_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,1, subplot_spec=outer_gs[0,1], hspace=0, wspace=0.1)
col_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(1,m, subplot_spec=outer_gs[1,0], hspace=0.1, wspace=0)
ax_11=[]
ax_12=[]
ax_21=[]
ax_22=[]
fig = plt.figure(figsize=(18,10))
for i in range (n):
    ax_11.append([])
    for j in range(m):
        ax_11[i].append(fig.add_subplot(inner_gs[i,j]))
        
for i in range(n):
        ax_12.append(fig.add_subplot(line_gs[i,0]))
        
for i in range(m):
        ax_21.append(fig.add_subplot(col_gs[0,i]))

ax_22 = fig.add_subplot(outer_gs[1,1])

And I obtained
enter image description here

But, now I have to remove inside axis labels and to keep only the outside ones.

Edit2

It works with this code :

import matplotlib
n=7
m=5
outer_gs = matplotlib.gridspec.GridSpec(2,2, height_ratios=[n,1], width_ratios=[m,1], hspace=0.1, wspace=0.1)
inner_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,m, subplot_spec=outer_gs[0,0], hspace=0, wspace=0)
line_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,1, subplot_spec=outer_gs[0,1], hspace=0, wspace=0.1)
col_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(1,m, subplot_spec=outer_gs[1,0], hspace=0.1, wspace=0)
ax_11=[]
ax_12=[]
ax_21=[]
ax_22=[]
fig = plt.figure(figsize=(18,10))
for i in range (n):
    ax_11.append([])
    for j in range(m):
        ax_11[i].append(fig.add_subplot(inner_gs[i,j]))
        if not ax_11[i][j].get_subplotspec().is_first_col():
            ax_11[i][j].axes.yaxis.set_visible(False)
        ax_11[i][j].axes.xaxis.set_visible(False)
        
for i in range(n):
        ax_12.append(fig.add_subplot(line_gs[i,0]))
        ax_12[i].axes.yaxis.set_visible(False)
        ax_12[i].axes.xaxis.set_visible(False)
        
for i in range(m):
        ax_21.append(fig.add_subplot(col_gs[0,i]))
        if not ax_21[i].get_subplotspec().is_first_col():
            ax_21[i].axes.yaxis.set_visible(False)

ax_22 = fig.add_subplot(outer_gs[1,1])
ax_22.axes.yaxis.set_visible(False);

enter image description here

But, I wonder if it is the simplest method to obtain such figure. I am discovering matplotlib and I am not sure that this code is good even if it gives the expected result.

Asked By: Stef1611

||

Answers:

Based on this answer and documentation, you can change the appearance of ticks and tick labels with using tick_params.

I add some if statements and tick_params to your code.

import matplotlib.pyplot as plt
import matplotlib
n=7
m=5
outer_gs = matplotlib.gridspec.GridSpec(2,2, height_ratios=[n,1],
width_ratios=
[m,1], hspace=0.1, wspace=0.1)
inner_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,m, 
subplot_spec=outer_gs[0,0], hspace=0, wspace=0)
line_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(n,1, 
subplot_spec=outer_gs[0,1], hspace=0, wspace=0.1)
col_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(1,m, 
subplot_spec=outer_gs[1,0], hspace=0.1, wspace=0)
ax_11=[]
ax_12=[]
ax_21=[]
ax_22=[]
fig = plt.figure(figsize=(18,10))
for i in range (n):
    ax_11.append([])
    for j in range(m):
        ax_11[i].append(fig.add_subplot(inner_gs[i,j]))
        plt.tick_params(labelbottom=False, length=0)
        if j!=0:
            plt.tick_params(labelleft=False, length=0)

for i in range(n):
        ax_12.append(fig.add_subplot(line_gs[i,0]))
        plt.tick_params(labelleft=False, length=0)
        plt.tick_params(labelbottom=False, length=0)

for i in range(m):
    ax_21.append(fig.add_subplot(col_gs[0,i]))
    if i!=0:
        plt.tick_params(labelleft=False, length=0)

ax_22 = fig.add_subplot(outer_gs[1,1])
plt.tick_params(labelleft=False, length=0)

plt.show()

Here is the result.
enter image description here

Answered By: Saeed Akbari

An alternative method would be to continue to use plt.subplots() to create your axes, but add an extra column and row for the gap, which you can remove after creation.

Note this method means your axes will continue to be shared as before, and there is no need to turn tick labels on or off for specific axes.

Using the height_ratios and width_ratios options for gridspec_kw, we can control how high and wide those gaps will be. In the example below, I set them to be one fifth of the regular axes dimensions, but that is easy to change to suit your needs.

We can remove the dummy axes using the .remove() method on them. And then so they don’t get in the way of our ax array, we can using numpy.delete to remove those slices.

For example:

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(9, 9, figsize=(18, 10), sharex='col', sharey='row',
                       gridspec_kw={
                           'height_ratios': (1, 1, 1, 1, 1, 1, 1, 0.2, 1), 
                           'width_ratios': (1, 1, 1, 1, 1, 1, 1, 0.2, 1),
                           'hspace': 0, 'wspace': 0
                           })

# remove 8th column
for dax in ax[:, 7]:
    dax.remove()
ax = np.delete(ax, 7, 1)

# remove 8th row
for dax in ax[7, :]:
    dax.remove()
ax = np.delete(ax, 7, 0)

plt.show()

enter image description here

Answered By: tmdavison
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.