首页 > 解决方案 > 我如何根据 12 个数组(12 个月)制作颜色图?

问题描述

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

这些是我作为散点图相互绘制的两个数据集:

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 月),但在每个数组中使用这些特定值?例如,对于一月,使用 from 的值为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) 的颜色图。

标签: pythonnumpymatplotlibjupytercolormap

解决方案


从颜色图中选择颜色非常简单,如matplotlib 颜色图教程中所示。有两种类型的颜色图对象(LinearSegmentedColormap 和 ListedColormap),它们没有完全相同的颜色选择方法。以下是如何使用pyplot 界面从 viridis 颜色图 (ListedColormap) 中选择颜色:

# 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_data1x 变量)映射到使用 创建的颜色栏plt.colorbar()。虽然可以传递与月份对应的值c来创建颜色条(参见下图所示的替代解决方案),但我发现如果预先选择月份的颜色然后将其传递给color. 然后可以从绘图中单独创建颜色条,如自定义颜色条教程的第二个示例所示。

这是一个示例,其中通过使用几个 numpy 函数简化了数据重塑部分,并使用zip创建了散点图以循环遍历子数组以及相关的月份和颜色。月份的名称是使用datetime 模块生成的,以节省一些输入。

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

custom_colorbar



为了完整起见,这是一个替代解决方案,它使用c参数 in plt.scatter(而不是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()

推荐阅读