我如何根据 12 个数组(12 个月)制作颜色图?

How I do make a colormap based off 12 arrays (12 months)?

我的目标是创建一个基于月份的彩色地图。 我有两组月度数据(长度相同等)。 但是我想绘制两个数据集的散点图,但颜色图要根据月份进行着色。希望这在我浏览示例时更有意义:

这些是我绘制成散点图的两个数据集:

data1 = np.random.rand(360)

data2 = np.random.rand(360)

然后我使用这个函数(split_months)将data1和data2变成一个二维数组,大小为12, 30。这就像按月重新分组一样,其中12代表所有月份,并且30 是那个特定月份的所有年份:

def split_months(monthly_data):
    month_split = []
    for month in range(12):
        month_split.append(monthly_data[month::12])
    month_split = np.array(month_split)
    return month_split


split_data1 = split_months(data1)

split_data2 = split_months(data2)

print(split_data1.shape, split_data2.shape)

(12, 30) (12, 30)

然后我将拆分后的月份数据重塑为一维数组,基本上是第一个月和所有年份,前面是第二个月和所有年份。因此制作一个一维数组,但按月重新排序,从而按年数重新排序(如下例所示):

split_months_reshape_data1= split_data1.reshape(12*30) ## reshaping so organized by month now (jan - dec for all years)

split_months_reshape_data2 = split_data2.reshape(12*30) 

print(split_data1[0])

print(split_months_reshape_data1[:30])

[0.70049451 0.24326443 0.29633189 0.35540148 0.68205274 0.15130453
 0.34046832 0.54975106 0.4502673  0.39086571 0.5610824  0.88443547
 0.85777702 0.39887896 0.82240821 0.31162978 0.23496537 0.68776803
 0.84677736 0.04060598 0.7735167  0.23317739 0.49447141 0.53932027
 0.62494628 0.19676697 0.41435389 0.22843223 0.22817976 0.09133836]

[0.70049451 0.24326443 0.29633189 0.35540148 0.68205274 0.15130453
 0.34046832 0.54975106 0.4502673  0.39086571 0.5610824  0.88443547
 0.85777702 0.39887896 0.82240821 0.31162978 0.23496537 0.68776803
 0.84677736 0.04060598 0.7735167  0.23317739 0.49447141 0.53932027
 0.62494628 0.19676697 0.41435389 0.22843223 0.22817976 0.09133836]

## data arrays are the same, split_months is showing all of the numbers for the first month, while split_months_reshape_data1 is showing the first 30 values which is the same as the `split_months[0]`

现在的问题是,有没有办法使用 split_months 中的 12 个数组中的每一个来创建颜色图(1 月 - 12 月),但在每个数组中使用这些特定值? 例如,对于一月份,使用 split_months[0] 中的值为颜色图制作一种颜色。然后对于二月,使用 split_months[1] 中的值为颜色图

制作另一种颜色

这是我想要的想法,但颜色条不正确:

plt.scatter(split_months_reshape_data1,split_months_reshape_data2, c = split_data1)
plt.colorbar()
plt.show()
plt.show()

如果我的问题需要澄清,请告诉我,它有点具体,但主要目标是获得基于重塑数据数组(split_data1split_data2)的颜色图。

从颜色图中选择颜色非常简单,如 matplotlib colormap tutorial. There are two types of colormap objects (LinearSegmentedColormap and ListedColormap) and they do not have exactly the same methods to select the colors. Here is how to select colors from the viridis colormap (ListedColormap), using the pyplot interface:

所示
# Select colormap with a certain number of colors
cmap = plt.cm.get_cmap('viridis', 12)

# Generate list of colors in these 3 equivalent ways for a ListeColormap
colors = cmap.colors  # this method is not applicable to LinearSegmentedColormaps
colors = cmap(range(12))
colors = cmap(np.linspace(0, 1, 12))

创建颜色条是比较棘手的部分。您正在绘制的数据集包含 3 个变量:

  1. 月(分类):绘制为色相
  2. data1(数值):绘制为 x 变量
  3. data2(数值):绘制为 y 变量

如您在示例中所见,传递给 c 的变量(即 split_data1,x 变量)映射到使用 plt.colorbar() 创建的颜色栏。虽然可以将与月份对应的值传递给 c 以创建颜色条(请参见下图所示的替代解决方案),但我发现如果预先选择月份的颜色然后传递代码,则代码更容易理解至 color。然后可以与绘图分开创建颜色条,如 the second example of the Customized Colorbars Tutorial.

所示

这是一个示例,其中使用多个 numpy 函数简化了数据整形部分,并使用 zip to loop through the sub-arrays and the related months and colors. The names of the months are generated with the datetime module 创建散点图以节省一些输入。

from datetime import datetime as dt
import numpy as np                   # v 1.19.2
import matplotlib.pyplot as plt      # v 3.3.4

# Create sample dataset
rng = np.random.default_rng(seed=1)  # random number generator
data1 = rng.random(360)
data2 = rng.random(360)

# Reshape data
split_data1 = np.stack(np.split(data1, 30)).transpose()
split_data2 = np.stack(np.split(data2, 30)).transpose()

# Generate lists of months and colors
months = [dt.strptime(str(m), '%m').strftime('%B') for m in range(1, 13)]
cmap = plt.cm.get_cmap('viridis')  # no need to preselect number of colors in this case
colors = cmap(np.linspace(0, 1, len(months)))

# Draw scatter plot by looping over zipped sub-arrays, colors and months
for x, y, c, month in zip(split_data1, split_data2, colors, months):
    plt.scatter(x, y, color=c, label=month)

# Add colorbar
bounds = np.arange(len(months)+1)
norm = plt.matplotlib.colors.BoundaryNorm(bounds, cmap.N)
cbar = plt.colorbar(plt.cm.ScalarMappable(norm=norm, cmap=cmap), ticks=bounds+0.5)
cbar.set_ticklabels(months)

# Optional extra formatting
cbar.ax.tick_params(length=0, pad=7)
cbar.ax.invert_yaxis()

plt.show()



为了完整起见,这里有一个替代解决方案,它使用 plt.scatter 中的 c 参数(而不是 color)直接从图中生成颜色条:

# Prepare data...

# months and cmap are the same as before
months = [dt.strptime(str(m), '%m').strftime('%B') for m in range(1, 13)]
cmap = plt.cm.get_cmap('viridis')

# Create objects needed to map the months to colors and create a colorbar
bounds = np.arange(13)
norm = plt.matplotlib.colors.BoundaryNorm(bounds, cmap.N)

# Draw scatter plot, notice how there is no need for colors
for x, y, month, bound in zip(split_data1, split_data2, months, bounds):
    plt.scatter(x, y, c=np.repeat(bound, len(x)), norm=norm, cmap=cmap, label=month)
cbar = plt.colorbar()

# Format colorbar
cbar.set_ticklabels(months)
cbar.set_ticks(bounds+0.5)
cbar.ax.tick_params(length=0, pad=7)
cbar.ax.invert_yaxis()