跳至主要内容

Matplotlib 颜色映射(Colormap):自定义您的配色方案

使用 Matplotlib 颜色映射增强可视化效果。学习如何选择合适的颜色映射、调整颜色分级,并排查常见可视化问题。
· 6分钟 阅读

使用 AI 探索

数据可视化是数据分析师和数据科学家展示复杂信息并产出有意义洞见的最佳方式之一(如果不是最好的话)。为了帮助您更好地与相关方沟通,我整理了有关 Matplotlib 颜色映射的实用信息。

正如您将在本文中看到的,Matplotlib 是 Python 中一个极其灵活且可扩展的可视化库。从简单图表到完全交互式图形,它提供了各种选项。如果您对 Python 还不太熟悉,建议先参加我们的 Introduction to Python 课程,以了解基础知识。就我个人而言,我也会随手放一份 Python Cheat Sheet,因为它是常用函数的便捷参考。

选择合适的 Matplotlib 颜色映射

首先需要考虑的是在顺序型、发散型或类别型颜色映射之间进行选择。选择颜色映射时的其他重要因素包括感知均匀性(即数据值的等距差异应被感知为颜色的等距变化),以及采用对色觉障碍友好的配色选项,使您的可视化对所有受众都更易访问。

选择颜色映射时,您还应考虑不同领域的规范。例如,在海洋学研究中,不同深浅的蓝色表示不同的水深。如果不确定哪种颜色映射适合您的可视化,有多种工具和资源可供参考。尤其是我们的 Introduction to Data Visualization with Matplotlib 课程,可帮助您应对多种情境。

Matplotlib 中的不同颜色映射

在 Python 中,matplotlib.colormaps 模块提供对内置颜色映射的访问,帮助您为项目选择最合适的方案。以下是最常见的几类选项:

顺序型颜色映射

顺序型颜色映射用于表示从低到高有序变化的数据。它们通常从浅到深渐变,以展示不同层级的数据幅度。一个示例是用于温度数据的热图,其中较浅的颜色代表较低温度,较深的颜色代表较高温度。

假设您有一个包含日期和温度列的数据集。以下代码将为温度创建热图。

# Import required libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

# Step 1: Extract month and day information from the date column
calendar_data = temperature_data.copy()   # Create a copy to work with
calendar_data['Month'] = calendar_data['Date'].dt.strftime('%B')
calendar_data['Day'] = calendar_data['Date'].dt.day

# Step 2: Define the order of months for a natural calendar sequence
month_names = ['January', 'February', 'March', 'April', 'May', 'June', 
               'July', 'August', 'September', 'October', 'November', 'December']

# Convert the 'Month' column to a categorical type with the specified order
calendar_data['Month'] = pd.Categorical(calendar_data['Month'], categories=month_names, ordered=True)

# Step 3: Pivot the data to create a structured table for the heatmap
monthly_temperature_table = calendar_data.pivot(index='Month', columns='Day', values='Temperature')

# Step 4: Set up the plot for the heatmap
plt.figure(figsize=(12, 8))

# Define a custom normalization for temperature range (optional)
norm = mcolors.Normalize(vmin=15, vmax=35)

# Create the heatmap with a sequential colormap
heatmap = plt.imshow(monthly_temperature_table, cmap='YlOrRd', aspect='auto', norm=norm)

# Add color bar to represent temperature
colorbar = plt.colorbar(heatmap, orientation='horizontal')
colorbar.set_label('Temperature (°C)', labelpad=10)

# Label the axes
plt.xlabel('Day of the Month')
plt.ylabel('Month')

# Set y-ticks to display month names instead of numbers
plt.yticks(ticks=np.arange(len(month_names)), labels=month_names)

# Add a title to the heatmap
plt.title('Monthly Temperature Heatmap (Sequential Colormap)')

# Display the plot
plt.grid(False)
plt.show()

Matplotlib 顺序型颜色映射可视化示例。

Matplotlib 顺序型颜色映射可视化示例。图片由作者提供

发散型颜色映射

发散型颜色映射用于突出显示相对于中心值两侧的偏差。它们对正负方向采用对比鲜明的颜色。常见应用场景是金融数据中表示盈亏。

# Set 'Month' as the index
profit_loss_df.set_index('Month', inplace=True)

# Set the figure size
plt.figure(figsize=(8, 4))

# Create a diverging colormap
cmap = plt.cm.RdYlGn

# Display the data as a heatmap using imshow
im = plt.imshow(profit_loss_df.T, cmap=cmap, aspect='auto', vmin=-np.max(np.abs(profit_loss_data)), vmax=np.max(np.abs(profit_loss_data)))

# Add color bar with label
cbar = plt.colorbar(im)
cbar.set_label('Profit/Loss ($)')

# Add annotations to each cell
for i, month in enumerate(profit_loss_df.index):
    plt.text(i, 0, f'{profit_loss_df.loc[month, "Profit/Loss"]:.2f}', ha='center', va='center', color='black')

# Set x-axis and y-axis labels and ticks
plt.xlabel('Month')
plt.ylabel('')  # No label needed for y-axis
plt.xticks(ticks=range(len(profit_loss_df.index)), labels=profit_loss_df.index, rotation=45)
plt.yticks([])  # Hide y-axis ticks as we only have one row

# Add title
plt.title('Profit/Loss Heatmap (Diverging Colormap)')

# Adjust layout for better display
plt.tight_layout()

# Show plot
plt.show()

Matplotlib 发散型颜色映射可视化示例。

Matplotlib 发散型颜色映射可视化示例。图片由作者提供。

循环型颜色映射

循环型颜色映射适用于表示具有重复或周期性模式的数据,例如角度、波形相位或一天中的时间。一个示例是可视化周期函数(如正弦波)的相位。

# Create data for a sine wave
x = np.linspace(0, 2 * np.pi, 100)  # X values from 0 to 2π (one complete cycle)
y = np.sin(x)  # Y values (sine of X)

# Create a figure and axis
plt.figure(figsize=(10, 6))

# Create a scatter plot with a cyclic colormap
# Color points by their position in the sine wave cycle
points = plt.scatter(x, y, c=x, cmap='twilight', edgecolor='black')

# Add a color bar to show the phase of the wave
cbar = plt.colorbar(points)
cbar.set_label('Wave Phase (Radians)', rotation=270, labelpad=15)

# Label the axes
plt.xlabel('Angle (Radians)')
plt.ylabel('Sine Value')

# Add a title
plt.title('Sine Wave with Cyclic Colormap (Twilight)')

# Display the plot
plt.grid(True)
plt.show()

Matplotlib 循环型颜色映射可视化示例。

Matplotlib 循环型颜色映射可视化示例。图片由作者提供。

定性(类别)颜色映射

定性颜色映射非常适合表示无特定顺序的分类数据。常见用例是饼图,其中每个扇区代表不同类别,且易于区分。

# Sample categorical data
categories = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
values = [20, 35, 25, 10, 10]

# Set the figure size
plt.figure(figsize=(8, 8))

# Define a qualitative colormap manually
colors = ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3']  # Manually selected color hex codes

# Create a pie chart
plt.pie(values, labels=categories, autopct='%1.1f%%', startangle=90, colors=colors)

# Equal aspect ratio ensures the pie is drawn as a circle
plt.axis('equal')

# Add a title
plt.title('Pie Chart with Qualitative Colormap')

# Display the chart
plt.show()

Matplotlib 定性颜色映射可视化示例

Matplotlib 定性颜色映射可视化示例。图片由作者提供。

彩虹颜色映射

当需要覆盖较宽的色相范围时,可以使用如 hsv 的彩虹颜色映射。

# Generate cyclic data
x = np.linspace(0, 2 * np.pi, 500)
y = np.sin(x)

# Create a plot with rainbow colormap
plt.scatter(x, y, c=x, cmap='hsv', s=50)

# Add a color bar
plt.colorbar(label='Phase')

# Add labels and title
plt.xlabel('Angle (radians)')
plt.ylabel('Sine Value')
plt.title('Cyclic Data Visualization using HSV Colormap')

# Display the plot
plt.show()

Matplotlib 彩虹颜色映射可视化示例。

Matplotlib 彩虹颜色映射可视化示例。图片由作者提供。

感知均匀型颜色映射

如 inferno 和 plasma 等颜色映射在不同显示介质上具有更好的可读性与可见性。

# Generate synthetic elevation data
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2)) * 100  # Elevation data

# Plot the elevation data using the 'plasma' colormap
plt.contourf(X, Y, Z, cmap='plasma')

# Add a color bar
plt.colorbar(label='Elevation (m)')

# Add title and labels
plt.title('Topographic Map (Plasma Colormap)')
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')

# Display the plot
plt.show()

Matplotlib 感知均匀型颜色映射可视化示例。

Matplotlib 感知均匀型颜色映射可视化示例。图片由作者提供。

创建与修改 Matplotlib 颜色映射

尽管 Matplotlib 内置了多种颜色映射,但在某些情况下您可能需要自定义颜色。用于创建自定义颜色映射的关键工具是 ListedColormap 和 LinearSegmentedColormap。

使用 ListedColormap 创建自定义颜色映射

ListedColomap 允许您从特定颜色列表创建颜色映射。当您需要为分类数据中的不同类别分配特定颜色时,此方法非常有用。

from matplotlib.colors import ListedColormap

# Categorical data
categories = ['Category A', 'Category B', 'Category C', 'Category D']
values = [25, 40, 35, 30]

# Custom color list for the colormap (e.g., shades of blue, green, red, and purple)
custom_colors = ['#1f77b4', '#2ca02c', '#d62728', '#9467bd']

# Create a ListedColormap using the custom colors
custom_cmap = ListedColormap(custom_colors)

# Set the figure size
plt.figure(figsize=(8, 6))

# Create a bar plot with the custom colormap
bars = plt.bar(categories, values, color=custom_cmap.colors)

# Add a title
plt.title('Bar Chart with Custom ListedColormap')

# Label the axes
plt.xlabel('Categories')
plt.ylabel('Values')

# Display the plot
plt.show()

Matplotlib 使用 ListedColormap 的自定义颜色映射。

Matplotlib 使用 ListedColormap 的自定义颜色映射。图片由作者提供。

使用 LinearSegmentedColormap 创建自定义颜色映射

LinearSegmentedColormap 可创建在颜色之间平滑过渡的颜色映射。这一点值得了解,因为连续型数据通常需要渐变的颜色变化。这里我也指定了希望在图形中显示的分级数量。

from matplotlib.colors import LinearSegmentedColormap

# Create a grid of values for a 2D Gaussian function
x = np.linspace(-2, 2, 500)
y = np.linspace(-2, 2, 500)
X, Y = np.meshgrid(x, y)
Z = np.exp(- (X**2 + Y**2))

# Define a custom colormap that transitions from blue to white to red
colors = ['blue', 'white', 'red']
custom_cmap = LinearSegmentedColormap.from_list('blue_white_red', colors)

# Adjust the number of color classes (discrete levels)
# Specify the number of levels (e.g., 10 for 10 distinct color bands)
num_classes = 10
levels = np.linspace(Z.min(), Z.max(), num_classes)

# Set the figure size
plt.figure(figsize=(8, 6))

# Plot the 2D Gaussian function with the adjusted colormap
contour = plt.contourf(X, Y, Z, levels=levels, cmap=custom_cmap)

# Add a color bar to show the discrete color classes
plt.colorbar(contour, label='Gaussian Function Value')

# Add labels for the axes
plt.xlabel('X')
plt.ylabel('Y')

# Add a title
plt.title(f'2D Gaussian with {num_classes} Discrete Color Classes')

# Display the plot
plt.show()

Matplotlib 自定义并调整颜色分级数量。

Matplotlib 自定义并调整颜色分级数量。图片由作者提供。

自定义颜色范围与强度

您可以通过调整归一化方式或对现有颜色映射进行切片来控制其颜色强度或取值范围,仅使用一部分可用颜色。以下示例将颜色范围切片为显示 16 至 40 摄氏度的温度。

# Set up the plot for the heatmap
plt.figure(figsize=(12, 8))

# Define a custom normalization for temperature range
norm = mcolors.Normalize(vmin=16, vmax=40)

# Create the heatmap with a sequential colormap
heatmap = plt.imshow(monthly_temperature_table, cmap='YlOrRd', aspect='auto', norm=norm)

# Add color bar to represent temperature
colorbar = plt.colorbar(heatmap, orientation='horizontal')
colorbar.set_label('Temperature (°C)', labelpad=10)

# Label the axes
plt.xlabel('Day of the Month')
plt.ylabel('Month')

# Set y-ticks to display month names instead of numbers
plt.yticks(ticks=np.arange(len(month_names)), labels=month_names)

# Add a title to the heatmap
plt.title('Monthly Temperature Heatmap (Sequential Colormap)')

# Display the plot
plt.grid(False)
plt.show()

Matplotlib 自定义颜色范围与强度。

Matplotlib 自定义颜色范围与强度。图片由作者提供。

组合现有颜色映射

您还可以通过混合多个颜色映射来组合现有方案,从而创建更复杂的可视化效果。

from matplotlib.colors import LinearSegmentedColormap, Normalize

# Create synthetic elevation data
x = np.linspace(-180, 180, 500)  # Longitude
y = np.linspace(-90, 90, 250)    # Latitude
X, Y = np.meshgrid(x, y)
Z = 5000 * np.sin(np.sqrt(X**2 + Y**2) * np.pi / 180)  # Synthetic elevation data

# Define the base colormaps ('viridis' and 'cividis')
cmap1 = plt.get_cmap('viridis')
cmap2 = plt.get_cmap('cividis')

# Create a custom colormap by blending the two base colormaps
def blend_colormaps(cmap1, cmap2, blend_ratio=0.5):
    """Blend two colormaps together."""
    c1 = cmap1(np.linspace(0, 1, 256))
    c2 = cmap2(np.linspace(0, 1, 256))
    blended_colors = (1 - blend_ratio) * c1 + blend_ratio * c2
    return LinearSegmentedColormap.from_list('blended_cmap', blended_colors)

# Create the blended colormap
custom_cmap = blend_colormaps(cmap1, cmap2, blend_ratio=0.5)

# Normalize the data for visualization
norm = Normalize(vmin=-5000, vmax=5000)

# Set the figure size
plt.figure(figsize=(12, 6))

# Plot the synthetic elevation data with the blended colormap
contour = plt.contourf(X, Y, Z, levels=100, cmap=custom_cmap, norm=norm)

# Add a color bar to show the blended color mapping
plt.colorbar(contour, label='Elevation (meters)')

# Add labels for the axes
plt.xlabel('Longitude')
plt.ylabel('Latitude')

# Add a title
plt.title('Geographical Elevation Data with Blended Colormap (Viridis + Cividis)')

# Display the plot
plt.show()

Matplotlib 组合现有颜色映射。

Matplotlib 组合现有颜色映射。图片由作者提供。

使用 _r 后缀反转颜色映射

在 Matplotlib 中,您可以通过在名称后添加 _r 后缀来反转任意颜色映射。

# Set up the plot for the heatmap
plt.figure(figsize=(12, 8))

# Create a custom normalization for the color range
norm = mcolors.Normalize(vmin=16, vmax=40)

# Plot the heatmap using imshow with the sequential colormap
im = plt.imshow(monthly_temperature_table, cmap='YlOrRd_r', norm=norm, aspect='equal')

# Add a color bar with a horizontal orientation
cbar = plt.colorbar(im, orientation='horizontal', pad=0.1)
cbar.set_label('Temperature (°C)', labelpad=10)

# Add labels for the axes
plt.xlabel('Day of the Month')
plt.ylabel('Month')

# Set y-ticks to display month names instead of numbers
plt.yticks(ticks=np.arange(len(month_names)), labels=month_names)

# Add a title
plt.title('Temperature Heatmap (Sequential Colormap)')

# Display the plot
plt.show()

Matplotlib 使用 _r 后缀反转颜色映射

Matplotlib 使用 _r 后缀反转颜色映射。图片由作者提供。

处理 Matplotlib 颜色映射中的常见错误

使用 Matplotlib 的颜色映射时,您可能会遇到影响工作流程的错误。以下是一些常见错误及其排查方法。

AttributeError: module 'matplotlib' has no attribute 'colormaps'

当您在 3.4.0 之前的 Matplotlib 版本中访问 matplotlib.colormaps 时会出现此错误。colormaps 属性是在 Matplotlib 3.4.0 中引入的。首先使用下面的代码检查您的 Matplotlib 版本来排查此错误。

import matplotlib
print(matplotlib.__version__)

使用以下 pip 命令进行升级。

pip install --upgrade matplotlib

如果您在升级 Matplotlib 版本时遇到问题,可尝试以下方式访问颜色映射。

plt.get_cmap('viridis')  # instead of matplotlib.colormaps['viridis']

颜色分配不正确

当您传入超出预期范围的取值或错误地应用颜色映射时,可能会出现颜色分配不正确。如果将用于连续数据的颜色映射应用于分类数据,或反之亦然,也可能导致错误的颜色分配。

为确保数据位于预期范围内,请始终使用 vmax 和 vmin 参数进行归一化或缩放。

import matplotlib.colors as mcolors

# Create a sample temperature dataset
data = np.random.rand(10, 10) * 100  # Adjust the range to match your data

# Create a color normalization instance to scale the data to the colormap's range
norm = mcolors.Normalize(vmin=0, vmax=100)

# Create a heatmap using the 'viridis' colormap and the specified normalization
plt.imshow(data, cmap='viridis', norm=norm, interpolation='nearest')
plt.colorbar()
plt.show()

若需更精细的控制,您可以在绘图函数中通过 boundaries 或 norm 参数显式定义颜色边界。

视觉伪影与意外结果

处理离散或低分辨率数据时,您可能会遇到非期望的色带、过度对比或颜色渗漏。当数据范围有限却使用了连续型颜色映射时,常会出现此问题。

要解决此问题,可增加数据点数量或调整颜色级数以平滑过渡。

# Increase the number of bins in the colormap
cmap = plt.get_cmap('viridis', 256)
plt.imshow(data, cmap=cmap)

对于离散数据,您也可以将颜色映射拆分为固定级数,以便更恰当地呈现。

cmap = plt.get_cmap('inferno', 10)  # Divide colormap into 10 discrete levels
plt.imshow(data, cmap=cmap)

您还可以检查显示设置并在保存可视化时调整分辨率,避免低分辨率图表。

plt.savefig('plot.png', dpi=300)  # Save the figure with a higher resolution

裁剪导致的颜色失真

当数据包含超出预期颜色范围的极端值时,会发生颜色失真。这会导致部分数据被裁剪,并被赋予颜色映射中的最小或最大颜色。

为避免颜色失真,请使用 vmin 和 vmax 调整颜色范围,使其与数据范围匹配,从而避免裁剪。

plt.imshow(data, cmap='plasma', vmin=0, vmax=100)

您还应使用稳健缩放,通过设置自定义上、下限以排除极端值,从而处理离群点。

import numpy as np
robust_vmin, robust_vmax = np.percentile(data, [2, 98])  # Use percentiles to remove extreme outliers
plt.imshow(data, cmap='inferno', vmin=robust_vmin, vmax=robust_vmax)

3D 图中颜色映射显示不正确

如果 3D 曲面中的数据映射存在问题,颜色映射可能无法在 3D 可视化中正确显示。要解决此问题,请确保 z 轴数据已归一化以适配颜色映射的预期范围。同时,使用合适的颜色映射上下限以覆盖 z 值的完整范围。

from mpl_toolkits.mplot3d import Axes3D

# Generate sample data for a 3D surface plot
X, Y = np.meshgrid(np.linspace(-5, 5, 50), np.linspace(-5, 5, 50))
Z = np.sin(np.sqrt(X**2 + Y**2))

# Create a 3D axes object
ax = plt.axes(projection='3d')

# Plot the surface using the 'viridis' colormap and adjusting the color limits
ax.plot_surface(X, Y, Z, cmap='viridis', vmin=np.min(Z), vmax=np.max(Z))
plt.show()

总结

选择合适的颜色映射至关重要,因为它会深刻影响用户如何查看和理解您的数据。在我看来,把大量时间花在数据分析上,却在最后一步(也就是传达结论的部分)马虎了事,是一个大错误。

好在,Matplotlib 提供了众多选项,确保您的可视化能够讲述一个有说服力的故事。报名参加我们的课程 Introduction to Data Visualization with Matplotlib,成为这方面的专家。另外,如果您既是 Python 用户又使用 Seaborn 进行可视化(两者都会很有帮助),请阅读我们的 Seaborn 选色速查指南,并继续学习 Introduction to Data Visualization with Seaborn 课程。

Allan Ouko

作者

Allan Ouko

数据科学技术写作者,具备数据分析、商业智能和数据科学的一线实践经验。我撰写以行业为导向的实用内容,涵盖 SQL、Python、Power BI、Databricks 和数据工程,并以真实的分析工作为基础。我的写作兼顾技术深度与业务影响,帮助专业人士将数据转化为自信的决策。

Matplotlib 颜色映射常见问答

Matplotlib 的默认颜色映射是什么?

Matplotlib 的默认颜色映射是 viridis。

如何修复 “AttributeError: module 'matplotlib' has no attribute 'colormaps'” 错误?

要修复 AttributeError: module 'matplotlib' has no attribute 'colormaps' 错误,请将 Matplotlib 升级到 3.4.0 之后的版本。

如何测试颜色映射对色觉障碍用户的可访问性?

您可以使用 Coblis(色盲模拟器)等工具,或使用第三方库如 palettable 来模拟颜色映射在色觉障碍用户视角下的显示效果,从而测试可访问性。

什么是感知均匀的颜色映射?

感知均匀的颜色映射可确保数据的等距变化对应于颜色上的等感知变化,从而便于准确解读可视化。

我可以在 Matplotlib 中使用外部库的自定义颜色映射吗?

可以。palettable 或 cmocean 等外部库提供的自定义颜色映射可与 Matplotlib 集成,满足特定可视化需求。

主题