一、颜色表示方法
1. 基本颜色表示方式
import matplotlib.pyplot as plt
import numpy as np
# 八种基本颜色字符
basic_colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
# 对应:蓝(blue)、绿(green)、红(red)、青(cyan)、品红(magenta)、黄(yellow)、黑(black)、白(white)
# 使用示例
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 2*np.pi, 100)
for i, color in enumerate(basic_colors):
y = np.sin(x + i*0.5)
ax.plot(x, y, color=color, linewidth=2, label=f"'{color}'")
ax.legend()
ax.set_title('Matplotlib 基本颜色字符', fontsize=14)
plt.show()2. 扩展颜色名称
# 查看所有命名颜色
import matplotlib.colors as mcolors
# 所有命名颜色(140+种)
named_colors = list(mcolors.CSS4_COLORS.keys())
print(f"CSS4 颜色数量: {len(named_colors)}")
print("前20个颜色:", named_colors[:20])
# XKCD 颜色调查颜色(954种)
xkcd_colors = list(mcolors.XKCD_COLORS.keys())
print(f"\nXKCD 颜色数量: {len(xkcd_colors)}")
# 使用示例
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 常用CSS4颜色
common_colors = ['red', 'blue', 'green', 'orange', 'purple',
'brown', 'pink', 'gray', 'olive', 'cyan',
'navy', 'teal', 'maroon', 'lime', 'gold']
for i, ax in enumerate(axes.flat):
for j in range(5):
idx = i*5 + j
if idx < len(common_colors):
color_name = common_colors[idx]
ax.bar(j, 1, color=color_name, edgecolor='black')
ax.text(j, 0.5, color_name, ha='center', va='center',
fontsize=9, rotation=90, color='white')
ax.set_ylim(0, 1.2)
ax.axis('off')
ax.set_title(f'颜色组 {i+1}')
plt.suptitle('CSS4 命名颜色示例', fontsize=16)
plt.tight_layout()
plt.show()3. 十六进制颜色
# 十六进制颜色表示
hex_colors = [
'#FF5733', # 橙红色
'#33FF57', # 亮绿色
'#3357FF', # 蓝色
'#F0E68C', # 卡其色
'#8A2BE2', # 蓝紫色
'#FF1493', # 深粉色
'#00FFFF', # 青色
'#FFD700', # 金色
]
# 创建渐变色系
def generate_gradient(start_hex, end_hex, n=10):
"""生成两种颜色之间的渐变"""
start = mcolors.hex2color(start_hex)
end = mcolors.hex2color(end_hex)
return [mcolors.to_hex([(1-i/(n-1))*start[j] + (i/(n-1))*end[j]
for j in range(3)])
for i in range(n)]
# 示例:蓝色到红色的渐变
blue_to_red = generate_gradient('#0000FF', '#FF0000', 8)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# 显示十六进制颜色
for i, color in enumerate(hex_colors):
ax1.bar(i, 1, color=color, edgecolor='black', width=0.8)
ax1.text(i, 0.5, color, ha='center', va='center',
fontsize=10, rotation=90, color='white')
ax1.set_title('十六进制颜色示例', fontsize=14)
ax1.set_ylim(0, 1.2)
ax1.axis('off')
# 显示渐变色
for i, color in enumerate(blue_to_red):
ax2.bar(i, 1, color=color, edgecolor='black', width=0.8)
ax2.text(i, 0.5, f'{i+1}', ha='center', va='center',
fontsize=10, color='white')
ax2.set_title('蓝色到红色渐变', fontsize=14)
ax2.set_ylim(0, 1.2)
ax2.axis('off')
plt.tight_layout()
plt.show()4. RGB/RGBA 颜色
# RGB: 0-1之间的浮点数或0-255之间的整数
rgb_colors = [
(1.0, 0.0, 0.0), # 纯红 (浮点数)
(0.0, 1.0, 0.0), # 纯绿
(0.0, 0.0, 1.0), # 纯蓝
(0.5, 0.5, 0.0), # 橄榄色
# 整数表示 (0-255)
(255, 0, 0), # 纯红
(0, 255, 0), # 纯绿
(0, 0, 255), # 纯蓝
]
# RGBA: 包含透明度 (Alpha)
rgba_colors = [
(1.0, 0.0, 0.0, 0.5), # 半透明红色
(0.0, 1.0, 0.0, 0.3), # 30%透明绿色
(0.0, 0.0, 1.0, 0.8), # 80%透明蓝色
]
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# RGB颜色示例
ax = axes[0, 0]
for i, color in enumerate(rgb_colors[:4]):
ax.bar(i, 1, color=color, edgecolor='black')
ax.text(i, 0.5, f'RGB{color}', ha='center', va='center',
fontsize=10, color='white')
ax.set_title('RGB 浮点数颜色', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
# RGBA颜色示例
ax = axes[0, 1]
for i, color in enumerate(rgba_colors):
ax.bar(i, 1, color=color, edgecolor='black')
alpha = color[3] if len(color) == 4 else 1.0
ax.text(i, 0.5, f'α={alpha}', ha='center', va='center',
fontsize=10, color='black')
ax.set_title('RGBA 颜色(带透明度)', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
# HSV/HSL颜色空间
ax = axes[1, 0]
hues = np.linspace(0, 1, 12) # 色相
for i, hue in enumerate(hues):
# HSV 转 RGB
rgb_color = mcolors.hsv_to_rgb([hue, 0.8, 0.8])
ax.bar(i, 1, color=rgb_color, edgecolor='black')
ax.set_title('HSV 色相变化', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
# 灰度颜色
ax = axes[1, 1]
grays = np.linspace(0, 1, 10) # 0=黑, 1=白
for i, gray in enumerate(grays):
ax.bar(i, 1, color=str(gray), edgecolor='black')
ax.text(i, 0.5, f'{gray:.1f}', ha='center', va='center',
fontsize=10, color='white' if gray < 0.5 else 'black')
ax.set_title('灰度颜色', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
plt.suptitle('RGB/RGBA 颜色表示', fontsize=16)
plt.tight_layout()
plt.show()二、颜色映射(Colormap)系统
1. 查看所有颜色映射
import matplotlib.pyplot as plt
import numpy as np
# 获取所有颜色映射
cmaps = plt.colormaps()
print(f"Matplotlib 内置颜色映射数量: {len(cmaps)}")
# 分类显示
categories = {
'Perceptually Uniform Sequential': ['viridis', 'plasma', 'inferno', 'magma', 'cividis'],
'Sequential': ['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'],
'Sequential (2)': ['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
'hot', 'afmhot', 'gist_heat', 'copper'],
'Diverging': ['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'],
'Cyclic': ['twilight', 'twilight_shifted', 'hsv'],
'Qualitative': ['Pastel1', 'Pastel2', 'Paired', 'Accent',
'Dark2', 'Set1', 'Set2', 'Set3',
'tab10', 'tab20', 'tab20b', 'tab20c'],
'Miscellaneous': ['flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',
'gist_rainbow', 'rainbow', 'jet', 'turbo', 'nipy_spectral',
'gist_ncar']
}
# 显示部分重要颜色映射
fig, axes = plt.subplots(6, 6, figsize=(15, 15))
axes = axes.flatten()
important_cmaps = [
'viridis', 'plasma', 'inferno', 'magma', 'cividis', # 感知均匀
'Greys', 'Blues', 'Reds', 'Greens', 'Oranges', # 顺序色
'coolwarm', 'RdBu', 'Spectral', 'PiYG', 'seismic', # 发散色
'Set1', 'Set2', 'Set3', 'tab10', 'tab20', # 分类色
'rainbow', 'hsv', 'jet', 'turbo', 'gist_rainbow', # 彩虹色
'bone', 'pink', 'summer', 'winter', 'autumn', # 杂项
'terrain', 'ocean', 'gist_earth', 'gist_stern', # 地理相关
'twilight', 'prism', 'flag', 'Paired', 'Accent' # 特殊用途
]
for idx, (ax, cmap_name) in enumerate(zip(axes, important_cmaps)):
# 创建渐变色条
gradient = np.linspace(0, 1, 256).reshape(1, -1)
gradient = np.vstack((gradient, gradient))
ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(cmap_name))
ax.set_title(cmap_name, fontsize=9)
ax.axis('off')
# 隐藏多余的子图
for i in range(len(important_cmaps), len(axes)):
axes[i].axis('off')
plt.suptitle('重要颜色映射预览', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()2. 颜色映射分类详解
(1) 顺序颜色映射(Sequential)
# 适用于表示从低到高的数据
sequential_cmaps = ['viridis', 'plasma', 'summer', 'winter', 'Blues', 'Reds', 'Greens']
fig, axes = plt.subplots(2, 4, figsize=(15, 8))
axes = axes.flatten()
# 创建示例数据
x = np.linspace(0, 10, 100)
y = np.linspace(0, 10, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
for idx, cmap_name in enumerate(sequential_cmaps[:8]):
ax = axes[idx]
im = ax.imshow(Z, cmap=cmap_name, extent=[0, 10, 0, 10])
ax.set_title(f'{cmap_name}\n(顺序色)', fontsize=11)
ax.set_xlabel('X')
ax.set_ylabel('Y')
plt.colorbar(im, ax=ax, shrink=0.8)
# 隐藏多余的子图
for i in range(len(sequential_cmaps[:8]), 8):
axes[i].axis('off')
plt.suptitle('顺序颜色映射示例', fontsize=16, y=0.98)
plt.tight_layout()
plt.show()(2) 发散颜色映射(Diverging)
# 适用于有中心值的数据(如温度异常、相关性)
diverging_cmaps = ['coolwarm', 'RdBu', 'RdYlBu', 'Spectral', 'PiYG', 'seismic', 'bwr']
fig, axes = plt.subplots(2, 4, figsize=(15, 8))
axes = axes.flatten()
# 创建发散数据(有正负值)
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = X**2 - Y**2 # 有正有负的数据
for idx, cmap_name in enumerate(diverging_cmaps[:8]):
ax = axes[idx]
im = ax.imshow(Z, cmap=cmap_name, extent=[-5, 5, -5, 5])
ax.set_title(f'{cmap_name}\n(发散色)', fontsize=11)
ax.set_xlabel('X')
ax.set_ylabel('Y')
# 添加0值线
ax.contour(X, Y, Z, levels=[0], colors='black', linewidths=0.5)
plt.colorbar(im, ax=ax, shrink=0.8)
# 隐藏多余的子图
for i in range(len(diverging_cmaps[:8]), 8):
axes[i].axis('off')
plt.suptitle('发散颜色映射示例', fontsize=16, y=0.98)
plt.tight_layout()
plt.show()(3) 分类颜色映射(Qualitative/Categorical)
# 适用于分类数据,颜色差异明显
qualitative_cmaps = ['tab10', 'tab20', 'Set1', 'Set2', 'Set3', 'Pastel1', 'Pastel2', 'Dark2']
fig, axes = plt.subplots(2, 4, figsize=(15, 8))
axes = axes.flatten()
# 创建分类数据
categories = 10 # 10个类别
data = np.random.rand(10, 10)
labels = np.random.randint(0, categories, (10, 10))
for idx, cmap_name in enumerate(qualitative_cmaps[:8]):
ax = axes[idx]
cmap = plt.get_cmap(cmap_name)
# 显示颜色条
colors = cmap(np.arange(cmap.N))
ax.imshow([colors], aspect='auto', extent=[0, cmap.N, 0, 1])
ax.set_title(f'{cmap_name}\n({cmap.N}种颜色)', fontsize=11)
ax.set_xlabel('颜色索引')
ax.set_yticks([])
ax.set_xlim(0, cmap.N)
plt.suptitle('分类颜色映射示例', fontsize=16, y=0.98)
plt.tight_layout()
plt.show()3. 颜色映射的应用
# 实际应用示例
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 1. 热图(顺序色)
ax = axes[0, 0]
data = np.random.rand(10, 10)
im = ax.imshow(data, cmap='viridis')
ax.set_title('热图 - viridis (顺序色)', fontsize=12)
plt.colorbar(im, ax=ax)
# 2. 相关性矩阵(发散色)
ax = axes[0, 1]
corr_matrix = np.random.randn(5, 5)
corr_matrix = np.corrcoef(corr_matrix)
im = ax.imshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1)
ax.set_title('相关性矩阵 - coolwarm (发散色)', fontsize=12)
plt.colorbar(im, ax=ax)
# 3. 分类散点图(分类色)
ax = axes[0, 2]
np.random.seed(42)
n_points = 100
categories = np.random.randint(0, 10, n_points)
x = np.random.randn(n_points)
y = np.random.randn(n_points)
scatter = ax.scatter(x, y, c=categories, cmap='tab10', s=50, alpha=0.7)
ax.set_title('分类散点图 - tab10 (分类色)', fontsize=12)
plt.colorbar(scatter, ax=ax)
# 4. 地形图(地理色)
ax = axes[1, 0]
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X**2 + Y**2)
im = ax.imshow(Z, cmap='terrain', extent=[-3, 3, -3, 3])
ax.set_title('地形图 - terrain (地理色)', fontsize=12)
plt.colorbar(im, ax=ax)
# 5. 相位图(循环色)
ax = axes[1, 1]
x = np.linspace(0, 2*np.pi, 100)
y = np.linspace(0, 2*np.pi, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
im = ax.imshow(Z, cmap='twilight', extent=[0, 2*np.pi, 0, 2*np.pi])
ax.set_title('相位图 - twilight (循环色)', fontsize=12)
plt.colorbar(im, ax=ax)
# 6. 3D曲面(彩虹色)
from mpl_toolkits.mplot3d import Axes3D
ax = axes[1, 2]
ax.remove()
ax = fig.add_subplot(2, 3, 6, projection='3d')
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
surf = ax.plot_surface(X, Y, Z, cmap='rainbow', alpha=0.8)
ax.set_title('3D曲面 - rainbow (彩虹色)', fontsize=12)
fig.colorbar(surf, ax=ax, shrink=0.6)
plt.suptitle('颜色映射实际应用示例', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()三、自定义颜色映射
1. 从颜色列表创建
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
# 方法1:从颜色列表创建线性颜色映射
colors_list = ['#FF0000', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF']
custom_cmap1 = LinearSegmentedColormap.from_list('rainbow_custom', colors_list, N=256)
# 方法2:创建分类颜色映射
categorical_colors = ['#E41A1C', '#377EB8', '#4DAF4A', '#984EA3', '#FF7F00']
custom_cmap2 = ListedColormap(categorical_colors, name='categorical_custom')
# 方法3:使用颜色字典
cdict = {
'red': [(0.0, 0.0, 0.0),
(0.5, 1.0, 1.0),
(1.0, 1.0, 1.0)],
'green': [(0.0, 0.0, 0.0),
(0.25, 0.0, 0.0),
(0.75, 1.0, 1.0),
(1.0, 1.0, 1.0)],
'blue': [(0.0, 0.0, 0.0),
(0.5, 0.0, 0.0),
(1.0, 1.0, 1.0)]
}
custom_cmap3 = LinearSegmentedColormap('Custom3', cdict, 256)
# 显示自定义颜色映射
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
custom_cmaps = [custom_cmap1, custom_cmap2, custom_cmap3]
names = ['彩虹渐变', '分类颜色', '红绿蓝渐变']
# 显示颜色条
for i, (cmap, name) in enumerate(zip(custom_cmaps, names)):
ax = axes[0, i]
gradient = np.linspace(0, 1, 256).reshape(1, -1)
gradient = np.vstack((gradient, gradient))
ax.imshow(gradient, aspect='auto', cmap=cmap)
ax.set_title(f'{name}', fontsize=14)
ax.axis('off')
# 应用示例
data = np.random.rand(10, 10)
for i, (cmap, name) in enumerate(zip(custom_cmaps, names)):
ax = axes[1, i]
im = ax.imshow(data, cmap=cmap)
ax.set_title(f'应用: {name}', fontsize=12)
ax.axis('off')
plt.colorbar(im, ax=ax, shrink=0.8)
plt.suptitle('自定义颜色映射', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()2. 高级自定义技巧
from matplotlib.colors import LinearSegmentedColormap, PowerNorm, LogNorm
# 创建发散型自定义颜色映射
def create_diverging_cmap(low_color, high_color, center_color='white'):
"""创建发散颜色映射"""
colors = [low_color, center_color, high_color]
return LinearSegmentedColormap.from_list('diverging_custom', colors, N=256)
# 创建多段颜色映射
def create_multi_segment_cmap(colors, positions=None):
"""创建多段颜色映射"""
if positions is None:
positions = np.linspace(0, 1, len(colors))
cdict = {'red': [], 'green': [], 'blue': []}
for pos, color in zip(positions, colors):
r, g, b = mcolors.to_rgb(color)
cdict['red'].append((pos, r, r))
cdict['green'].append((pos, g, g))
cdict['blue'].append((pos, b, b))
return LinearSegmentedColormap('multi_segment', cdict, 256)
# 示例
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 1. 发散颜色映射
cmap_div = create_diverging_cmap('#0000FF', '#FF0000', '#FFFFFF')
ax = axes[0, 0]
gradient = np.linspace(0, 1, 256).reshape(1, -1)
ax.imshow(gradient, aspect='auto', cmap=cmap_div)
ax.set_title('蓝-白-红发散色', fontsize=12)
ax.axis('off')
# 2. 多段颜色映射
colors_multi = ['#0000FF', '#00FFFF', '#00FF00', '#FFFF00', '#FF0000']
cmap_multi = create_multi_segment_cmap(colors_multi)
ax = axes[0, 1]
ax.imshow(gradient, aspect='auto', cmap=cmap_multi)
ax.set_title('多段渐变色', fontsize=12)
ax.axis('off')
# 3. 透明度渐变色映射
colors_with_alpha = [
(1, 0, 0, 0.0), # 完全透明红色
(1, 0, 0, 0.5), # 半透明红色
(1, 0, 0, 1.0), # 不透明红色
]
cmap_alpha = LinearSegmentedColormap.from_list('alpha_cmap', colors_with_alpha)
ax = axes[0, 2]
ax.imshow(gradient, aspect='auto', cmap=cmap_alpha)
ax.set_title('透明度渐变色', fontsize=12)
ax.axis('off')
# 4. 非线性标准化
ax = axes[1, 0]
data = np.random.lognormal(mean=1, sigma=1, size=(10, 10))
im = ax.imshow(data, cmap='viridis', norm=LogNorm())
ax.set_title('LogNorm 标准化', fontsize=12)
plt.colorbar(im, ax=ax)
# 5. 幂律标准化
ax = axes[1, 1]
data = np.random.rand(10, 10) ** 2
im = ax.imshow(data, cmap='plasma', norm=PowerNorm(gamma=0.5))
ax.set_title('PowerNorm (gamma=0.5)', fontsize=12)
plt.colorbar(im, ax=ax)
# 6. 离散化颜色映射
from matplotlib.colors import BoundaryNorm
ax = axes[1, 2]
data = np.random.randn(10, 10)
# 定义边界和颜色
bounds = [-3, -2, -1, 0, 1, 2, 3]
norm = BoundaryNorm(bounds, ncolors=256)
im = ax.imshow(data, cmap='RdBu', norm=norm)
ax.set_title('BoundaryNorm 离散化', fontsize=12)
plt.colorbar(im, ax=ax, boundaries=bounds)
plt.suptitle('高级颜色映射技巧', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()四、颜色盲友好调色板
1. 颜色盲类型与友好颜色
# 颜色盲友好颜色方案
colorblind_friendly = {
'色盲通用': ['#377EB8', '#FF7F00', '#4DAF4A', # 蓝、橙、绿
'#F781BF', '#A65628', '#984EA3', # 粉、棕、紫
'#999999', '#E41A1C', '#DEDE00'], # 灰、红、黄绿
'红绿色盲优化': ['#006BA4', '#FF800E', '#ABABAB', # 深蓝、橙色、浅灰
'#595959', '#5F9ED1', '#C85200', # 深灰、浅蓝、深橙
'#898989', '#A2C8EC', '#FFBC79'], # 中灰、淡蓝、淡橙
'蓝黄色盲优化': ['#E69F00', '#56B4E9', '#009E73', # 橙、浅蓝、绿
'#F0E442', '#0072B2', '#D55E00', # 黄绿、蓝、红棕
'#CC79A7', '#000000'], # 紫、黑
}
# 颜色盲模拟函数
def simulate_colorblindness(color, deficiency_type='protanopia'):
"""
模拟不同类型的色盲
deficiency_type: 'protanopia'(红色盲),
'deuteranopia'(绿色盲),
'tritanopia'(蓝色盲)
"""
# 简化的色盲模拟矩阵(实际应用应使用更精确的转换)
matrices = {
'protanopia': np.array([[0.567, 0.433, 0],
[0.558, 0.442, 0],
[0, 0.242, 0.758]]),
'deuteranopia': np.array([[0.625, 0.375, 0],
[0.7, 0.3, 0],
[0, 0.3, 0.7]]),
'tritanopia': np.array([[0.95, 0.05, 0],
[0, 0.433, 0.567],
[0, 0.475, 0.525]])
}
rgb = np.array(mcolors.to_rgb(color))
return mcolors.to_hex(matrices[deficiency_type] @ rgb)
fig, axes = plt.subplots(3, 4, figsize=(16, 12))
deficiency_types = ['正常', '红色盲', '绿色盲', '蓝色盲']
color_sets = ['色盲通用', '红绿色盲优化', '蓝黄色盲优化']
for row, (set_name, colors) in enumerate(color_sets.items()):
for col, deficiency in enumerate(deficiency_types):
ax = axes[row, col]
for i, color in enumerate(colors):
if deficiency == '正常':
display_color = color
else:
display_color = simulate_colorblindness(color, deficiency)
ax.bar(i, 1, color=display_color, edgecolor='black')
ax.text(i, 0.5, str(i+1), ha='center', va='center',
fontsize=10, color='white' if i not in [3, 7] else 'black')
ax.set_ylim(0, 1.2)
ax.set_title(f'{set_name}\n{deficiency}', fontsize=11)
ax.axis('off')
plt.suptitle('颜色盲友好调色板', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()2. 实际应用建议
# 创建颜色盲友好的可视化
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 1. 分类数据 - 使用Set2(颜色盲友好)
ax = axes[0, 0]
np.random.seed(42)
n_categories = 8
data = np.random.rand(5, n_categories)
x = np.arange(5)
for i in range(n_categories):
ax.bar(x + i*0.1, data[:, i], width=0.1,
color=plt.cm.Set2(i/n_categories),
label=f'类别 {i+1}')
ax.set_title('分类柱状图 - Set2', fontsize=12)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
# 2. 顺序数据 - 使用viridis(颜色盲友好)
ax = axes[0, 1]
data = np.random.rand(10, 10)
im = ax.imshow(data, cmap='viridis')
ax.set_title('热图 - viridis', fontsize=12)
plt.colorbar(im, ax=ax)
# 3. 发散数据 - 使用coolwarm(颜色盲友好)
ax = axes[0, 2]
data = np.random.randn(10, 10)
im = ax.imshow(data, cmap='coolwarm', vmin=-2, vmax=2)
ax.set_title('发散数据 - coolwarm', fontsize=12)
plt.colorbar(im, ax=ax)
# 4. 散点图 - 使用颜色盲友好调色板
ax = axes[1, 0]
np.random.seed(42)
n_points = 50
categories = np.random.randint(0, 6, n_points)
x = np.random.randn(n_points)
y = np.random.randn(n_points)
# 使用颜色盲友好颜色
cb_friendly_colors = ['#377EB8', '#FF7F00', '#4DAF4A',
'#F781BF', '#A65628', '#984EA3']
for i in range(6):
mask = categories == i
ax.scatter(x[mask], y[mask], color=cb_friendly_colors[i],
s=50, alpha=0.7, label=f'组{i+1}')
ax.set_title('散点图 - 颜色盲友好', fontsize=12)
ax.legend()
# 5. 折线图 - 使用线型和标记区分
ax = axes[1, 1]
x = np.linspace(0, 10, 100)
line_styles = ['-', '--', '-.', ':']
markers = ['o', 's', '^', 'D']
for i in range(4):
y = np.sin(x + i*0.5)
ax.plot(x, y, linestyle=line_styles[i],
marker=markers[i], markevery=10,
color='black', # 统一用黑色,用样式区分
label=f'序列{i+1}')
ax.set_title('折线图 - 用样式区分', fontsize=12)
ax.legend()
# 6. 饼图 - 使用纹理填充
ax = axes[1, 2]
sizes = [30, 25, 20, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
# 定义纹理模式
patterns = ['/', '\\', '|', '-', '+']
colors = ['gray'] * 5 # 统一颜色
wedges, texts = ax.pie(sizes, labels=labels, colors=colors)
# 添加纹理
for wedge, pattern in zip(wedges, patterns):
wedge.set_hatch(pattern)
ax.set_title('饼图 - 用纹理区分', fontsize=12)
plt.suptitle('颜色盲友好可视化实践', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()五、颜色工具与实用函数
1. 颜色转换工具
import matplotlib.colors as mcolors
def demonstrate_color_conversions():
"""演示颜色转换"""
# 测试颜色
test_colors = [
'red', # 颜色名
'#FF0000', # 十六进制
(1.0, 0.0, 0.0), # RGB浮点
(255, 0, 0), # RGB整数
(1.0, 0.0, 0.0, 0.5) # RGBA
]
print("颜色转换演示:")
print("="*60)
for color in test_colors:
print(f"\n输入: {color}")
# 转换为RGB浮点
try:
rgb = mcolors.to_rgb(color)
print(f" → RGB浮点: {rgb}")
except Exception as e:
print(f" → RGB转换错误: {e}")
# 转换为RGBA浮点
try:
rgba = mcolors.to_rgba(color)
print(f" → RGBA浮点: {rgba}")
except Exception as e:
print(f" → RGBA转换错误: {e}")
# 转换为十六进制
try:
hex_color = mcolors.to_hex(color)
print(f" → 十六进制: {hex_color}")
except Exception as e:
print(f" → 十六进制转换错误: {e}")
# 转换为HSV
try:
hsv = mcolors.rgb_to_hsv(mcolors.to_rgb(color))
print(f" → HSV: {hsv}")
except Exception as e:
print(f" → HSV转换错误: {e}")
# 运行演示
demonstrate_color_conversions()
# 创建颜色转换工具界面
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 1. 颜色拾取器模拟
ax = axes[0, 0]
# 创建颜色网格
colors_grid = np.random.rand(10, 10, 3)
ax.imshow(colors_grid)
ax.set_title('颜色拾取器', fontsize=12)
ax.axis('off')
# 添加点击事件(模拟)
ax.text(0.5, -0.1, '点击选择颜色 →', transform=ax.transAxes,
ha='center', fontsize=10, style='italic')
# 2. 颜色梯度生成器
ax = axes[0, 1]
start_color = '#FF0000'
end_color = '#0000FF'
n_steps = 10
gradient_colors = []
for i in range(n_steps):
t = i / (n_steps - 1)
# 线性插值
start_rgb = mcolors.to_rgb(start_color)
end_rgb = mcolors.to_rgb(end_color)
interp_color = [(1-t)*start_rgb[j] + t*end_rgb[j] for j in range(3)]
gradient_colors.append(interp_color)
for i, color in enumerate(gradient_colors):
ax.bar(i, 1, color=color, edgecolor='black')
hex_color = mcolors.to_hex(color)
ax.text(i, 0.5, hex_color, ha='center', va='center',
fontsize=8, rotation=90, color='white')
ax.set_title(f'渐变: {start_color} → {end_color}', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
# 3. 颜色调和
ax = axes[1, 0]
color1 = '#FF0000'
color2 = '#00FF00'
color3 = '#0000FF'
# 显示原色
ax.bar(0, 1, color=color1, edgecolor='black', label='红')
ax.bar(1, 1, color=color2, edgecolor='black', label='绿')
ax.bar(2, 1, color=color3, edgecolor='black', label='蓝')
# 显示混合色
mix1 = mcolors.to_hex([0.5, 0.5, 0]) # 红+绿=黄
mix2 = mcolors.to_hex([0.5, 0, 0.5]) # 红+蓝=紫
mix3 = mcolors.to_hex([0, 0.5, 0.5]) # 绿+蓝=青
ax.bar(4, 1, color=mix1, edgecolor='black', label='红+绿')
ax.bar(5, 1, color=mix2, edgecolor='black', label='红+蓝')
ax.bar(6, 1, color=mix3, edgecolor='black', label='绿+蓝')
ax.set_title('颜色调和', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.1), ncol=3)
# 4. 颜色亮度调整
ax = axes[1, 1]
base_color = '#FF0000'
base_rgb = mcolors.to_rgb(base_color)
# 创建不同亮度的颜色
for i in range(10):
brightness = i / 9
# 调整亮度
adjusted_color = [c * brightness for c in base_rgb]
ax.bar(i, 1, color=adjusted_color, edgecolor='black')
ax.text(i, 0.5, f'{brightness:.1f}', ha='center', va='center',
fontsize=9, color='white' if brightness < 0.5 else 'black')
ax.set_title(f'亮度调整: {base_color}', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
plt.suptitle('颜色工具与实用函数', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()2. 自动配色方案生成
def generate_color_scheme(base_color, scheme_type='analogous', n_colors=5):
"""
生成配色方案
scheme_type:
- 'analogous': 类似色(相邻色相)
- 'complementary': 互补色
- 'triadic': 三角色
- 'tetradic': 矩形色
- 'monochromatic': 单色调
"""
# 转换为HSV
base_hsv = mcolors.rgb_to_hsv(mcolors.to_rgb(base_color))
h, s, v = base_hsv
colors = []
if scheme_type == 'analogous':
# 类似色:基础色相±30度
hues = [(h + i*30/360) % 1 for i in range(-(n_colors//2), n_colors//2 + 1)]
colors = [mcolors.hsv_to_rgb([hue, s, v]) for hue in hues]
elif scheme_type == 'complementary':
# 互补色:基础色相±180度
complementary_h = (h + 0.5) % 1
colors = [mcolors.hsv_to_rgb([h, s, v]),
mcolors.hsv_to_rgb([complementary_h, s, v])]
elif scheme_type == 'triadic':
# 三角色:基础色相±120度
colors = [mcolors.hsv_to_rgb([(h + i/3) % 1, s, v]) for i in range(3)]
elif scheme_type == 'tetradic':
# 矩形色:基础色相±90度, ±180度
colors = [mcolors.hsv_to_rgb([(h + i*0.25) % 1, s, v]) for i in range(4)]
elif scheme_type == 'monochromatic':
# 单色调:调整饱和度或亮度
for i in range(n_colors):
factor = i / (n_colors - 1)
# 调整亮度
new_v = v * (0.5 + 0.5*factor)
colors.append(mcolors.hsv_to_rgb([h, s, new_v]))
return [mcolors.to_hex(color) for color in colors]
# 演示配色方案生成
base_color = '#3498db' # 蓝色
scheme_types = ['analogous', 'complementary', 'triadic', 'tetradic', 'monochromatic']
fig, axes = plt.subplots(3, 2, figsize=(12, 15))
axes = axes.flatten()
for idx, scheme_type in enumerate(scheme_types):
ax = axes[idx]
colors = generate_color_scheme(base_color, scheme_type, n_colors=5)
for i, color in enumerate(colors):
ax.bar(i, 1, color=color, edgecolor='black')
ax.text(i, 0.5, color, ha='center', va='center',
fontsize=9, rotation=90, color='white')
ax.set_title(f'{scheme_type.capitalize()} 配色方案\n基础色: {base_color}',
fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
# 最后一个子图显示基础色
ax = axes[-1]
ax.bar(0, 1, color=base_color, edgecolor='black')
ax.text(0.5, 0.5, f'基础色\n{base_color}',
ha='center', va='center', fontsize=12, color='white')
ax.set_title('基础颜色', fontsize=12)
ax.set_ylim(0, 1.2)
ax.axis('off')
plt.suptitle('自动配色方案生成', fontsize=16, y=0.95)
plt.tight_layout()
plt.show()颜色使用最佳实践
- 数据语义匹配:
- 顺序数据 → 顺序颜色映射(viridis, plasma等)
- 分类数据 → 分类颜色映射(Set3, tab20等)
- 发散数据 → 发散颜色映射(coolwarm, RdBu等)
- 可访问性考虑:
- 避免红绿搭配(色盲不友好)
- 提供纹理/图案作为颜色替代
- 测试颜色盲模拟效果
- 美学原则:
- 限制颜色数量(一般不超过6-8种)
- 使用调色板而非随机颜色
- 保持一致性(相同含义使用相同颜色)
- 性能优化:
- 对于大量数据,使用轻量级颜色映射
- 避免不必要的颜色转换
- 预计算颜色映射
- 导出考虑:
- 打印时使用CMYK安全颜色
- 网页使用sRGB颜色空间
- 考虑不同设备的颜色显示差异
通过合理使用Matplotlib的颜色系统,可以创建出既美观又实用的数据可视化图表。
