Skip to main content
 首页 » 编程设计

python之共享轴并删除 matplotlib 子图中未使用的

2025年05月04日23lidabo

我想在网格中绘制一系列 seaborn 热图。我知道子图的数量(可以是奇数或偶数)。 热图将按“星期几”(y 轴)和“一天中的小时”(x 轴)显示平均“占用率”,例如它们都共享相同的 x/y 域。

这是我当前的代码:

df2 = df[['name','openLots','occupationRatio','DoW','Hour']] 
fig, axs = plt.subplots(figsize=(24,24), nrows=7, ncols=6) 
axs = axs.flatten() 
locations = df2['name'].sort_values().unique() 
 
 
def occupation_heatmap (name, ax): 
    dfn = df2[df2['name'] == name] 
    dfn = dfn.groupby(['DoW', 'Hour']).mean()['occupationRatio'].unstack() 
    dfn = dfn.reindex(['Mon', 'Tue', 'Wed','Thu','Fri','Sat','Sun']) 
    sns.heatmap(data=dfn, cmap="coolwarm", vmin=0, vmax=1.0, ax= ax) 
    ax.set_title(name) 
 
 
i = 0 
for n in locations:  
    occupation_heatmap (n, axs[i]) 
    i = i+1 
 
plt.tight_layout() 

它看起来几乎是我想要的(最后几行): 不管我想要什么:

  • 每行只有一次 y 轴标签 (DoW)(最左边的图)
  • 仅在每行最右边的图上使用颜色图图例(或完全不使用,颜色非常不言自明)
  • 由于总数为奇数,删除最后一行的“空地 block ”

非常感谢任何提示

请您参考如下方法:

  • 每行只有一次 y 轴标签 (DoW)(最左边的图)
    这可以使用 sharey = True 作为 plt.subplots 的参数来完成。
  • 仅在每行最右边的图上使用颜色图图例(或者完全不使用它,颜色非常不言自明)
    将 cbar = False 参数用于 seaborn.heatmap 以便不显示颜色条。这可以作为绘图函数的输入,具体取决于子图的实际数量。
  • 由于总数为奇数而删除最后一行的“空地 block ”
    在创建绘图的循环之后,您可以添加另一个循环来删除未使用的轴。

    for j in range(len(locations), ncols*nrows): 
        axs[j].axis("off") 
    

这是一个完整的例子(我借用了@Robbie 的 cod 来生成数据框):

import matplotlib.pyplot as plt 
import pandas as pd 
import numpy as np 
import seaborn as sns 
 
days = ['Mon','Tue','Wed','Thurs','Fri','Sat','Sun'] 
names = ["Parkhaus {:02}".format(i+1) for i in range(22)] 
 
nItems = 1000 
 
df = pd.DataFrame() 
df['name'] = [names[i] for i in np.random.randint(0,len(names),nItems)] 
df['openLots'] = np.random.randint(0,100,nItems) 
df['occupationRatio'] = np.random.rand(nItems) 
df['DoW'] = [days[i] for i in np.random.randint(0,7,nItems)] 
df['Hour'] = np.random.randint(0,12,nItems) 
 
df2 = df[['name','openLots','occupationRatio','DoW','Hour']] 
nrows = 4; ncols=6 
fig, axs = plt.subplots(nrows=nrows, ncols=ncols, figsize=(15,9), sharey=True) 
axs = axs.flatten() 
locations = df2['name'].sort_values().unique() 
 
 
def occupation_heatmap (name, ax, cbar=False, ylabel=False): 
    dfn = df2[df2['name'] == name] 
    dfn = dfn.groupby(['DoW', 'Hour']).mean()['occupationRatio'].unstack() 
    dfn = dfn.reindex(['Mon', 'Tue', 'Wed','Thu','Fri','Sat','Sun']) 
    sns.heatmap(data=dfn, cmap="coolwarm", vmin=0, vmax=1.0, ax=ax, cbar=cbar) 
    ax.set_title(name) 
    plt.setp(ax.get_yticklabels(), rotation=0) 
    if not ylabel: ax.set_ylabel("") 
 
 
for i, n in enumerate(locations):  
    occupation_heatmap (n, axs[i], cbar=i%ncols==ncols-1, ylabel=i%ncols==0) 
for j in range(len(locations), ncols*nrows): 
    axs[j].axis("off") 
 
plt.tight_layout() 
plt.show()