1. Matplotlib颜色基础:从单字符简写到完整色名
第一次用Matplotlib画图时,我盯着plt.plot(x, y, 'r--')里的'r'发愣——这个字母居然能控制颜色?后来才发现,Matplotlib藏着不少这样的"彩蛋"。单字符颜色代码就像编程界的摩斯密码,用最简短的表达传递丰富信息:
# 基础单字符颜色代码 'blue': 'b', 'green': 'g', 'red': 'r', 'cyan': 'c', 'magenta': 'm', 'yellow': 'y', 'black': 'k', 'white': 'w'但实际项目中,我们更常用完整英文色名。比如要画一组温度数据折线图:
import matplotlib.pyplot as plt temperatures = [22, 25, 28, 26, 23] plt.plot(temperatures, color='steelblue', linewidth=2) plt.title('Daily Temperature', color='darkslategray') plt.grid(color='lightgray', linestyle='--')这里用到的steelblue(钢蓝色)、darkslategray(深石板灰)比简单的'b'、'k'更能精准表达设计意图。Matplotlib支持的颜色名远不止基础色,完整列表可以通过以下代码查看:
from matplotlib import colors print(list(colors.CSS4_COLORS.keys())) # 输出148种CSS4颜色名称提示:在Jupyter Notebook中运行
colors.CSS4_COLORS会返回包含十六进制值的字典,方便直接复制使用
2. 颜色编码的三种核心格式
2.1 十六进制颜色码
设计师朋友递给我一张UI稿,指着某个元素说"这里用品牌蓝",然后发来#2A5CAA——这就是前端开发最常用的十六进制颜色表示法。在Matplotlib中,十六进制字符串可以直接作为颜色参数:
# 品牌色应用案例 brand_colors = { 'primary': '#2A5CAA', 'secondary': '#FFD43B', 'dark': '#333333' } plt.bar(['Q1', 'Q2', 'Q3'], [120, 145, 110], color=brand_colors['primary']) plt.plot([0.2, 0.8], [0.7, 0.7], color=brand_colors['secondary'], linewidth=4, transform=plt.gcf().transFigure)十六进制格式的优势在于:
- 与网页设计工具无缝对接
- 支持简写形式(如
#ABC等价于#AABBCC) - 直观反映RGB通道值
2.2 RGB/RGBA元组
当需要精确控制颜色通道时,我会使用0-1范围的RGB元组。比如创建半透明的误差带:
import numpy as np x = np.linspace(0, 10, 100) y = np.sin(x) error = 0.2 * np.random.rand(100) plt.fill_between(x, y-error, y+error, color=(0.2, 0.4, 0.6, 0.3)) # RGBA格式 plt.plot(x, y, color=(0.1, 0.3, 0.5)) # RGB格式这里第四个参数0.3表示30%透明度。在绘制重叠图形时,透明度能有效提升图表可读性。
2.3 灰度字符串
制作学术海报时,经常需要灰度图表。除了用'black',还可以用字符串形式的灰度值:
plt.subplot(121) plt.plot(np.random.rand(10), '0.8') # 浅灰 plt.title('Light Gray', color='0.3') # 深灰 plt.subplot(122) plt.scatter(range(5), np.random.rand(5), c='0.5') # 中灰 plt.title('Medium Gray', color='0')3. 专业颜色库深度对比
3.1 CSS4 vs X11颜色标准
Matplotlib同时支持CSS4和X11两种颜色标准,但有些色名在两个标准中存在差异。比如green在CSS4中是#008000,在X11中却是#00FF00。通过以下代码可以查看这些"同名不同色"的情况:
from matplotlib.colors import CSS4_COLORS, XKCD_COLORS conflicts = [] for name in CSS4_COLORS: if f'xkcd:{name}' in XKCD_COLORS: if CSS4_COLORS[name] != XKCD_COLORS[f'xkcd:{name}']: conflicts.append(name) print(f"存在差异的颜色名:{conflicts}")3.2 XKCD颜色调查
xkcd作者Randall Munroe曾发起颜色命名调查,产生了954种有趣的颜色名称。要在Matplotlib中使用它们,需要添加xkcd:前缀:
plt.barh(['程序员', '设计师', '产品经理'], [8, 6, 7], color=['xkcd:bright blue', 'xkcd:pea green', 'xkcd:dusty pink'])这些名字生动形象,比如xkcd:baby puke green(婴儿呕吐绿)、xkcd:radioactive lime(放射性柠檬黄),特别适合非正式报告。
3.3 Tableau经典配色
Tableau的默认配色在数据可视化领域广受好评。Matplotlib通过'tab:'前缀提供这些颜色:
categories = ['A', 'B', 'C', 'D'] values = [15, 30, 45, 10] plt.pie(values, labels=categories, colors=['tab:blue', 'tab:orange', 'tab:green', 'tab:red'])Tableau配色特点是饱和度适中、彼此区分度高,特别适合分类数据展示。
4. 颜色映射(Colormap)的科学选择
4.1 连续型数据配色
处理温度、海拔等连续数据时,线性渐变的colormap是首选。Matplotlib内置的viridis、plasma是经过优化的色系:
data = np.random.randn(1000).cumsum() plt.scatter(range(1000), data, c=data, cmap='viridis', alpha=0.6) plt.colorbar(label='Value')实测建议:避免使用传统的
jet色系,虽然颜色鲜艳但存在亮度突变,可能误导数据解读
4.2 离散型数据配色
当需要强调特定阈值时,BoundaryNorm配合ListedColormap能创建离散色阶:
from matplotlib.colors import BoundaryNorm, ListedColormap bounds = [-2, -1, 0, 1, 2] cmap = ListedColormap(['#2b83ba', '#abdda4', '#ffffbf', '#fdae61']) norm = BoundaryNorm(bounds, cmap.N) plt.contourf(np.random.randn(100).reshape(10,10), levels=bounds, cmap=cmap, norm=norm) plt.colorbar(ticks=bounds)4.3 分类数据配色
处理非有序分类数据时,需要确保各颜色在色相上有明显区分。tab20色系提供20种高对比度颜色:
categories = [f'Group {i}' for i in range(8)] values = np.random.randint(10, 50, size=8) plt.bar(categories, values, color=plt.get_cmap('tab20').colors[:8]) plt.xticks(rotation=45)5. 高级配色技巧与实践
5.1 创建自定义渐变色
当项目需要特定品牌渐变时,可以用LinearSegmentedColormap:
from matplotlib.colors import LinearSegmentedColormap brand_colors = ['#2A5CAA', '#7FB2FF', '#FFFFFF'] my_cmap = LinearSegmentedColormap.from_list('brand', brand_colors) plt.imshow(np.random.rand(10,10), cmap=my_cmap) plt.colorbar()5.2 颜色循环优化
默认的颜色循环可能不够用,通过修改rcParams可以扩展:
plt.rcParams['axes.prop_cycle'] = plt.cycler( color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'])5.3 无障碍配色检查
为色盲用户考虑,可以用colors.to_rgb()转换后检查亮度对比:
def check_contrast(color1, color2): rgb1 = colors.to_rgb(color1) rgb2 = colors.to_rgb(color2) lum1 = 0.299*rgb1[0] + 0.587*rgb1[1] + 0.114*rgb1[2] lum2 = 0.299*rgb2[0] + 0.587*rgb2[1] + 0.114*rgb2[2] return abs(lum1 - lum2) > 0.5 # 经验阈值 print(check_contrast('red', 'blue')) # 输出:False print(check_contrast('black', 'white')) # 输出:True6. 实战案例:气象数据可视化
结合温度降水数据,演示专业配色方案:
# 生成模拟数据 months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] temps = [5, 7, 12, 16, 20, 25] rains = [45, 40, 50, 60, 80, 120] fig, ax1 = plt.subplots(figsize=(10,6)) ax1.set_title('Monthly Climate Data', pad=20) # 温度折线(使用连续色系) temp_color = plt.get_cmap('YlOrRd')(0.7) ax1.plot(months, temps, color=temp_color, marker='o', linewidth=2) ax1.set_ylabel('Temperature (°C)', color=temp_color) ax1.tick_params(axis='y', labelcolor=temp_color) # 降水柱状(使用离散色系) rain_colors = plt.get_cmap('Blues')(np.linspace(0.3, 0.8, len(months))) ax2 = ax1.twinx() ax2.bar(months, rains, color=rain_colors, alpha=0.7) ax2.set_ylabel('Precipitation (mm)', color=rain_colors[-1]) ax2.tick_params(axis='y', labelcolor=rain_colors[-1]) # 添加图例 ax1.legend(['Temperature'], loc='upper left') ax2.legend(['Precipitation'], loc='upper right')