You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Altair绘制频谱图?DataFrame格式适配与轴编码问题

使用Altair绘制频谱图的解决方案

问题背景

现有一个宽格式DataFrame:列名为频率区间,索引为时间/帧,单元格值对应对应时间下该频率的幅值。需要用Altair绘制频谱图,将频率作为Y轴、时间作为X轴、幅值作为颜色编码,但不清楚如何让Altair识别列名作为Y轴,或是否需要重构数据。已有Matplotlib版本实现,需要Altair的交互功能。

数据集示例

col_freq= [172.265625, 344.53125, 516.796875, 689.0625]

row_1 = [1610974057651.0325, 1261973870532.6091, 
234137860730.91223, 42549716015.37]
row_2 = [4741489056189.282, 3278778293422.225, 
160494114891.44345, 57040784835.97968]
row_3 = [198776867252.5261, 661886049124.3528, 188309227047.4264, 
124549622810.97015]

data = [row_1, row_2, row_3]
df = pd.DataFrame(data, columns=col_freq)

原Scipy数据生成代码

import pandas as pd
import altair as alt
import scipy as sc
from scipy import fft, signal 
from matplotlib import pyplot as plt

# 替换为你的音频文件路径
sample_rate, audio_file = sc.io.wavfile.read('path/my_audio.wav')
size = 2048
window_func = signal.windows.hann(size)

def wave_to_spect(x, label):
    freq, time, Sxx = signal.spectrogram(x, sample_rate, 
       window=window_func, nperseg=len(window_func))
    col_name = [str(x) for x in freq]    
    df = pd.DataFrame(Sxx, index=col_name)
    df = df.T
    # Matplotlib可视化
    plt.pcolormesh(time, freq, np.log(Sxx), shading='gouraud')
    plt.title('Spectrogram ' + label)
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec]')    
    plt.show()

wave_to_spect(audio_file, "audio_car")

核心解决方案:重构为长格式数据

Altair基于Vega-Lite,更适配长格式(long-form)数据——即每行对应一个观测值,列对应时间、频率、幅值三个变量。当前宽格式数据需要先转换。

步骤1:修改数据生成逻辑,直接输出长格式DataFrame

调整wave_to_spect函数,生成符合Altair要求的结构:

import numpy as np

def wave_to_spect_altair(x, label):
    freq, time, Sxx = signal.spectrogram(x, sample_rate, 
       window=window_func, nperseg=len(window_func))
    # 生成长格式数据:重复时间、平铺频率、展平幅值
    df_long = pd.DataFrame({
        'time': np.repeat(time, len(freq)),
        'frequency': np.tile(freq, len(time)),
        'amplitude': np.log(Sxx).flatten()  # 和Matplotlib保持对数处理
    })
    return df_long, label

步骤2:用Altair绘制交互式频谱图

直接映射变量到编码通道,启用交互功能:

# 获取长格式数据
df_spect, plot_label = wave_to_spect_altair(audio_file, "audio_car")

# 绘制频谱图
chart = alt.Chart(df_spect).mark_rect().encode(
    x=alt.X('time:Q', title='Time [sec]'),
    y=alt.Y('frequency:Q', title='Frequency [Hz]'),
    color=alt.Color('amplitude:Q', title='Log Amplitude', 
                   scale=alt.Scale(scheme='viridis')),  # 可选颜色方案
    tooltip=['time:Q', 'frequency:Q', 'amplitude:Q']  # 鼠标悬停显示详情
).properties(
    title=f'Spectrogram - {plot_label}',
    width=800,
    height=400
).interactive()  # 启用缩放、平移交互

chart.show()

已有宽格式DataFrame的转换方法

如果已经存在宽格式数据,用pd.melt快速转换:

# 将时间索引转为列
df.reset_index(inplace=True, names='time')
# 宽转长
df_long = df.melt(
    id_vars='time',
    var_name='frequency',
    value_name='amplitude'
)
# 频率列转为数值类型(若原列名为字符串)
df_long['frequency'] = pd.to_numeric(df_long['frequency'])
# 可选:对幅值取对数
df_long['amplitude'] = np.log(df_long['amplitude'])

额外优化建议

  • 颜色方案:替换scheme参数使用不同配色,比如inferno、magma
  • 性能优化:大数据量下启用alt.data_transformers.enable('vegafusion')提升渲染速度
  • 交互增强:添加选择器(如alt.selection_interval())实现频率/时间范围过滤

内容的提问来源于stack exchange,提问作者phidelity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:27:00