📈 章节概览
线图是展示连续数据变化趋势的最佳工具。本章系统讲解线图的12种高级技法, 包括颗粒度控制、阶跃图、火柴梗图、参考线、面具、交点标注、极值标记、 色谱着色、分段渲染、网格绘制,以及用线条创作生成艺术。
📊
基础技法
颗粒度、阶跃、火柴梗
🎯
增强标注
参考线、交点、极值
🎨
视觉编码
面具、色谱、分段渲染
✨
生成艺术
网格、三角形、创意线条
8.1 平面线图颗粒度
控制采样密度,理解Nyquist-Shannon采样定理
📊 线图颗粒度实验室(Line Granularity Lab)
通过调整采样点数,理解颗粒度对曲线平滑度的影响
🧪 探索建议
- • 拖动滑块改变采样点数,观察曲线变化
- • 点数太少→曲线失真;点数太多→计算冗余
- • 切换函数类型,体验不同函数的采样需求
- • 开启"显示点"查看实际采样位置
✅
颗粒度评分: 100/100
当前: 50点 × sin函数
✅ 采样点数适中,曲线平滑
50
粗糙(5)平滑(200)
线条粗细2px
⚡ 性能考量
当前数据点: 50
计算复杂度: O(n)
渲染元素: 1
📚 采样理论(Sampling Theory)
Nyquist-Shannon 采样定理
要完整还原信号,采样率必须至少是信号最高频率的2倍。 对于正弦波 sin(x),理论上每周期至少需要2个点,但实际需要更多以保证平滑。
采样点数建议
- • 简单函数(如sin、cos):30-50点
- • 中等复杂度:50-100点
- • 快速变化/尖锐:100-200点
- • 平滑艺术曲线:200+点
欠采样问题
采样点太少会导致锯齿状曲线、失真、 甚至混叠(Aliasing)——高频信号被错误地表示为低频。
过采样权衡
采样点过多虽然曲线更平滑,但会:
- • 增加计算时间
- • 占用更多内存
- • 文件体积变大
🎯 学习目标:通过动手调整采样点数,建立"采样率→曲线质量"的直觉。 理解采样定理的实际意义,学会为不同函数选择合适的颗粒度。
📚 Python绘图代码(基于Ch08原文)
# ===== 示例1:线图颗粒度对比 =====
import matplotlib.pyplot as plt
import numpy as np
# 低颗粒度:9个点
x_low = np.linspace(0, 4*np.pi, 9)
y_low = np.sin(x_low)
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_low, y_low, '.--', ms=10, color='#0088FF')
ax.set_xlim((0, 4*np.pi))
ax.set_ylim((-1.2, 1.2))
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
plt.show()
# 合理颗粒度:101个点
x_fine = np.linspace(0, 4*np.pi, 101)
y_fine = np.sin(x_fine)
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_fine, y_fine, color='#0088FF') # 平滑曲线
ax.set_xlim((0, 4*np.pi))
ax.set_ylim((-1.2, 1.2))
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
plt.show()
# ===== 示例2:阶跃图(step函数) =====
x_coarse = np.linspace(0, 4*np.pi, 25)
y_coarse = np.sin(x_coarse)
x_reference = np.linspace(0, 4*np.pi, 101)
y_reference = np.sin(x_reference)
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_reference, y_reference, '--', color='#888888') # 参考线
plt.step(x_coarse, y_coarse, '.-', ms=10, color='#0088FF') # 阶跃
# where参数:'pre'(向前填充), 'mid'(中间), 'post'(向后填充)
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
plt.show()
# ===== 示例3:火柴梗图(stem函数) =====
# 绘制等差数列
n_array = np.arange(1, 21)
a_n = 1 + (n_array - 1) * 2 # 首项1,公差2
fig, ax = plt.subplots(figsize=(5, 3))
plt.stem(n_array, a_n)
ax.set_xlabel('$n$')
ax.set_ylabel('n-th term, $a_n$')
plt.show()
# 绘制二项分布PMF
from scipy.stats import binom
k_array = np.arange(0, 21)
pmf = binom.pmf(k_array, n=20, p=0.4)
plt.stem(k_array, pmf)
plt.xlabel('$x$')
plt.ylabel('PMF, $f_X(x)$')
plt.show()
# 💡 关键学习点:
# 1. linspace()控制采样点数:点数越多,曲线越平滑
# 2. plot()样式:'.-'点+虚线,'.--'点+虚线,纯线条
# 3. step()绘制阶跃图:where参数控制填充方向
# 4. stem()绘制火柴梗图:适合离散数据(数列、PMF)8.2 阶跃函数:plt.step() 绘制离散值
理解三种阶跃模式的差异
• 在中点转折
Python代码:
import matplotlib.pyplot as plt
import numpy as np
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([1, 3, 2, 5, 4, 6])
# where参数控制阶跃方式
plt.step(x, y, where='mid', linewidth=2, color='blue')
plt.scatter(x, y, c='red', s=50, zorder=5)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Step Function (where="mid")')
plt.grid(alpha=0.3)
plt.show()💡 阶跃函数的应用:
• pre:数字信号处理中常用,值在下一个采样点前保持
• mid:直方图绘制,在区间中点转换
• post:控制系统中,输出在输入改变后立即响应
• 适合展示离散时间序列、数字信号、分段常数函数
• pre:数字信号处理中常用,值在下一个采样点前保持
• mid:直方图绘制,在区间中点转换
• post:控制系统中,输出在输入改变后立即响应
• 适合展示离散时间序列、数字信号、分段常数函数
8.3 火柴梗图:plt.stem() 展示离散数据
突出显示每个数据点的幅度
Python代码:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 21)
y = np.sin(x * 0.5) * 3 + 3
# 绘制火柴梗图
plt.stem(x, y,
linefmt='purple', # 茎的样式
markerfmt='o', # 标记样式
basefmt='orange') # 基线样式
plt.xlabel('Sample Index')
plt.ylabel('Amplitude')
plt.title('Stem Plot - Sine Wave')
plt.grid(alpha=0.3)
plt.show()💡 火柴梗图的应用:
• 数字信号:展示离散时间信号的幅度
• 频谱分析:显示频率成分的强度
• 脉冲响应:系统对脉冲输入的响应
• 采样数据:突出每个采样点的值
• 相比普通线图,更强调数据的离散性
• 数字信号:展示离散时间信号的幅度
• 频谱分析:显示频率成分的强度
• 脉冲响应:系统对脉冲输入的响应
• 采样数据:突出每个采样点的值
• 相比普通线图,更强调数据的离散性
8.4 参考线:axhline / axvline 标记关键值
添加水平和垂直参考线辅助分析
06
010
Python代码:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = 2 + 2*np.sin(x*0.8) + np.cos(x*0.3)
# 绘制曲线
plt.plot(x, y, 'b-', linewidth=2.5, label='f(x)')
# 添加水平参考线
plt.axhline(y=3.0, color='hotpink',
linestyle='--', linewidth=2, label='y=3.0')
# 添加垂直参考线
plt.axvline(x=5.0, color='crimson',
linestyle='--', linewidth=2, label='x=5.0')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(alpha=0.3)
plt.show()💡 参考线的应用:
• 阈值标记:标出警戒线、目标值、平均值
• 区间划分:将数据分为不同区域
• 关键时刻:标记重要时间点或事件
• 比较基准:提供对比的参考标准
• 拖动滑块调整参考线位置,观察与曲线的关系
• 阈值标记:标出警戒线、目标值、平均值
• 区间划分:将数据分为不同区域
• 关键时刻:标记重要时间点或事件
• 比较基准:提供对比的参考标准
• 拖动滑块调整参考线位置,观察与曲线的关系
8.5 使用面具mask:选择性显示数据
根据条件筛选和突出显示特定数据段
15
显示 y > 3.0 的数据段
总数据点
101
符合条件的点
74
数据段数
2
Python代码:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
y = 3 + 2*np.sin(x*0.6)*np.cos(x*0.2)
# 创建mask
mask = y > 3.0
# 绘制完整曲线(灰色)
plt.plot(x, y, 'lightgray', linewidth=1.5, label='All data')
# 仅绘制满足条件的部分(红色高亮)
plt.plot(x[mask], y[mask], 'r-', linewidth=3, label='Masked data')
# 添加阈值线或区间
plt.axhline(3.0, color='red', linestyle='--', linewidth=2)
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()💡 Mask的应用:
• 异常检测:突出显示超出正常范围的数据
• 条件筛选:仅展示符合特定条件的数据段
• 数据清洗:过滤噪声或无效数据
• 区间分析:关注特定值域内的变化
• NumPy mask是强大的数组操作工具
• 异常检测:突出显示超出正常范围的数据
• 条件筛选:仅展示符合特定条件的数据段
• 数据清洗:过滤噪声或无效数据
• 区间分析:关注特定值域内的变化
• NumPy mask是强大的数组操作工具
8.6 交点标注:找出两条曲线的交叉位置
计算并标注曲线交点,辅助数据分析
-12
找到 3 个交点
交点坐标:
P1: (0.983, 3.415)
P2: (3.436, 2.764)
P3: (8.691, 3.241)
Python代码:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
y1 = 2 + 2*np.sin(x*0.8)
y2 = 3 + 0.50*np.cos(x*0.6)
# 绘制两条曲线
plt.plot(x, y1, 'b-', linewidth=2.5, label='f(x)')
plt.plot(x, y2, 'g-', linewidth=2.5, label='g(x)')
# 找交点(符号变化法)
idx = np.where(np.diff(np.sign(y1 - y2)))[0]
# 标注交点
for i in idx:
# 线性插值
x_cross = x[i] + (x[i+1]-x[i])*(0-(y1[i]-y2[i]))/((y1[i+1]-y2[i+1])-(y1[i]-y2[i]))
y_cross = np.interp(x_cross, x, y1)
plt.plot(x_cross, y_cross, 'ro', markersize=8)
plt.annotate(f'({x_cross:.2f}, {y_cross:.2f})',
xy=(x_cross, y_cross),
xytext=(10, 10), textcoords='offset points')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(alpha=0.3)
plt.show()💡 交点分析的应用:
• 经济学:供需平衡点、盈亏平衡点
• 物理学:运动轨迹交叉、波的干涉
• 工程学:系统响应的临界点
• 金融学:均线交叉信号(金叉/死叉)
• 拖动滑块改变曲线形状,观察交点如何移动
• 经济学:供需平衡点、盈亏平衡点
• 物理学:运动轨迹交叉、波的干涉
• 工程学:系统响应的临界点
• 金融学:均线交叉信号(金叉/死叉)
• 拖动滑块改变曲线形状,观察交点如何移动
8.11-8.12 生成艺术:用线条创作几何艺术
观察算法驱动的艺术创作过程,理解参数化设计
✨ 生成艺术动画器(Generative Art Animator)
观察线条逐步生成几何艺术的动态过程
步骤: 0 / 20
🔺 三角形
速度1x
线条数量20
🎨 观察要点
- • 注意每条线的生成位置和角度
- • 观察颜色如何随步骤变化(色相渐变)
- • 暂停后可以仔细查看中间状态
- • 不同模式展示不同的数学规律
🎭 艺术模式
📊 生成统计
已绘制线条0
完成度0%
当前颜色
📐 数学原理
等边三角形:三个顶点相隔120°, 通过旋转角度θ和递增半径r创造螺旋效果。
🎨 生成艺术技巧
- • 色彩渐变:使用HSL色相循环
- • 几何规律:基于数学公式
- • 分层叠加:透明度0.8产生混色
- • 对称美感:中心对称设计
📚 生成艺术(Generative Art)
🎲
算法驱动
通过代码和数学公式自动生成艺术作品,而非手工绘制
🔄
随机性与确定性
结合数学规律和随机元素,每次运行产生独特作品
✨
参数化设计
调整参数即可创造无限变化的视觉效果
🎯 应用领域
• NFT数字艺术作品
• 数据可视化美化
• 建筑设计参数化
• 品牌视觉识别系统
• 游戏程序化生成
• 交互装置艺术
📚 Python绘图代码(基于Ch08原文)
# ===== 示例4:参考线(axhline/axvline) =====
import matplotlib.pyplot as plt
import numpy as np
x_array = np.linspace(0, 4*np.pi, 101)
y_array = np.sin(x_array)
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_array, y_array, color='#0088FF')
# 水平参考线
plt.axhline(y=1, color='r', ls='--')
plt.axhline(y=0, color='r', ls='--')
plt.axhline(y=-1, color='r', ls='--')
# 竖直参考线
plt.axvline(x=np.pi, color='r', ls='--')
plt.axvline(x=2*np.pi, color='r', ls='--')
plt.axvline(x=3*np.pi, color='r', ls='--')
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
plt.show()
# ===== 示例5:填充区域(fill_between) =====
# 填充曲线下方区域
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_array, y_array, color='#0088FF', linewidth=2)
plt.fill_between(x_array, y_array, 0,
where=(y_array > 0),
color='#0088FF',
alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
plt.show()
# ===== 示例6:多条曲线填充 =====
y1 = np.sin(x_array)
y2 = np.sin(2*x_array) * 0.5
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_array, y1, color='#0088FF', label='sin(x)')
plt.plot(x_array, y2, color='#FF6B00', label='0.5·sin(2x)')
# 填充两曲线之间区域
plt.fill_between(x_array, y1, y2,
where=(y1 >= y2),
color='#0088FF',
alpha=0.2)
plt.fill_between(x_array, y1, y2,
where=(y1 < y2),
color='#FF6B00',
alpha=0.2)
plt.legend()
plt.show()
# ===== 示例7:指定范围的参考线(hlines/vlines) =====
fig, ax = plt.subplots(figsize=(5, 3))
plt.plot(x_array, y_array, color='#0088FF')
# 指定范围的水平线
ax.hlines(y=1, xmin=np.pi/2-1, xmax=np.pi/2+1,
linewidth=2, color='r', ls='--')
ax.hlines(y=-1, xmin=3*np.pi/2-1, xmax=3*np.pi/2+1,
linewidth=2, color='r', ls='--')
# 指定范围的竖直线
ax.vlines(x=np.pi, ymin=-0.5, ymax=0.5,
linewidth=2, color='g', ls=':')
plt.show()
# 💡 关键学习点:
# 1. axhline()/axvline():绘制贯穿全图的参考线
# 2. hlines()/vlines():绘制指定范围的参考线
# 3. fill_between():填充曲线下方或两曲线之间区域
# 4. where参数:条件填充,只填充满足条件的部分📚 章节总结
基础线图技法
- ✓ 颗粒度控制:调整采样点数
- ✓ 阶跃图:离散值的连续展示
- ✓ 火柴梗图:突出每个数据点
- ✓ 参考线:标记关键值
高级标注技法
- ✓ 面具选择:条件筛选数据
- ✓ 交点标注:曲线交叉点
- ✓ 极值标记:最大/最小值
- ✓ 色谱编码:多曲线区分
艺术创作
- ✓ 分段渲染:不同区间不同样式
- ✓ 网格绘制:规则图案
- ✓ 几何艺术:三角形生成
- ✓ 生成艺术:创意线条作品
💡 核心洞察: 线图不仅是数据可视化工具,更是艺术创作媒介。通过12种技法的组合运用, 可以创造出既科学严谨又视觉震撼的作品。从函数可视化到生成艺术, 线图展现了数学与美学的完美结合。
💻关键函数速查表
基础绘图
plt.plot(x, y, linewidth, linestyle, color)
plt.step(x, y, where='pre'|'post'|'mid')
plt.stem(x, y, linefmt, markerfmt, basefmt)
标注增强
plt.axhline(y, color, linestyle, linewidth)
plt.axvline(x, color, linestyle, linewidth)
plt.annotate(text, xy, xytext, arrowprops)
高级技法
mask = (condition)
y[mask] = value
y[mask] = value
cmap = plt.get_cmap('viridis')
colors = cmap(np.linspace(0, 1, n))
colors = cmap(np.linspace(0, 1, n))
📂Python代码文件
本章内容对应以下Jupyter Notebook代码文件:
BK_2_Ch08_01.ipynb小节 8.1BK_2_Ch08_02.ipynb小节 8.2BK_2_Ch08_03.ipynb小节 8.3BK_2_Ch08_04.ipynb小节 8.4BK_2_Ch08_05.ipynb小节 8.5BK_2_Ch08_06.ipynb小节 8.6BK_2_Ch08_07.ipynb小节 8.7BK_2_Ch08_08.ipynb小节 8.8BK_2_Ch08_09.ipynb小节 8.9BK_2_Ch08_10.ipynb小节 8.10BK_2_Ch08_11.ipynb小节 8.11BK_2_Ch08_12.ipynb小节 8.12📁 代码位置:
books/Book2_Beauty-of-Data-Visualization/Book2_Ch08_Python_Codes/🎯线图应用场景
📈
时间序列
股票价格、气温变化、网站流量等随时间变化的数据
📐
函数可视化
数学函数、物理曲线、工程模拟结果的图形展示
🔬
科学实验
实验测量数据、传感器读数、信号处理结果
💹
趋势分析
市场趋势、用户增长、性能指标的变化趋势
🎨
生成艺术
算法艺术、几何图案、参数化设计作品
🔄
比较分析
多条曲线对比、AB测试结果、模型性能比较