一、颜色系统
1. 基本颜色表示
import matplotlib.pyplot as plt
import numpy as np
# 1. 颜色字符串(8种基本颜色)
basic_colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
# blue, green, red, cyan, magenta, yellow, black, white
# 2. 扩展颜色名(140+种)
named_colors = ['red', 'blue', 'green', 'orange', 'purple',
'brown', 'pink', 'gray', 'olive', 'cyan']
# 3. 十六进制颜色
hex_colors = ['#FF5733', '#33FF57', '#3357FF', '#F0E68C', '#8A2BE2']
# 4. RGB/RGBA元组
rgb_colors = [
(1.0, 0.0, 0.0), # 纯红
(0.0, 0.5, 0.0), # 深绿
(0.2, 0.4, 0.6), # 蓝灰
(0.5, 0.5, 0.5, 0.5), # 半透明白
]
# 5. 灰度值
gray_colors = ['0.0', '0.25', '0.5', '0.75', '1.0'] # 黑到白2. 颜色映射(Colormap)
# 查看所有颜色映射
print(plt.colormaps()[:10]) # 显示前10个
# 分类颜色映射(适用于分类数据)
categorical_cmaps = ['tab10', 'tab20', 'Set1', 'Set2', 'Set3', 'Pastel1']
# 连续颜色映射(适用于连续数据)
sequential_cmaps = ['viridis', 'plasma', 'inferno', 'magma', 'cividis',
'Greys', 'Blues', 'Greens', 'Oranges', 'Reds']
# 发散颜色映射(适用于有中心值的数据)
diverging_cmaps = ['RdBu', 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm']
# 使用示例
fig, axes = plt.subplots(3, 3, figsize=(12, 10))
cmaps = ['viridis', 'plasma', 'inferno',
'RdBu', 'coolwarm', 'Spectral',
'Set1', 'tab10', 'Pastel1']
for ax, cmap in zip(axes.flat, cmaps):
data = np.random.rand(10, 10)
im = ax.imshow(data, cmap=cmap)
ax.set_title(cmap)
ax.axis('off')
plt.colorbar(im, ax=ax, shrink=0.8)
plt.suptitle('常用颜色映射示例', fontsize=16)
plt.tight_layout()
plt.show()3. 自定义颜色映射
from matplotlib.colors import LinearSegmentedColormap
# 方法1:从颜色列表创建
colors = ['#FF0000', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF']
custom_cmap = LinearSegmentedColormap.from_list('my_cmap', colors, N=256)
# 方法2:定义颜色节点
cdict = {
'red': [(0.0, 0.0, 0.0), # 在0.0位置,红色为0
(0.5, 1.0, 1.0), # 在0.5位置,红色为1
(1.0, 1.0, 1.0)], # 在1.0位置,红色为1
'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_cmap2 = LinearSegmentedColormap('Custom2', cdict, 256)
# 应用自定义颜色映射
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 使用第一个自定义颜色映射
im1 = ax1.imshow(np.random.rand(10, 10), cmap=custom_cmap)
ax1.set_title('彩虹色映射')
plt.colorbar(im1, ax=ax1)
# 使用第二个自定义颜色映射
im2 = ax2.imshow(np.random.rand(10, 10), cmap=custom_cmap2)
ax2.set_title('红绿蓝渐变映射')
plt.colorbar(im2, ax=ax2)
plt.tight_layout()
plt.show()二、线型与标记
1. 线型(Line Styles)
# 基本线型
line_styles = [
'-', # 实线
'--', # 虚线
'-.', # 点划线
':', # 点线
' ', # 无线
'', # 无线
'None' # 无线
]
# 自定义线型
custom_linestyle = {
'dotted': (0, (1, 1)), # 点线
'dashed': (0, (5, 5)), # 虚线
'dashdot': (0, (3, 5, 1, 5)), # 点划线
'loosely dotted': (0, (1, 10)), # 稀疏点线
'densely dotted': (0, (1, 1)), # 密集点线
'loosely dashed': (0, (5, 10)), # 稀疏虚线
'densely dashed': (0, (5, 1)), # 密集虚线
}
# 线型演示
fig, ax = plt.subplots(figsize=(12, 6))
x = np.linspace(0, 10, 100)
# 基本线型
for i, ls in enumerate(line_styles[:4]):
y = np.sin(x) + i * 0.5
ax.plot(x, y, linestyle=ls, linewidth=2, label=f"linestyle='{ls}'")
# 自定义线型
for i, (name, ls) in enumerate(custom_linestyle.items()):
y = np.cos(x) + (i + 4) * 0.5
ax.plot(x, y, linestyle=ls, linewidth=2, label=name)
ax.legend(ncol=2, loc='upper right')
ax.set_title('线型样式示例', fontsize=14)
ax.grid(True, alpha=0.3)
plt.show()2. 标记(Markers)
# 基本标记类型
markers = [
'.', # 点
',', # 像素点
'o', # 圆圈
'v', # 倒三角
'^', # 正三角
'<', # 左三角
'>', # 右三角
'1', # 三脚架下
'2', # 三脚架上
'3', # 三脚架左
'4', # 三脚架右
'8', # 八角形
's', # 正方形
'p', # 五边形
'*', # 星号
'h', # 六边形1
'H', # 六边形2
'+', # 加号
'x', # 叉号
'D', # 菱形
'd', # 瘦菱形
'|', # 竖线
'_', # 横线
'P', # 加号填充
'X', # 叉号填充
]
# 标记演示
fig, axes = plt.subplots(4, 6, figsize=(15, 10))
axes = axes.flatten()
for i, (ax, marker) in enumerate(zip(axes, markers)):
x = np.arange(5)
y = np.ones(5) * i
ax.scatter(x, y, marker=marker, s=100, edgecolor='k', linewidth=1)
ax.set_title(f"'{marker}'", fontsize=12)
ax.set_xlim(-1, 5)
ax.set_ylim(-1, len(markers))
ax.axis('off')
plt.suptitle('标记样式大全', fontsize=16)
plt.tight_layout()
plt.show()3. 线型与标记组合
fig, ax = plt.subplots(figsize=(12, 8))
# 创建组合样式
styles = [
{'marker': 'o', 'linestyle': '-', 'color': 'blue'},
{'marker': 's', 'linestyle': '--', 'color': 'red'},
{'marker': '^', 'linestyle': '-.', 'color': 'green'},
{'marker': 'D', 'linestyle': ':', 'color': 'orange'},
{'marker': '*', 'linestyle': ' ', 'color': 'purple'}, # 只有标记
{'marker': ' ', 'linestyle': '-', 'color': 'brown'}, # 只有线
]
x = np.linspace(0, 10, 20)
for i, style in enumerate(styles):
y = np.sin(x) + i * 0.8
ax.plot(x, y,
marker=style['marker'],
linestyle=style['linestyle'],
color=style['color'],
markersize=10,
markerfacecolor='white',
markeredgecolor=style['color'],
markeredgewidth=2,
linewidth=2,
label=f"样式{i+1}")
ax.legend(loc='upper right', ncol=2)
ax.set_title('线型与标记组合示例', fontsize=14)
ax.grid(True, alpha=0.3)
plt.show()三、文本装饰
1. 字体与样式
# 系统可用字体
import matplotlib.font_manager as fm
fonts = [f.name for f in fm.fontManager.ttflist]
print(f"可用字体数量: {len(fonts)}")
print("部分字体:", fonts[:10])
# 字体属性设置
font_properties = {
'family': 'serif', # 字体族: 'serif', 'sans-serif', 'monospace'
'style': 'italic', # 样式: 'normal', 'italic', 'oblique'
'variant': 'normal', # 变体: 'normal', 'small-caps'
'weight': 'bold', # 粗细: 'light', 'normal', 'medium', 'semibold', 'bold', 'black'
'stretch': 'normal', # 拉伸: 'ultra-condensed' 到 'ultra-expanded'
'size': 12 # 大小
}
# 应用示例
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y)
# 添加不同样式的文本
texts = [
('正常文本', (1, 0.5), {'fontsize': 12}),
('粗体文本', (3, 0), {'fontweight': 'bold', 'fontsize': 14}),
('斜体文本', (5, -0.5), {'fontstyle': 'italic', 'fontsize': 12}),
('大号文本', (7, 0.5), {'fontsize': 16}),
('彩色文本', (2, 0.8), {'color': 'red', 'fontsize': 12}),
('带框文本', (4, 0.8), {'bbox': dict(boxstyle='round', facecolor='yellow', alpha=0.5)}),
('旋转文本', (8, -0.5), {'rotation': 45, 'fontsize': 12}),
]
for text_str, position, props in texts:
ax.text(position[0], position[1], text_str, **props)
ax.set_title('文本样式示例', fontsize=16, fontweight='bold')
plt.show()2. 数学公式
fig, ax = plt.subplots(figsize=(12, 8))
# 行内公式(单$符号)
ax.text(0.1, 0.9, r'行内公式: $E = mc^2$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.8, r'希腊字母: $\alpha, \beta, \gamma$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.7, r'上下标: $x^2 + y_1$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.6, r'分数: $\frac{a}{b}$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.5, r'根号: $\sqrt{x}$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.4, r'积分: $\int_a^b f(x)dx$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.3, r'求和: $\sum_{i=1}^n i$', fontsize=14, transform=ax.transAxes)
ax.text(0.1, 0.2, r'矩阵: $\begin{pmatrix} a & b \\ c & d \end{pmatrix}$', fontsize=14, transform=ax.transAxes)
# 多行公式($$符号)
equation = r'''
多行公式:
$$
\begin{aligned}
f(x) &= \int_{-\infty}^{\infty} \hat{f}(\xi) e^{2\pi i \xi x} d\xi \\
&= \lim_{n \to \infty} \sum_{k=1}^{n} f(x_k) \Delta x
\end{aligned}
$$
'''
ax.text(0.6, 0.5, equation, fontsize=14, transform=ax.transAxes,
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.set_title('LaTeX数学公式示例', fontsize=16, fontweight='bold')
plt.show()3. 注释与箭头
fig, ax = plt.subplots(figsize=(12, 8))
# 绘制示例曲线
x = np.linspace(0, 10, 100)
y = np.sin(x) * np.exp(-x/10)
ax.plot(x, y, 'b-', linewidth=2)
# 1. 基本注释
ax.annotate('最大值点',
xy=(np.pi/2, max(y)), # 箭头指向的位置
xytext=(np.pi/2 + 1, max(y) + 0.1), # 文本位置
arrowprops=dict(arrowstyle='->', connectionstyle='arc3', color='red'),
fontsize=12)
# 2. 带不同箭头的注释
arrow_styles = ['->', '-[', '<-', '<->', 'fancy', 'wedge', 'simple']
for i, arrowstyle in enumerate(arrow_styles):
x_pos = 1 + i * 1.2
y_pos = -0.2 - i * 0.05
ax.annotate(f"'{arrowstyle}'",
xy=(x_pos, np.sin(x_pos) * np.exp(-x_pos/10)),
xytext=(x_pos, y_pos),
arrowprops=dict(arrowstyle=arrowstyle,
color='green',
lw=1.5,
shrinkA=5, shrinkB=5),
fontsize=10,
ha='center')
# 3. 文本框注释
ax.text(0.02, 0.98, '曲线说明:\n• 衰减的正弦波\n• 时间常数: 10\n• 初始相位: 0',
transform=ax.transAxes,
fontsize=12,
verticalalignment='top',
bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
# 4. 连接线注释
ax.annotate('',
xy=(8, y[80]),
xytext=(8.5, -0.3),
arrowprops=dict(arrowstyle='->',
connectionstyle='angle3,angleA=90,angleB=0',
color='purple',
lw=2))
ax.text(8.5, -0.35, '连接线示例', ha='center', fontsize=10)
ax.set_title('注释与箭头装饰示例', fontsize=16)
ax.grid(True, alpha=0.3)
plt.show()四、填充与阴影
1. 区域填充
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 子图1:基本填充
ax = axes[0, 0]
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
ax.plot(x, y1, 'b-', label='sin(x)')
ax.plot(x, y2, 'r--', label='cos(x)')
ax.fill_between(x, y1, y2, where=(y1 > y2), color='green', alpha=0.3, label='sin > cos')
ax.fill_between(x, y1, y2, where=(y1 <= y2), color='red', alpha=0.3, label='sin ≤ cos')
ax.legend()
ax.set_title('fill_between 区域填充')
# 子图2:与基准线填充
ax = axes[0, 1]
x = np.arange(10)
y = np.random.randn(10).cumsum()
ax.plot(x, y, 'o-')
ax.fill_between(x, y, 0, where=(y > 0), color='green', alpha=0.3, interpolate=True)
ax.fill_between(x, y, 0, where=(y <= 0), color='red', alpha=0.3, interpolate=True)
ax.axhline(y=0, color='black', linestyle='--', alpha=0.5)
ax.set_title('与基准线填充')
# 子图3:多边形填充
ax = axes[1, 0]
t = np.linspace(0, 2*np.pi, 100)
x = 2 * np.cos(t) + np.cos(2*t)
y = 2 * np.sin(t) - np.sin(2*t)
ax.fill(x, y, 'orange', alpha=0.7, edgecolor='darkorange', linewidth=2)
ax.set_title('多边形填充')
ax.set_aspect('equal')
# 子图4:渐变填充
ax = axes[1, 1]
x = np.linspace(0, 10, 100)
y = np.exp(-x/5) * np.sin(x)
ax.plot(x, y, 'b-', linewidth=2)
# 创建渐变填充
for i in range(len(x)-1):
alpha = 1 - i/len(x) # 渐变透明度
ax.fill_between(x[i:i+2], 0, y[i:i+2],
color='blue',
alpha=alpha*0.3)
ax.set_title('渐变透明度填充')
plt.suptitle('填充装饰示例', fontsize=16)
plt.tight_layout()
plt.show()2. 阴影效果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 子图1:误差带
ax = axes[0, 0]
x = np.linspace(0, 10, 50)
y = np.sin(x)
y_err = 0.2 * np.ones_like(x)
ax.plot(x, y, 'b-', linewidth=2, label='均值')
ax.fill_between(x, y - y_err, y + y_err,
alpha=0.3, color='blue', label='±1σ')
ax.fill_between(x, y - 2*y_err, y + 2*y_err,
alpha=0.2, color='blue', label='±2σ')
ax.legend()
ax.set_title('误差带阴影')
# 子图2:置信区间
ax = axes[0, 1]
np.random.seed(42)
x = np.linspace(0, 10, 30)
y_true = 2 * x + 1
y_noise = y_true + np.random.randn(30) * 3
# 模拟置信区间
y_pred = 2.1 * x + 0.8 # 预测值
ci_lower = y_pred - 4
ci_upper = y_pred + 4
ax.scatter(x, y_noise, alpha=0.6, label='观测值')
ax.plot(x, y_pred, 'r-', linewidth=2, label='回归线')
ax.fill_between(x, ci_lower, ci_upper,
color='red', alpha=0.2, label='95%置信区间')
ax.legend()
ax.set_title('置信区间阴影')
# 子图3:柱状图阴影
ax = axes[1, 0]
categories = ['A', 'B', 'C', 'D', 'E']
values = [25, 40, 30, 35, 20]
bars = ax.bar(categories, values,
color='skyblue',
edgecolor='navy',
linewidth=2)
# 添加阴影效果
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height + 1,
f'{height}', ha='center', va='bottom',
fontsize=10, fontweight='bold')
# 添加阴影
shadow = plt.Rectangle((bar.get_x() + 0.05, 0),
bar.get_width() - 0.1,
height,
color='gray', alpha=0.3, zorder=0)
ax.add_patch(shadow)
ax.set_title('柱状图阴影效果')
# 子图4:文字阴影
ax = axes[1, 1]
ax.axis([0, 1, 0, 1])
ax.axis('off')
# 创建带阴影的文字
def text_with_shadow(ax, x, y, text, fontsize=24, shadow_offset=0.005):
# 先画阴影
ax.text(x + shadow_offset, y - shadow_offset, text,
fontsize=fontsize, fontweight='bold',
color='gray', alpha=0.5,
transform=ax.transAxes)
# 再画实际文字
ax.text(x, y, text,
fontsize=fontsize, fontweight='bold',
color='darkred',
transform=ax.transAxes)
text_with_shadow(ax, 0.1, 0.8, '阴影文字效果', 28)
text_with_shadow(ax, 0.2, 0.6, '3D立体感', 32, 0.008)
text_with_shadow(ax, 0.3, 0.4, '装饰性强', 36, 0.01)
text_with_shadow(ax, 0.4, 0.2, '重点突出', 40, 0.012)
ax.set_title('文字阴影效果')
plt.suptitle('阴影装饰示例', fontsize=16)
plt.tight_layout()
plt.show()五、边框与背景
1. 坐标轴装饰
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 子图1:基本坐标轴样式
ax = axes[0, 0]
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
ax.set_title('默认坐标轴')
# 子图2:隐藏坐标轴
ax = axes[0, 1]
ax.plot(x, np.cos(x))
ax.axis('off') # 隐藏所有坐标轴
ax.set_title('隐藏坐标轴')
# 子图3:自定义坐标轴样式
ax = axes[0, 2]
ax.plot(x, np.tan(x)/10) # 缩放tan函数
ax.spines['top'].set_visible(False) # 隐藏顶部边框
ax.spines['right'].set_visible(False) # 隐藏右侧边框
ax.spines['left'].set_linewidth(2) # 加粗左侧边框
ax.spines['left'].set_color('red') # 左侧边框红色
ax.spines['bottom'].set_linewidth(2) # 加粗底部边框
ax.spines['bottom'].set_color('blue') # 底部边框蓝色
ax.set_title('自定义坐标轴边框')
# 子图4:移动坐标轴位置
ax = axes[1, 0]
ax.plot(x, np.exp(-x/5) * np.sin(x))
ax.spines['left'].set_position('center') # 左侧坐标轴移到中心
ax.spines['bottom'].set_position('center') # 底部坐标轴移到中心
ax.spines['right'].set_color('none') # 隐藏右侧坐标轴
ax.spines['top'].set_color('none') # 隐藏顶部坐标轴
ax.xaxis.set_ticks_position('bottom') # X轴刻度在底部
ax.yaxis.set_ticks_position('left') # Y轴刻度在左侧
ax.set_title('坐标轴居中')
# 子图5:双坐标轴
ax = axes[1, 1]
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.exp(-x/5) * 100
color1 = 'tab:blue'
color2 = 'tab:red'
ax.plot(x, y1, color=color1, label='sin(x)')
ax.set_xlabel('x')
ax.set_ylabel('sin(x)', color=color1)
ax.tick_params(axis='y', labelcolor=color1)
# 创建第二个Y轴
ax2 = ax.twinx()
ax2.plot(x, y2, color=color2, linestyle='--', label='exp(-x/5)*100')
ax2.set_ylabel('衰减指数', color=color2)
ax2.tick_params(axis='y', labelcolor=color2)
ax.set_title('双Y轴图表')
# 子图6:极坐标轴
ax = axes[1, 2]
ax = plt.subplot(236, projection='polar')
theta = np.linspace(0, 2*np.pi, 100)
r = 1 + 0.5 * np.sin(5*theta)
ax.plot(theta, r)
ax.set_title('极坐标轴', pad=20)
ax.grid(True)
plt.suptitle('坐标轴装饰示例', fontsize=16)
plt.tight_layout()
plt.show()2. 背景与网格
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 子图1:网格样式
ax = axes[0, 0]
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), 'b-', linewidth=2)
ax.grid(True,
which='both', # 'major', 'minor', 'both'
axis='both', # 'x', 'y', 'both'
linestyle='--', # 线型
linewidth=0.5, # 线宽
alpha=0.7, # 透明度
color='gray') # 颜色
ax.set_title('网格样式')
# 子图2:背景颜色
ax = axes[0, 1]
ax.plot(x, np.cos(x), 'r-', linewidth=2)
ax.set_facecolor('lightyellow') # 设置背景颜色
ax.set_title('黄色背景')
# 添加网格
ax.grid(True, alpha=0.3)
# 子图3:渐变背景
ax = axes[1, 0]
ax.plot(x, np.sin(x) * np.exp(-x/10), 'g-', linewidth=2)
# 创建渐变背景
gradient = np.linspace(0, 1, 256).reshape(1, -1)
gradient = np.vstack((gradient, gradient))
ax.imshow(gradient, aspect='auto', cmap='Blues',
extent=[ax.get_xlim()[0], ax.get_xlim()[1],
ax.get_ylim()[0], ax.get_ylim()[1]],
alpha=0.3, zorder=0)
# 重新绘制曲线(在渐变之上)
ax.plot(x, np.sin(x) * np.exp(-x/10), 'g-', linewidth=2, zorder=1)
ax.set_title('渐变背景')
# 子图4:图片背景
ax = axes[1, 1]
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
# 加载背景图片(示例:使用颜色渐变代替)
from matplotlib.cbook import get_sample_data
import matplotlib.image as mpimg
# 创建示例背景
bg_data = np.random.rand(10, 10)
ax.imshow(bg_data, extent=[0, 2*np.pi, -1.2, 1.2],
aspect='auto', cmap='Greys', alpha=0.2, zorder=0)
# 绘制曲线
ax.plot(x, y, 'purple', linewidth=3, zorder=1)
ax.fill_between(x, 0, y, where=(y>0), color='purple', alpha=0.3, zorder=1)
ax.set_title('图片背景')
plt.suptitle('背景与网格装饰示例', fontsize=16)
plt.tight_layout()
plt.show()六、图例装饰
1. 图例样式
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 子图1:基本图例
ax = axes[0, 0]
x = np.linspace(0, 10, 100)
for i in range(5):
ax.plot(x, np.sin(x + i*0.5), label=f'曲线 {i+1}')
ax.legend()
ax.set_title('基本图例')
# 子图2:自定义位置和样式
ax = axes[0, 1]
for i in range(3):
ax.plot(x, np.cos(x + i*0.5), linewidth=2, label=f'cos {i+1}')
legend = ax.legend(loc='upper left', # 位置
bbox_to_anchor=(1.02, 1), # 相对于坐标轴的位置
borderaxespad=0., # 边框内边距
frameon=True, # 显示边框
fancybox=True, # 圆角边框
shadow=True, # 阴影
fontsize=12,
title='图例标题',
title_fontsize=13)
# 设置图例样式
legend.get_frame().set_facecolor('lightblue')
legend.get_frame().set_alpha(0.7)
legend.get_frame().set_edgecolor('navy')
legend.get_frame().set_linewidth(2)
ax.set_title('自定义图例样式')
# 子图3:多列图例
ax = axes[1, 0]
for i in range(8):
ax.plot(x[:50], np.random.randn(50).cumsum(), label=f'序列 {i+1}')
ax.legend(ncol=2, # 2列
loc='upper center', # 位置
bbox_to_anchor=(0.5, -0.1), # 在图外底部
fontsize=10)
ax.set_title('多列图例')
# 子图4:自定义图例项
ax = axes[1, 1]
# 创建不同类型的图形元素
line1, = ax.plot(x, np.sin(x), 'b-', label='正弦')
line2, = ax.plot(x, np.cos(x), 'r--', label='余弦')
scatter = ax.scatter(x[::10], np.tan(x[::10])/10,
c='green', s=50, label='正切点')
# 创建自定义图例
from matplotlib.lines import Line2D
# 手动创建图例句柄
custom_lines = [Line2D([0], [0], color='blue', lw=2),
Line2D([0], [0], color='red', lw=2, linestyle='--'),
Line2D([0], [0], marker='o', color='w',
markerfacecolor='green', markersize=10)]
# 创建图例
ax.legend(custom_lines, ['自定义线1', '自定义线2', '自定义点'],
loc='center',
framealpha=0.9,
edgecolor='black')
ax.set_title('自定义图例句柄')
plt.suptitle('图例装饰示例', fontsize=16)
plt.tight_layout()
plt.show()2. 高级图例技巧
fig, ax = plt.subplots(figsize=(12, 8))
# 创建多个数据系列
np.random.seed(42)
n_series = 5
n_points = 50
# 绘制多条曲线
lines = []
for i in range(n_series):
line, = ax.plot(np.arange(n_points),
np.random.randn(n_points).cumsum(),
linewidth=2,
marker='o' if i < 2 else 's', # 前2个用圆圈,后3个用方块
markersize=6 if i < 2 else 8,
markevery=5,
alpha=0.7,
label=f'系列 {i+1}')
lines.append(line)
# 1. 交互式图例(点击隐藏/显示系列)
legends = []
for i, line in enumerate(lines):
leg = ax.legend([line], [line.get_label()],
loc='upper left',
bbox_to_anchor=(1.01, 1 - i*0.15),
frameon=True,
fancybox=True,
framealpha=0.8)
# 使图例可点击
leg.get_lines()[0].set_picker(True)
leg.get_lines()[0].pickradius = 10
# 存储图例对象
legends.append(leg)
# 默认添加到ax,但后面会移除
ax.add_artist(leg)
# 移除临时图例,添加总图例
for leg in legends:
leg.remove()
# 添加一个总图例
main_legend = ax.legend(loc='upper left',
bbox_to_anchor=(1.01, 0.3),
title='数据系列',
fontsize=11)
# 2. 带符号的图例
from matplotlib.patches import Patch
# 创建符号图例
symbols_legend_elements = [
Patch(facecolor='lightblue', edgecolor='blue', label='类别 A'),
Patch(facecolor='lightgreen', edgecolor='green', label='类别 B'),
Patch(facecolor='lightcoral', edgecolor='red', label='类别 C'),
]
symbols_legend = ax.legend(handles=symbols_legend_elements,
loc='upper left',
bbox_to_anchor=(1.01, 0),
title='数据类别',
fontsize=11)
ax.add_artist(main_legend) # 重新添加主图例
# 3. 彩色图例文本
color_legend = ax.legend([], [], loc='upper left',
bbox_to_anchor=(1.01, 0.6),
title='状态说明',
frameon=False,
handlelength=0)
# 创建彩色文本
from matplotlib.patches import Rectangle
# 添加彩色方块
colors = ['green', 'yellow', 'red']
labels = ['正常', '警告', '危险']
for i, (color, label) in enumerate(zip(colors, labels)):
# 添加彩色方块
rect = Rectangle((0, 0), 1, 1, facecolor=color, edgecolor='black')
color_legend.add_patch(rect)
# 添加文本
color_legend.get_texts()[i].set_text(label)
color_legend.get_texts()[i].set_color('black')
ax.add_artist(color_legend)
# 设置图形边界
ax.set_xlim(0, n_points)
ax.set_title('高级图例装饰示例', fontsize=14, pad=20)
ax.grid(True, alpha=0.3)
# 调整布局
plt.subplots_adjust(right=0.75)
plt.show()七、综合装饰实战
# 创建专业风格的图表装饰
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
# 设置全局样式
plt.style.use('seaborn-v0_8-darkgrid')
fig.patch.set_facecolor('#F5F5F5') # 画布背景色
# 数据准备
np.random.seed(42)
x = np.linspace(0, 10, 100)
time = pd.date_range('2023-01-01', periods=100, freq='D')
# 1. 商业折线图装饰
ax1.plot(time, 100 + np.cumsum(np.random.randn(100)),
color='#2E86AB', linewidth=2.5, marker='o', markevery=10)
ax1.fill_between(time,
100 + np.cumsum(np.random.randn(100)) - 5,
100 + np.cumsum(np.random.randn(100)) + 5,
color='#2E86AB', alpha=0.2)
# 装饰
ax1.set_title('📈 股价走势分析', fontsize=14, fontweight='bold', pad=15)
ax1.set_xlabel('日期', fontsize=11)
ax1.set_ylabel('价格 (USD)', fontsize=11)
ax1.tick_params(axis='x', rotation=45)
ax1.grid(True, alpha=0.4)
# 添加注释
ax1.annotate('关键突破点',
xy=(time[60], 110),
xytext=(time[40], 120),
arrowprops=dict(arrowstyle='->',
connectionstyle='arc3,rad=0.2',
color='red',
lw=1.5),
fontsize=10,
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
# 2. 统计柱状图装饰
categories = ['科技', '金融', '医疗', '能源', '消费']
values = [35, 28, 18, 12, 7]
colors = ['#4ECDC4', '#FF6B6B', '#FFD166', '#06D6A0', '#118AB2']
errors = [2, 3, 1.5, 2.5, 1]
bars = ax2.bar(categories, values,
color=colors,
edgecolor='white',
linewidth=2,
yerr=errors,
capsize=5,
error_kw={'elinewidth': 2, 'ecolor': 'darkred'})
# 添加数值标签
for bar, value in zip(bars, values):
height = bar.get_height()
ax2.text(bar.get_x() + bar.get_width()/2., height + 1,
f'{value}%', ha='center', va='bottom',
fontsize=10, fontweight='bold',
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
# 装饰
ax2.set_title('🏢 行业市场份额分布', fontsize=14, fontweight='bold', pad=15)
ax2.set_ylabel('市场份额 (%)', fontsize=11)
ax2.set_ylim(0, 45)
ax2.grid(True, axis='y', alpha=0.3)
# 3. 科学散点图装饰
x_scatter = np.random.randn(200)
y_scatter = 0.5 * x_scatter + np.random.randn(200) * 0.5
# 按密度着色
from scipy.stats import gaussian_kde
xy = np.vstack([x_scatter, y_scatter])
z = gaussian_kde(xy)(xy)
scatter = ax3.scatter(x_scatter, y_scatter,
c=z, s=50, alpha=0.6,
cmap='viridis', edgecolor='white', linewidth=0.5)
# 添加回归线
from scipy import stats
slope, intercept, r_value, p_value, std_err = stats.linregress(x_scatter, y_scatter)
x_fit = np.array([x_scatter.min(), x_scatter.max()])
y_fit = slope * x_fit + intercept
ax3.plot(x_fit, y_fit, 'r--', linewidth=2,
label=f'y = {slope:.2f}x + {intercept:.2f}\nR² = {r_value**2:.3f}')
# 装饰
ax3.set_title('🔬 实验数据相关性分析', fontsize=14, fontweight='bold', pad=15)
ax3.set_xlabel('自变量 X', fontsize=11)
ax3.set_ylabel('因变量 Y', fontsize=11)
ax3.legend(loc='upper left', fontsize=10, framealpha=0.9)
ax3.grid(True, alpha=0.3)
plt.colorbar(scatter, ax=ax3, label='点密度')
# 4. 饼图装饰
sizes = [30, 25, 20, 15, 10]
labels = ['Python', 'Java', 'JavaScript', 'C++', '其他']
explode = (0.05, 0, 0, 0, 0)
colors_pie = ['#FF9F1C', '#E71D36', '#2EC4B6', '#011627', '#6C757D']
wedges, texts, autotexts = ax4.pie(sizes,
explode=explode,
labels=labels,
colors=colors_pie,
autopct='%1.1f%%',
startangle=90,
shadow=True,
wedgeprops=dict(edgecolor='white', linewidth=2))
# 美化百分比文本
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(10)
autotext.set_fontweight('bold')
# 美化标签文本
for text in texts:
text.set_fontsize(11)
# 添加中心圆(甜甜圈图效果)
centre_circle = plt.Circle((0,0), 0.6, fc='white')
ax4.add_patch(centre_circle)
# 装饰
ax4.set_title('💻 编程语言使用比例', fontsize=14, fontweight='bold', pad=20)
# 统一调整
for ax in [ax1, ax2, ax3, ax4]:
# 设置统一的边框样式
for spine in ax.spines.values():
spine.set_linewidth(1.5)
spine.set_color('gray')
# 设置统一的刻度样式
ax.tick_params(axis='both', which='major', labelsize=10)
# 添加总标题
fig.suptitle('数据可视化装饰综合示例',
fontsize=18, fontweight='bold', y=0.98)
# 调整布局
plt.tight_layout(rect=[0, 0, 1, 0.96])
# 添加脚注
fig.text(0.5, 0.01,
'数据来源:模拟数据 | 可视化工具:Matplotlib',
ha='center', fontsize=10, style='italic',
bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.3))
plt.show()八、实用装饰技巧
# 装饰技巧集合
fig, axes = plt.subplots(3, 3, figsize=(15, 12))
# 1. 渐变线
ax = axes[0, 0]
x = np.linspace(0, 10, 100)
y = np.sin(x)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
from matplotlib.collections import LineCollection
lc = LineCollection(segments, cmap='viridis', linewidth=3)
lc.set_array(y) # 按y值着色
ax.add_collection(lc)
ax.set_xlim(x.min(), x.max())
ax.set_ylim(y.min(), y.max())
ax.set_title('渐变线')
# 2. 填充透明度渐变
ax = axes[0, 1]
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y, 'b-')
for i in range(len(x)-1):
alpha = 0.3 * (1 - i/len(x))
ax.fill_between(x[i:i+2], 0, y[i:i+2], color='blue', alpha=alpha)
ax.set_title('渐变透明度填充')
# 3. 阴影文字
ax = axes[0, 2]
ax.axis([0, 1, 0, 1])
ax.axis('off')
for i in range(5):
size = 20 + i * 4
offset = 0.003 * size
ax.text(0.1, 0.9 - i*0.15, f'Size {size}',
fontsize=size, fontweight='bold',
color='white',
path_effects=[patheffects.withSimplePatchShadow(
offset=(offset, -offset), shadow_color='gray',
alpha=0.7)])
ax.set_title('阴影文字效果')
# 4. 高亮区域
ax = axes[1, 0]
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y, 'b-')
ax.axvspan(3, 5, alpha=0.3, color='yellow', label='关键区域')
ax.axvspan(7, 9, alpha=0.3, color='red')
ax.set_title('高亮区域')
# 5. 箭头标注
ax = axes[1, 1]
x = np.linspace(0, 10, 100)
y = np.exp(-x/5) * np.sin(x)
ax.plot(x, y, 'g-')
ax.annotate('局部最大值', xy=(x[20], y[20]),
xytext=(x[20]+1, y[20]+0.1),
arrowprops=dict(arrowstyle='fancy',
facecolor='red',
connectionstyle='arc3,rad=0.3'),
fontsize=10,
bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.8))
ax.set_title('箭头标注')
# 6. 自定义刻度
ax = axes[1, 2]
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
ax.set_xticks([0, np.pi, 2*np.pi, 3*np.pi])
ax.set_xticklabels(['0', 'π', '2π', '3π'], fontsize=12)
ax.set_yticks([-1, 0, 1])
ax.set_yticklabels(['最小', '零', '最大'], fontsize=12)
ax.set_title('自定义刻度标签')
# 7. 多Y轴
ax = axes[2, 0]
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), 'b-', label='sin(x)')
ax.set_ylabel('sin(x)', color='blue')
ax2 = ax.twinx()
ax2.plot(x, x**2, 'r--', label='x²')
ax2.set_ylabel('x²', color='red')
ax.set_title('多Y轴图表')
# 8. 极坐标装饰
ax = axes[2, 1]
ax = plt.subplot(3, 3, 8, projection='polar')
theta = np.linspace(0, 2*np.pi, 100)
r = 1 + 0.5 * np.cos(5*theta)
ax.plot(theta, r, 'purple', linewidth=2)
ax.fill(theta, r, 'purple', alpha=0.3)
ax.set_title('极坐标装饰', pad=20)
# 9. 3D装饰
from mpl_toolkits.mplot3d import Axes3D
ax = axes[2, 2]
ax.remove()
ax = fig.add_subplot(3, 3, 9, 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))
ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
ax.set_title('3D曲面装饰')
plt.suptitle('实用装饰技巧大全', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()装饰最佳实践
- 保持一致性:同一图表中,相似元素使用相同样式
- 突出重点:使用颜色、大小、透明度突出关键信息
- 适度装饰:装饰服务于内容,不要过度装饰
- 考虑色盲:避免红绿搭配,使用颜色盲友好调色板
- 测试输出:在不同设备、不同尺寸下测试显示效果
- 性能优化:复杂装饰可能影响渲染性能,适时优化
通过合理使用这些装饰技巧,可以让你的图表更具表现力和专业性。
