简体   繁体   中英

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

Using matplotlib, I plotted nxn 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)

在此处输入图像描述

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

在此处输入图像描述

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在此处输入图像描述

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);

在此处输入图像描述

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.

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. 在此处输入图像描述

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()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM