【问题标题】:How I do make a colormap based off 12 arrays (12 months)?我如何根据 12 个数组(12 个月)制作颜色图?
【发布时间】:2021-07-13 18:10:18
【问题描述】:

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

这是我以散点图的形式相互绘制的两个数据集:

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)的颜色图。

【问题讨论】:

  • 如果我理解正确,您想使用从连续颜色图中获取的 12 种独特颜色(例如 Viridis 而不是 Set3),而不是使用包含 12 个小矩形的标准图例来显示它们,你想将它们显示为一个有 12 个部分的颜色条(我假设带有月份的标签而不是数字)?
  • 是的,完全正确!我尝试创建一个离散的颜色图,但它们只采用硬边界(如特定值)而不是数字数组

标签: python numpy matplotlib jupyter colormap


【解决方案1】:

从颜色图中选择颜色非常简单,如matplotlib colormap tutorial 所示。 colormap objects 有两种类型(LinearSegmentedColormap 和 ListedColormap),它们没有完全相同的颜色选择方法。以下是如何使用 pyplot interface 从 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_data1,x 变量)映射到使用plt.colorbar() 创建的颜色条。虽然可以将对应于月份的值传递给c 以创建颜色条(参见下图所示的替代解决方案),但我发现如果预先选择月份的颜色然后传递给@,代码更容易理解987654334@。然后可以将颜色条与绘图分开创建,如the second example of the Customized Colorbars Tutorial 所示。

这是一个示例,其中使用多个 numpy 函数简化了数据重塑部分,并使用 zip 创建了散点图以循环遍历子数组和相关的月份和颜色。月份的名称是使用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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 2021-08-14
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多