为不同范围的多个 matplotlib 子图设置 'global' 颜色条范围

Set 'global' colorbar range for multiple matplotlib subplots of different ranges

我想在 python 中使用 matplotlib.pyplot 在子图中绘制数据。每个子图将包含不同范围的数据。我想使用 pyplot.scatter 绘制它们,并为整个图使用一个单一的颜色条。因此,颜色条应包含每个子图中值的整个范围。但是,当我使用循环绘制子图并在循环外调用颜色条时,它仅使用最后一个子图的值范围。许多可用的示例都涉及调整颜色条位置的大小,因此这个答案(如何为多个子图制作一个通用颜色条)并不明显。

我有以下独立的示例代码。这里渲染了两个子图,一个应该用俄罗斯典型的寒冷温度着色,另一个用巴西的热带温度着色。然而,最终结果显示的颜色条仅在巴西热带温度范围内变化,使得俄罗斯子图错误:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

core_list = ['Russia', 'Brazil']
core_depth = [0, 2, 4, 6, 8, 10]
lo = [-33, 28]
hi = [10, 38]
df = pd.DataFrame([], columns = ['Location', 'Depth', '%TOC', 'Temperature'])

#Fill df
for ii, name in enumerate(core_list):
    for jj in core_depth:
        df.loc[len(df.index)] = [name, jj, (np.random.randint(1, 20))/10, np.random.randint(lo[ii], hi[ii])]
#Russia data have much colder temperatures than Brazil data due to hi and lo

#Plot data from each location using scatter plots
fig, axs = plt.subplots(nrows = 1, ncols = 2, sharey = True)
for nn, name in enumerate(core_list):
    core_mask = df['Location'] == name
    data = df.loc[core_mask]
    plt.sca(axs[nn])
    plt.scatter(data['Depth'], data['%TOC'], c = data['Temperature'], s = 50, edgecolors = 'k')
    axs[nn].set_xlabel('%TOC')
    plt.text(1.25*min(data['%TOC']), 1.75, name)
    if nn == 0:
        axs[nn].set_ylabel('Depth')

cbar = plt.colorbar()
cbar.ax.set_ylabel('Temperature, degrees C')
#How did Russia get so warm?!? Temperatures and ranges of colorbar are set to last called location. 
#How do I make one colorbar encompass global temperature range of both data sets?

此代码的输出显示巴西和俄罗斯的温度落在相同的颜色范围内:

我们直觉地知道,从数据来看,这是错误的。那么,我们如何告诉 pyplot 正确绘制它呢?

答案很简单,使用 pyplot.scatter 的 vmax 和 vmin 控件。这些必须使用通用范围的数据设置,而不仅仅是在循环的任何单个迭代中关注的数据。因此,要更改上面的代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

core_list = ['Russia', 'Brazil']
core_depth = [0, 2, 4, 6, 8, 10]
lo = [-33, 28]
hi = [10, 38]

df = pd.DataFrame([], columns = ['Location', 'Depth', '%TOC', 'Temperature'])
#Fill df
for ii, name in enumerate(core_list):
    for jj in core_depth:
        df.loc[len(df.index)] = [
                  name,
                  jj, 
                  (np.random.randint(1, 20))/10,
                  np.random.randint(lo[ii], hi[ii])
         ]
#Russia data have much colder temperatures than Brazil data due to hi and lo

#Plot data from each location using scatter plots
fig, axs = plt.subplots(nrows = 1, ncols = 2, sharey = True)
for nn, name in enumerate(core_list):
    core_mask = df['Location'] == name
    data = df.loc[core_mask]
    plt.sca(axs[nn])
    plt.scatter(
        data['Depth'],
        data['%TOC'],
        c=data['Temperature'],
        s=50,
        edgecolors='k',
        vmax=max(df['Temperature']),
        vmin=min(df['Temperature'])
     )
    axs[nn].set_xlabel('%TOC')
    plt.text(1.25*min(data['%TOC']), 1.75, name)
    if nn == 0:
        axs[nn].set_ylabel('Depth')

cbar = plt.colorbar()
cbar.ax.set_ylabel('Temperature, degrees C') 

现在,输出显示了俄罗斯和巴西之间的温差,这是粗略浏览数据后所预料到的。修复此问题的更改发生在 for 循环中,但是它引用所有数据来查找最大值和最小值:

plt.scatter(data['Depth'], data['%TOC'], c = data['Temperature'], s = 50, edgecolors = 'k', vmax = max(df['Temperature']), vmin = min(df['Temperature']) )