Python数据可视化:matplotlib画波形图和频谱图,FPGA调试的好帮手
数据可视化是分析和展示数据的重要手段。在FPGA开发中,可视化常用于波形显示、频谱分析、时序图绘制等场景。本篇介绍matplotlib的基本使用。
1. matplotlib简介
pip install matplotlib
import matplotlib.pyplot as plt
import numpy as np
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 设置默认图像大小和DPI
plt.rcParams['figure.figsize'] = [10, 6]
plt.rcParams['figure.dpi'] = 100
# 简单示例
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title('正弦波')
plt.xlabel('x')
plt.ylabel('sin(x)')
plt.show()
2. 基本绑图
import matplotlib.pyplot as plt
import numpy as np
# 创建数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 方式1:快速绑图
plt.plot(x, y1)
plt.show()
# 方式2:面向对象方式(推荐)
fig, ax = plt.subplots()
ax.plot(x, y1, label='sin(x)')
ax.plot(x, y2, label='cos(x)')
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_title('三角函数')
ax.legend()
ax.grid(True)
plt.show()
# 线条样式
plt.plot(x, y1, 'r-', linewidth=2, label='红色实线')
plt.plot(x, y2, 'b--', linewidth=1.5, label='蓝色虚线')
plt.plot(x, y1+y2, 'g:', label='绿色点线')
plt.plot(x, y1-y2, 'm-.', label='品红点划线')
plt.legend()
plt.show()
# 标记样式
plt.plot(x[::10], y1[::10], 'ro', markersize=8, label='圆点')
plt.plot(x[::10], y2[::10], 'bs', markersize=6, label='方块')
plt.plot(x[::10], (y1+y2)[::10], 'g^', markersize=6, label='三角')
plt.legend()
plt.show()
# 常用颜色:r红 g绿 b蓝 c青 m品红 y黄 k黑 w白
# 常用线型:- 实线 -- 虚线 : 点线 -. 点划线
# 常用标记:o圆 s方 ^三角 *星 +加 x叉 d菱形
# 保存图像
fig, ax = plt.subplots()
ax.plot(x, y1)
fig.savefig('plot.png', dpi=150, bbox_inches='tight')
fig.savefig('plot.pdf') # 矢量图
fig.savefig('plot.svg') # SVG格式
plt.close(fig)
3. 图表类型
import matplotlib.pyplot as plt
import numpy as np
# 散点图
x = np.random.randn(100)
y = np.random.randn(100)
colors = np.random.rand(100)
sizes = np.random.rand(100) * 500
plt.scatter(x, y, c=colors, s=sizes, alpha=0.5, cmap='viridis')
plt.colorbar()
plt.title('散点图')
plt.show()
# 柱状图
categories = ['A', 'B', 'C', 'D', 'E']
values = [23, 45, 56, 78, 32]
plt.bar(categories, values, color='steelblue', edgecolor='black')
plt.title('柱状图')
plt.ylabel('数值')
plt.show()
# 分组柱状图
x = np.arange(5)
width = 0.35
values1 = [20, 35, 30, 35, 27]
values2 = [25, 32, 34, 20, 25]
fig, ax = plt.subplots()
ax.bar(x - width/2, values1, width, label='组1')
ax.bar(x + width/2, values2, width, label='组2')
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.legend()
plt.show()
# 直方图
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, alpha=0.7, color='steelblue', edgecolor='black')
plt.title('直方图')
plt.xlabel('值')
plt.ylabel('频率')
plt.show()
# 饼图
sizes = [30, 25, 20, 15, 10]
labels = ['A', 'B', 'C', 'D', 'E']
explode = (0.1, 0, 0, 0, 0) # 突出第一块
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)
plt.title('饼图')
plt.axis('equal')
plt.show()
# 箱线图
data = [np.random.randn(100) for _ in range(4)]
plt.boxplot(data, labels=['A', 'B', 'C', 'D'])
plt.title('箱线图')
plt.show()
# 热力图
data = np.random.rand(10, 10)
plt.imshow(data, cmap='hot', interpolation='nearest')
plt.colorbar()
plt.title('热力图')
plt.show()
# 等高线图
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
plt.contour(X, Y, Z, levels=20, cmap='RdYlBu')
plt.colorbar()
plt.title('等高线图')
plt.show()
# 填充等高线
plt.contourf(X, Y, Z, levels=20, cmap='RdYlBu')
plt.colorbar()
plt.title('填充等高线图')
plt.show()
4. 图表美化
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(10, 6))
# 绑制曲线
ax.plot(x, y, 'b-', linewidth=2, label='sin(x)')
# 标题和标签
ax.set_title('正弦波形', fontsize=16, fontweight='bold')
ax.set_xlabel('时间 (s)', fontsize=12)
ax.set_ylabel('幅度 (V)', fontsize=12)
# 坐标轴范围
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
# 刻度
ax.set_xticks(np.arange(0, 11, 2))
ax.set_yticks(np.arange(-1.5, 2, 0.5))
# 网格
ax.grid(True, linestyle='--', alpha=0.7)
# 图例
ax.legend(loc='upper right', fontsize=10)
# 添加文本注释
ax.annotate('最大值', xy=(np.pi/2, 1), xytext=(2, 1.2),
arrowprops=dict(arrowstyle='->', color='red'),
fontsize=10, color='red')
# 添加水平/垂直线
ax.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
ax.axvline(x=np.pi, color='r', linestyle='--', linewidth=1, label='π')
# 填充区域
ax.fill_between(x, y, 0, where=(y > 0), alpha=0.3, color='green')
ax.fill_between(x, y, 0, where=(y < 0), alpha=0.3, color='red')
# 边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
# 使用样式
print(plt.style.available) # 查看可用样式
with plt.style.context('seaborn-v0_8-darkgrid'):
plt.plot(x, y)
plt.title('使用seaborn样式')
plt.show()
5. 子图布局
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
# 方式1:subplot
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.plot(x, np.sin(x))
plt.title('sin(x)')
plt.subplot(2, 2, 2)
plt.plot(x, np.cos(x))
plt.title('cos(x)')
plt.subplot(2, 2, 3)
plt.plot(x, np.tan(x))
plt.title('tan(x)')
plt.ylim(-5, 5)
plt.subplot(2, 2, 4)
plt.plot(x, np.exp(-x/5) * np.sin(x))
plt.title('衰减正弦')
plt.tight_layout()
plt.show()
# 方式2:subplots(推荐)
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title('sin(x)')
axes[0, 1].plot(x, np.cos(x))
axes[0, 1].set_title('cos(x)')
axes[1, 0].plot(x, np.tan(x))
axes[1, 0].set_title('tan(x)')
axes[1, 0].set_ylim(-5, 5)
axes[1, 1].plot(x, np.exp(-x/5) * np.sin(x))
axes[1, 1].set_title('衰减正弦')
plt.tight_layout()
plt.show()
# 方式3:GridSpec(灵活布局)
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 8))
gs = GridSpec(3, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, :]) # 第一行,跨所有列
ax1.plot(x, np.sin(x))
ax1.set_title('跨列')
ax2 = fig.add_subplot(gs[1:, 0]) # 第2-3行,第一列
ax2.plot(x, np.cos(x))
ax2.set_title('跨行')
ax3 = fig.add_subplot(gs[1, 1:]) # 第二行,第2-3列
ax3.plot(x, np.tan(x))
ax3.set_ylim(-5, 5)
ax4 = fig.add_subplot(gs[2, 1])
ax4.plot(x, x**2)
ax5 = fig.add_subplot(gs[2, 2])
ax5.plot(x, np.sqrt(x))
plt.tight_layout()
plt.show()
# 共享坐标轴
fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
axes[0].plot(x, np.sin(x))
axes[0].set_ylabel('sin(x)')
axes[1].plot(x, np.cos(x))
axes[1].set_ylabel('cos(x)')
axes[1].set_xlabel('x')
plt.tight_layout()
plt.show()
6. 波形显示
import matplotlib.pyplot as plt
import numpy as np
def plot_waveform(time, signal, title='波形', xlabel='时间', ylabel='幅度'):
"""绑制波形"""
fig, ax = plt.subplots(figsize=(12, 4))
ax.plot(time, signal, 'b-', linewidth=0.5)
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.grid(True, alpha=0.3)
plt.tight_layout()
return fig, ax
def plot_digital_waveform(time, signals, names):
"""绑制数字波形(时序图)"""
n_signals = len(signals)
fig, axes = plt.subplots(n_signals, 1, figsize=(12, 2*n_signals), sharex=True)
if n_signals == 1:
axes = [axes]
for i, (signal, name) in enumerate(zip(signals, names)):
axes[i].step(time, signal, 'b-', where='post', linewidth=1.5)
axes[i].set_ylabel(name)
axes[i].set_ylim(-0.2, 1.2)
axes[i].set_yticks([0, 1])
axes[i].grid(True, axis='x', alpha=0.3)
axes[i].fill_between(time, signal, step='post', alpha=0.3)
axes[-1].set_xlabel('时间')
plt.tight_layout()
return fig, axes
# 示例:模拟波形
fs = 10000 # 采样率
t = np.arange(0, 0.1, 1/fs)
signal = np.sin(2*np.pi*100*t) + 0.5*np.sin(2*np.pi*200*t)
signal += 0.1 * np.random.randn(len(t))
plot_waveform(t*1000, signal, '模拟信号', '时间 (ms)', '电压 (V)')
plt.show()
# 示例:数字波形
t = np.arange(0, 100, 1)
clk = (t % 2).astype(int)
data = np.random.randint(0, 2, len(t))
enable = np.zeros(len(t), dtype=int)
enable[20:80] = 1
plot_digital_waveform(t, [clk, data, enable], ['CLK', 'DATA', 'EN'])
plt.show()
# 双Y轴
fig, ax1 = plt.subplots(figsize=(10, 5))
t = np.linspace(0, 10, 1000)
signal1 = np.sin(2*np.pi*0.5*t)
signal2 = 100 * np.cos(2*np.pi*0.3*t) + 500
ax1.plot(t, signal1, 'b-', label='信号1')
ax1.set_xlabel('时间 (s)')
ax1.set_ylabel('信号1 (V)', color='b')
ax1.tick_params(axis='y', labelcolor='b')
ax2 = ax1.twinx()
ax2.plot(t, signal2, 'r-', label='信号2')
ax2.set_ylabel('信号2 (mV)', color='r')
ax2.tick_params(axis='y', labelcolor='r')
fig.legend(loc='upper right', bbox_to_anchor=(0.9, 0.9))
plt.title('双Y轴波形')
plt.tight_layout()
plt.show()
7. 频谱分析图
import matplotlib.pyplot as plt
import numpy as np
def plot_spectrum(signal, fs, title='频谱'):
"""绑制频谱图"""
n = len(signal)
fft_result = np.fft.fft(signal)
freq = np.fft.fftfreq(n, 1/fs)
# 只取正频率
positive_freq = freq[:n//2]
magnitude = np.abs(fft_result[:n//2]) * 2 / n
magnitude_db = 20 * np.log10(magnitude + 1e-10)
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
# 线性幅度
axes[0].plot(positive_freq, magnitude, 'b-')
axes[0].set_xlabel('频率 (Hz)')
axes[0].set_ylabel('幅度')
axes[0].set_title(f'{title} - 线性')
axes[0].grid(True, alpha=0.3)
# dB幅度
axes[1].plot(positive_freq, magnitude_db, 'b-')
axes[1].set_xlabel('频率 (Hz)')
axes[1].set_ylabel('幅度 (dB)')
axes[1].set_title(f'{title} - 对数')
axes[1].grid(True, alpha=0.3)
axes[1].set_ylim(bottom=-80)
plt.tight_layout()
return fig, axes
def plot_spectrogram(signal, fs, title='频谱图'):
"""绑制时频图(频谱图)"""
fig, ax = plt.subplots(figsize=(12, 6))
Pxx, freqs, bins, im = ax.specgram(signal, NFFT=256, Fs=fs,
noverlap=128, cmap='viridis')
ax.set_xlabel('时间 (s)')
ax.set_ylabel('频率 (Hz)')
ax.set_title(title)
cbar = fig.colorbar(im, ax=ax)
cbar.set_label('功率 (dB)')
plt.tight_layout()
return fig, ax
# 示例
fs = 10000
t = np.arange(0, 1, 1/fs)
# 单频信号
signal1 = np.sin(2*np.pi*1000*t)
plot_spectrum(signal1, fs, '1kHz正弦波频谱')
plt.show()
# 多频信号
signal2 = np.sin(2*np.pi*500*t) + 0.5*np.sin(2*np.pi*1500*t) + 0.3*np.sin(2*np.pi*2500*t)
plot_spectrum(signal2, fs, '多频信号频谱')
plt.show()
# 扫频信号
f0, f1 = 100, 2000
signal3 = np.sin(2*np.pi*(f0 + (f1-f0)*t/2)*t)
plot_spectrogram(signal3, fs, '扫频信号时频图')
plt.show()
# 综合显示
def plot_signal_analysis(signal, fs, title='信号分析'):
"""综合信号分析图"""
n = len(signal)
t = np.arange(n) / fs
# FFT
fft_result = np.fft.fft(signal)
freq = np.fft.fftfreq(n, 1/fs)[:n//2]
magnitude = np.abs(fft_result[:n//2]) * 2 / n
fig = plt.figure(figsize=(14, 10))
# 时域波形
ax1 = fig.add_subplot(3, 1, 1)
ax1.plot(t*1000, signal, 'b-', linewidth=0.5)
ax1.set_xlabel('时间 (ms)')
ax1.set_ylabel('幅度')
ax1.set_title(f'{title} - 时域')
ax1.grid(True, alpha=0.3)
# 频谱
ax2 = fig.add_subplot(3, 1, 2)
ax2.plot(freq, magnitude, 'b-')
ax2.set_xlabel('频率 (Hz)')
ax2.set_ylabel('幅度')
ax2.set_title(f'{title} - 频域')
ax2.grid(True, alpha=0.3)
# 时频图
ax3 = fig.add_subplot(3, 1, 3)
ax3.specgram(signal, NFFT=256, Fs=fs, noverlap=128, cmap='viridis')
ax3.set_xlabel('时间 (s)')
ax3.set_ylabel('频率 (Hz)')
ax3.set_title(f'{title} - 时频')
plt.tight_layout()
return fig
# 测试
signal = np.sin(2*np.pi*500*t) + 0.5*np.sin(2*np.pi*1200*t)
signal += 0.1 * np.random.randn(len(t))
plot_signal_analysis(signal, fs, '测试信号')
plt.show()
8. 实时绑图
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
import time
# 方式1:使用动画
def realtime_plot_animation():
"""使用FuncAnimation实现实时绑图"""
fig, ax = plt.subplots()
line, = ax.plot([], [], 'b-')
ax.set_xlim(0, 100)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel('采样点')
ax.set_ylabel('幅度')
ax.set_title('实时波形')
ax.grid(True)
xdata, ydata = [], []
def init():
line.set_data([], [])
return line,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame * 0.1) + 0.1 * np.random.randn())
# 保持窗口大小
if len(xdata) > 100:
xdata.pop(0)
ydata.pop(0)
ax.set_xlim(xdata[0], xdata[-1])
line.set_data(xdata, ydata)
return line,
ani = FuncAnimation(fig, update, frames=range(500),
init_func=init, blit=True, interval=50)
plt.show()
# 方式2:交互模式
def realtime_plot_interactive():
"""使用交互模式实现实时绑图"""
plt.ion() # 开启交互模式
fig, ax = plt.subplots()
line, = ax.plot([], [], 'b-')
ax.set_xlim(0, 100)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel('采样点')
ax.set_ylabel('幅度')
ax.grid(True)
xdata, ydata = [], []
for i in range(200):
xdata.append(i)
ydata.append(np.sin(i * 0.1) + 0.1 * np.random.randn())
if len(xdata) > 100:
xdata.pop(0)
ydata.pop(0)
ax.set_xlim(xdata[0], xdata[-1])
line.set_data(xdata, ydata)
fig.canvas.draw()
fig.canvas.flush_events()
time.sleep(0.05)
plt.ioff()
plt.show()
# 方式3:使用blitting(更高效)
class RealtimePlotter:
"""高效实时绑图器"""
def __init__(self, max_points=1000):
self.max_points = max_points
self.fig, self.ax = plt.subplots()
self.line, = self.ax.plot([], [], 'b-', animated=True)
self.ax.set_xlim(0, max_points)
self.ax.set_ylim(-2, 2)
self.ax.grid(True)
self.xdata = np.arange(max_points)
self.ydata = np.zeros(max_points)
self.idx = 0
self.fig.canvas.draw()
self.background = self.fig.canvas.copy_from_bbox(self.ax.bbox)
def update(self, new_value):
self.ydata[self.idx % self.max_points] = new_value
self.idx += 1
# 滚动显示
if self.idx >= self.max_points:
display_data = np.roll(self.ydata, -self.idx % self.max_points)
else:
display_data = self.ydata
self.fig.canvas.restore_region(self.background)
self.line.set_data(self.xdata, display_data)
self.ax.draw_artist(self.line)
self.fig.canvas.blit(self.ax.bbox)
self.fig.canvas.flush_events()
# realtime_plot_animation()
9. 实战案例
案例:FPGA信号分析可视化工具
"""
实战案例:FPGA信号分析可视化工具
"""
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Button, Slider
from dataclasses import dataclass
from typing import Optional
@dataclass
class SignalData:
"""信号数据"""
time: np.ndarray
voltage: np.ndarray
sample_rate: float
name: str = "Signal"
class SignalViewer:
"""信号查看器"""
def __init__(self):
self.fig = None
self.axes = None
self.signals = []
def add_signal(self, signal: SignalData):
"""添加信号"""
self.signals.append(signal)
def plot_time_domain(self, ax, signal: SignalData):
"""绑制时域波形"""
ax.clear()
ax.plot(signal.time * 1000, signal.voltage, 'b-', linewidth=0.5)
ax.set_xlabel('时间 (ms)')
ax.set_ylabel('电压 (V)')
ax.set_title(f'{signal.name} - 时域')
ax.grid(True, alpha=0.3)
# 添加统计信息
stats = f'Min: {signal.voltage.min():.3f}V Max: {signal.voltage.max():.3f}V RMS: {np.sqrt(np.mean(signal.voltage**2)):.3f}V'
ax.text(0.02, 0.98, stats, transform=ax.transAxes,
verticalalignment='top', fontsize=9,
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
def plot_frequency_domain(self, ax, signal: SignalData):
"""绑制频域"""
ax.clear()
n = len(signal.voltage)
fft_result = np.fft.fft(signal.voltage)
freq = np.fft.fftfreq(n, 1/signal.sample_rate)[:n//2]
magnitude_db = 20 * np.log10(np.abs(fft_result[:n//2]) * 2 / n + 1e-10)
ax.plot(freq/1000, magnitude_db, 'b-')
ax.set_xlabel('频率 (kHz)')
ax.set_ylabel('幅度 (dB)')
ax.set_title(f'{signal.name} - 频域')
ax.grid(True, alpha=0.3)
ax.set_ylim(bottom=-80)
# 标记主频
peak_idx = np.argmax(magnitude_db[1:]) + 1
peak_freq = freq[peak_idx]
peak_mag = magnitude_db[peak_idx]
ax.annotate(f'{peak_freq:.0f}Hz\n{peak_mag:.1f}dB',
xy=(peak_freq/1000, peak_mag),
xytext=(peak_freq/1000 + 0.5, peak_mag + 5),
arrowprops=dict(arrowstyle='->', color='red'),
fontsize=9, color='red')
def plot_histogram(self, ax, signal: SignalData):
"""绑制直方图"""
ax.clear()
ax.hist(signal.voltage, bins=50, density=True, alpha=0.7,
color='steelblue', edgecolor='black')
ax.set_xlabel('电压 (V)')
ax.set_ylabel('概率密度')
ax.set_title(f'{signal.name} - 分布')
ax.grid(True, alpha=0.3)
def plot_spectrogram(self, ax, signal: SignalData):
"""绑制时频图"""
ax.clear()
ax.specgram(signal.voltage, NFFT=256, Fs=signal.sample_rate,
noverlap=128, cmap='viridis')
ax.set_xlabel('时间 (s)')
ax.set_ylabel('频率 (Hz)')
ax.set_title(f'{signal.name} - 时频')
def show(self, signal: Optional[SignalData] = None):
"""显示分析界面"""
if signal is None and self.signals:
signal = self.signals[0]
if signal is None:
print("没有信号数据")
return
self.fig = plt.figure(figsize=(14, 10))
# 创建子图
ax1 = self.fig.add_subplot(2, 2, 1)
ax2 = self.fig.add_subplot(2, 2, 2)
ax3 = self.fig.add_subplot(2, 2, 3)
ax4 = self.fig.add_subplot(2, 2, 4)
self.plot_time_domain(ax1, signal)
self.plot_frequency_domain(ax2, signal)
self.plot_histogram(ax3, signal)
self.plot_spectrogram(ax4, signal)
plt.tight_layout()
plt.show()
def save_report(self, signal: SignalData, filename: str):
"""保存分析报告"""
self.fig = plt.figure(figsize=(14, 10))
ax1 = self.fig.add_subplot(2, 2, 1)
ax2 = self.fig.add_subplot(2, 2, 2)
ax3 = self.fig.add_subplot(2, 2, 3)
ax4 = self.fig.add_subplot(2, 2, 4)
self.plot_time_domain(ax1, signal)
self.plot_frequency_domain(ax2, signal)
self.plot_histogram(ax3, signal)
self.plot_spectrogram(ax4, signal)
plt.tight_layout()
self.fig.savefig(filename, dpi=150, bbox_inches='tight')
plt.close(self.fig)
print(f"报告已保存到 {filename}")
# 使用示例
def demo():
# 生成测试信号
fs = 10000
t = np.arange(0, 1, 1/fs)
# 多频信号 + 噪声
signal = (1.0 * np.sin(2*np.pi*500*t) +
0.5 * np.sin(2*np.pi*1200*t) +
0.3 * np.sin(2*np.pi*2000*t) +
0.2 * np.random.randn(len(t)))
data = SignalData(
time=t,
voltage=signal,
sample_rate=fs,
name="测试信号"
)
viewer = SignalViewer()
viewer.add_signal(data)
viewer.show(data)
# viewer.save_report(data, 'signal_report.png')
demo()
10. 总结
🔑 核心要点
| 知识点 | 要点 |
|---|---|
| 基本绑图 | plt.plot(), fig, ax = plt.subplots() |
| 图表类型 | 折线图、散点图、柱状图、直方图、饼图 |
| 图表美化 | 标题、标签、图例、网格、注释 |
| 子图布局 | subplots(), GridSpec |
| 波形显示 | 时域波形、数字波形、双Y轴 |
| 频谱分析 | FFT频谱、时频图 |
| 实时绑图 | FuncAnimation, 交互模式 |
✅ 学习检查清单
- 能绑制基本图表
- 能美化图表
- 能创建子图布局
- 能绑制波形和频谱
- 了解实时绑图方法
📖 下一步学习
掌握了数据可视化后,让我们学习Vivado工程自动化:
常见问题 FAQ
💬 matplotlib图表中文显示乱码怎么办?
设置字体:plt.rcParams['font.sans-serif'] = ['SimHei'],同时plt.rcParams['axes.unicode_minus'] = False解决负号显示问题。
💬 matplotlib和plotly怎么选?
matplotlib适合静态图表和论文插图,plotly适合交互式图表和Web展示。FPGA波形分析用matplotlib足够,需要交互缩放用plotly。
� 系列导航
- 上一篇:24 - Python NumPy数据处理
- 当前:25 - Python数据可视化
- 下一篇:26 - Python调用Vivado自动化