如何用Python和Matplotlib把ASCII地震数据画成直观图表

来源:JS脚本作者:林则安头衔:网络博主
导读:本期聚焦于林则安创作的《如何用Python和Matplotlib把ASCII地震数据画成直观图表》,敬请观看详情。地震观测站常以纯文本ASCII格式记录波形与震相信息,但直接阅读数字矩阵很难判断事件特征。借助Python读取结构化文本,再用Matplotlib将采样序列转换为时间序列曲线或伪彩色剖面,可快速识别P波、S波到时。本文说明文本解析逻辑、坐标轴映射方法,以及用numpy加载数据后调用plot与imshow的差异,帮助科研人员少写重复脚本,把精力放在信号解释而非格式转换上。

在地球物理研究中,许多老旧台站和教学实验仍采用ASCII文本保存地震波形,每一行可能是等间隔采样的时间位移对,也可能是固定宽度的多通道记录。用Python配合Matplotlib处理这类数据,核心在于先把字符串准确解析成数值数组,再根据采样率还原时间轴,最后选择折线图或图像来呈现。下面以常见的两列空格分隔数据为例,展示完整流程。

如何用Python和Matplotlib把ASCII地震数据画成直观图表

ASCII地震数据的读取与清洗

ASCII地震文件往往带有表头注释,以井号或字母开头,真正的数据行才是浮点数。如果直接用numpy的loadtxt读取,遇到非数值行会报错,因此要先逐行判断。可以打开文件,用startswith过滤掉注释,再把剩余行按空白切分,转成float后追加到列表。这种写法比正则更直观,也方便处理偶尔出现的连续空格。

另一种情况是固定格式的宽度记录,比如每帧八十个字符、每四个字符一个采样。此时应该用字符串切片而非split,否则错位会导致数值完全错误。清洗阶段还要处理缺失值,有些台站会用9999或-12345表示断记,需要替换成nan,避免后续绘图出现垂直直线误导判断。下面代码演示了通用读取函数。

def read_ascii_seismic(path):
    rows = []
    with open(path, 'r') as f:
        for line in f:
            line = line.strip()
            if not line or line[0] in '#%':
                continue
            parts = line.split()
            try:
                vals = [float(x) for x in parts]
            except ValueError:
                continue
            if 9999.0 in vals:
                vals = [float('nan') if v == 9999.0 else v for v in vals]
            rows.append(vals)
    return rows

data = read_ascii_seismic('seismic.txt')
print(len(data), 'rows loaded')

当数据量达到几十万行时,纯Python循环会偏慢,可改用numpy的genfromtxt并指定comments参数跳过表头,它内部用C实现,速度提升明显。但要注意genfromtxt对不规则列数容忍度低,若某些行少一两列,会填充nan或报错,所以前期用简单脚本统计每行列数是必要的健康检查。

用Matplotlib绘制时间序列曲线

拿到二维列表后,通常第一列是时间或序号,第二列是振幅。若只有序号,需要除以采样率得到秒。Matplotlib的plot函数适合画单道波形,它能自动处理nan,在断记处断开线条。设置figsize和dpi可让导出图片清晰,xlabel写时间秒、ylabel写加速度或位移,符合论文习惯。

多台站对比时,用subplot堆叠多个坐标轴更直观。可以用共享x轴避免重复标注,突出不同方位的到时差。下面示例把前两道画成上下两张图,并标出疑似P波位置。实际分析中还可叠加filter后的曲线,用不同颜色区分原始与去趋势结果。

import matplotlib.pyplot as plt
import numpy as np

arr = np.array(data)
t = arr[:, 0] / 100.0  # 假设100Hz采样
amp = arr[:, 1]

fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(10, 6))
ax1.plot(t, amp, color='black', linewidth=0.6)
ax1.set_ylabel('Channel 1')
ax2.plot(t, arr[:, 2], color='gray', linewidth=0.6)
ax2.set_ylabel('Channel 2')
ax2.set_xlabel('Time (s)')
ax1.axvline(12.4, color='red', linestyle='--')
plt.tight_layout()
plt.savefig('waveform.png', dpi=150)

折线图虽然精细,但在长时间记录里像素密集,肉眼难辨频带变化。此时可改用specgram画频谱图,或者把连续段重采样后做图像。要注意plot默认连线会在nan处断掉,如果希望断记区域留白而不是跳线,需手动切片分段绘制,否则可能看到斜跨屏幕的假信号。

将多道ASCII数据转为剖面图像

当ASCII文件包含几十个通道、每个通道等长度时,可把数据整理成二维矩阵,用imshow展示伪彩色剖面。行代表通道深度或距离,列代表时间,颜色映射用seismic或gray,能一眼看出同相轴倾斜,也就是震相随距离延迟。这种方法比逐条线看更高效,常用于初至拾取前的快速浏览。

矩阵构造时要注意转置方向,Matplotlib的imshow默认原点在左上,而地震剖面通常时间向下增加,因此要设origin='upper'并调整extent参数,让y轴显示真实时间。若ASCII里通道顺序和台站位置不对应,还需按坐标排序,否则剖面会空间错乱。下面代码把前三列通道拼成图像。

matrix = np.array(data)[:, 1:4].T  # 3通道,转置为通道×时间
plt.imshow(matrix, aspect='auto', cmap='seismic',
           extent=[0, matrix.shape[1]/100.0, matrix.shape[0], 0])
plt.colorbar(label='Amplitude')
plt.xlabel('Time (s)')
plt.ylabel('Channel index')
plt.title('Seismic section from ASCII')
plt.show()

剖面图像虽快,却丢失了精确数值,所以正式处理仍要结合折线图定位。如果ASCII数据带有经纬度表头,还可把剖面映射到地图底图上,用basemap或cartopy叠加,但这已超出基础Matplotlib范围。掌握文本解析与两种绘图方式的切换,就能覆盖多数教学与巡检场景,不必依赖商业软件导入。

PythonMatplotlibascii_seismic_data修改时间:2026-08-17 19:02:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。