简介geolog-app 是一个基于 Python 开发的地质数据处理与可视化应用面向地质科研人员、数据分析学习者以及希望掌握 GIS 和 Web 开发技能的编程爱好者。压缩包仅有 14KB共含 22 个文件以 14 个 Python 脚本为核心覆盖 Django 后端的配置、URL 路由、视图、模型、迁移等模块同时提供 SQLite 数据库、HTML/CSS 前端页面、依赖清单、部署配置和 README结构紧凑便于快速定位与研读。目前已有 162 人学习下载。通过该项目读者可以完整了解一个微型地质 Web 应用的代码组织方式看到 Python 在地质数据清洗、空间分析与图表展示中的实际落地体会到从后端逻辑到前端渲染的串联方法也为后续引入 NumPy、Pandas、GeoPandas 等更复杂的数据科学和 GIS 工具建立了清晰的参考模板。对于刚接触 Django 的开发者这份代码还能展示 MTV 架构的常见写法帮助理解 URL 分发、模型迁移与模板渲染之间的协作关系。1. geolog-app 是干什么的写给数据一堆但出不来图的人听到 geolog-app 这个名字先别急着把它当成又一个商业地质软件。它更像一个围绕“深度—数值—分层标记”三条数据线做整理的轻量工具解决的是测井数据和地质分层之间的衔接问题。常见场景是你手里有一口井的 LAS 或 CSV曲线在深度在但要把层位顶底深度标出来、把两口井放在同一深度轴上对比却总在格式转换和深度对不齐上耗掉大半天。这类活儿是 geolog-app 的主场它不替你做地质解释只把深度校正、重采样、分层标记和图件导出这条管线整理到一个可重复执行的工作流里。适合谁用一种是每天在商业工作站里点鼠标、但想省掉重复整理步骤的从业者另一种是拿到别人给的数据、第一件事是确认深度和曲线是否干净的工程师。如果你正处于“数据越多越不敢动”的状态这个方向值得投入。2. 先让 geolog-app 跑起来依赖安装与最小启动命令2.1 先理解三张表深度、数值、分层标记用 geolog-app 之前建议把数据结构先拆成三类。第一类是深度轴也就是每一条曲线对应的采样深度点第二类是曲线数值比如 GR、SP、电阻率这些测井响应第三类是分层标记也就是你要人工或半自动确定的层位顶底深度。这三者分开存、分开处理后续所有操作才会不打架。我最开始用的时候习惯把所有东西塞进一个 DataFrame结果深度校正后索引全乱了分层标记也跟着错位。后来改成三表分离深度轴单独一个数组数值曲线按名字存在字典里分层标记单独用一个 CSV 维护。这样做的直接好处是无论哪一步做错了只要重新执行对应步骤就行是一个可复跑的工作流而不是一次性的脚本。2.2 安装与环境准备geolog-app 的依赖不算复杂核心是 lasio、pandas、numpy、matplotlib 这几个库。lasio 负责解析 LAS 格式pandas 负责表格操作matplotlib 负责出图。以下是我常用的环境初始化方式python -m venv venv source venv/bin/activate pip install lasio pandas numpy matplotlib scipy逻辑上先建虚拟环境避免污染系统 Pythonlasio 是测井行业通用的 LAS 文件解析库只要不是太老的文件版本都能读。scipy 是可选的我在做曲线平滑时才用得到如果你只做分层标记可以先不装。安装完成后建议先空跑一遍导入检查而不是直接去读数据文件这样可以区分“环境问题”和“数据问题”。2.3 最小启动命令读入一口井并确认深度轴环境准备好了第一步是把一口井的 LAS 文件读进来然后打印最基本的信息曲线名、单位、起始深度和终止深度。这一步的意义在于很多问题在还没开始处理之前就会暴露出来比如单位全乱、深度轴顺序颠倒等。import lasio las lasio.read(demo.las) for curve in las.curves: print(curve.mnemonic, curve.unit) depth las.index print(起始深度:, depth.min(), 结束深度:, depth.max()) print(采样点数:, len(depth))lasio.read 默认返回一个 LAS 对象las.index 是深度轴las[GR] 可以按曲线名取数值。第一次跑通的时候记住先看曲线单位再看深度范围。单位不一致的情况不在少数比如 GR 是 API、电阻率是 OHMM这些在后续绘图时如果不换算图例就没法统一。3. 深度轴校正与重采样两个必调参数看清数据差异3.1 深度漂移校正先对齐再做别的测井深度漂移是个老话题。同一口井不同趟次测井深度轴可能差出几米不同井之间补心高、井深基准也可能不同。在校正之前做任何分层都等于在沙地上盖楼。常见的做法是选一条参考曲线比如用电缆深度校正后的 GR 作为基准把需要校正的曲线整体平移或分段平移。import numpy as np depth las.index gr_raw las[GR] # 校正量由人工对比参考GR确定单位是米 shift 2.5 depth_corr depth - shift # 用校正后的深度重新插值保证深度轴单调 gr_corrected np.interp(depth, depth_corr, gr_raw)这里 shift 的含义很关键它是“需要减去的偏移量”正值表示当前深度比参考深度偏大。某个方向上如果校正后出现了重复深度或倒序深度说明方向取反了。这个参数几乎没有自动化的万能解法因为漂移原因多样我在实际项目中通常靠直观对比曲线峰谷来定初始值再微调 0.250.5 米的量级。3.2 平滑窗口用中值滤波还是均值滤波曲线毛刺太多时直接自动分层会抓出一堆假突变。中值滤波比均值滤波更稳因为它保留台阶边缘不会把真实层界面磨平。这个特性对层位识别非常重要因为你要的是突变的台阶而均值滤波会把台阶过渡拉长让顶底边界看着像渐变。from scipy.ndimage import median_filter # size 是滑动窗口的点数按采样间隔换算 # 例如采样间隔0.125米size5 相当于平滑0.625米 gr_smooth median_filter(gr_corrected, size5)size 怎么选采样间隔越密理论上窗口可以开得越大但窗口过大会削平薄层的响应极值。对 0.125 米采样的 GR 曲线我用 5 到 9 个点起步然后对比原曲线看形态是否失真。对层厚小于 1 米的薄层窗口建议控制在 5 个点以内。这个参数属于“看数据说话”的类型没有通吃的值。3.3 重采样统一井间的深度网格井间对比时每口井的采样间隔和起始深度都不同比如 A 井从 2000 米开始采、间隔 0.125 米而 B 井从 1999.8 米开始、间隔 0.5 米。如果不统一网格后面所有井间对比图都错位。重采样的做法是定义一个统一的深度序列然后把每口井的曲线插值到这套序列上来。# 定义统一网格从 2000 米到 2500 米间隔 0.125 米 new_depth np.arange(2000.0, 2500.0, 0.125) # 线性插值到新网格 gr_resampled np.interp(new_depth, depth_corr, gr_smooth, leftnp.nan, rightnp.nan)参数说明left 和 right 设置为 nan是为了让超出原井深度范围的区域不参与后续统计否则外推数据会形成虚假的水平线。此外超过原深度范围而插值得到的 nan 会在绘图时形成空白这是期望行为。如果用的是更高阶插值比如样条请留意过冲震荡薄层处尤其容易出负值这在 GR 曲线上就是明显的假响应。4. 分层作业手动标记与自动候选的正确打开方式4.1 手动分层模式用表格维护顶底深度自动分层在复杂地质条件下并不可靠至少在目前最终解释权还是应该交给人工。手动分层不代表用鼠标在软件里拉线而是通过观察平滑后的曲线把层位顶底深度记录到一个结构化文件里。这样既保留了人的判断又让结果可以被脚本复用。# markers.csv: layer_top,layer_bottom,layer_name # 2385.0,2420.5,Layer_A # 2420.5,2471.0,Layer_B import pandas as pd markers pd.read_csv(markers.csv) markers[thickness] markers[layer_bottom] - markers[layer_top] print(markers)CSV 是分层标记最好的载体因为顶底深度本身就是两列数字。每次手工修正分层时只需要改 CSV 里对应行的数字再保存处理脚本不需要改。这种做法对我来说最大的价值是历史可追溯每一版分层文件都保留了谁在什么时候调整过哪个层位而不是一个不可回放的图形状态。4.2 自动分层候选一阶差分找突变点自动分层可以做但定位应是“候选生成器”而不是“最终解释器”。对 GR 这类能反映岩性变化的曲线地层界面往往对应曲线值的一阶差分极值。实现思路很简单计算平滑后曲线的差分绝对值设定一个阈值超过阈值的位置就是候选界面。diff np.abs(np.diff(gr_smooth)) # 用98分位数做阈值只挑最显著的突变 threshold np.percentile(diff, 98) candidates np.where(diff threshold)[0] # 把索引换算成深度 candidate_depths depth_corr[candidates] print(候选界面深度:, candidate_depths[:10])threshold 是这里唯一的关键参数。98 分位数通常是安全起点如果候选太多说明分层信号太碎一是提高分位数到 99二是先加大平滑窗口。如果候选太少或一个大突变掩盖了次级界面可以改成在一个滑动区间内做局部百分位筛选。注意自动候选必须和人工标记配合我的经验是百分之八十的候选点可直接采用剩下百分之二十因为薄层、断点或泥质条带需要手动剔除。不要试图把这个比例反过来。5. geolog-app 避坑5 条实测记录5.1 深度轴相关的三个坑现象一一口井的 GR 曲线与邻井形态相似但每套层位深度都系统性偏浅 3 米左右人工分层时怎么都对齐不了。原因LAS 文件里的深度单位是英尺而参考数据用的是米差值正好来自单位换算。这类问题常见于数据源混杂的项目录入时没有做单位统一。解决读取 LAS 后第一步打印 las.well 里的深度单位确认是 feet 还是 meter再统一换算。换算系数记住一个1 英尺等于 0.3048 米。查出来的问题往往不是曲线问题而是单位问题。现象二在 geolog-app 里把曲线和数据表导出后某口井的分层边界与原始测井图相差约半个采样间隔怎么都对不上。原因深度校正和重采样之后分层标记的深度基准没有同步更新。用旧深度轴上的分层数据去匹配新深度轴上的曲线自然差出间隔。解决把“深度轴”作为唯一基准。重采样后立刻用新深度轴重新换算所有分层顶底深度再做下一层操作。我在工作流里强制规定所有分层修正只允许基于最新导出的一版校正深度不能来回混用。现象三同一工区数口井分别来自不同批次测井有的从补心高起算有的从地面起算井间对比时同一层位深度跳来跳去。原因深度基准不一致。这是数据管理问题不是曲线问题。解决导入阶段明确记录每口井的深度基准类型统一换算到同一基准后再进入后续流程。在分层文件里增加一列 depth_datum 做标记虽然看起来多此一举但若干口井对比时能省大量排查时间。5.2 曲线数值与格式相关的两个坑现象四平滑处理后的 GR 曲线上出现几个异常深谷形态与原始曲线完全不吻合看起来像“挖坑”。原因LAS 文件里的缺失值记录为 -999.25没有做缺失值屏蔽直接送入中值滤波后这些异常值就会像真实低值一样参与运算并扩散到相邻点。解决所有处理前先屏蔽缺失值用 np.where 将异常值替换为 nan再在前处理里统一填充。中值滤波前把 nan 做插值处理避免窗口内的异常值影响滤波输出。这一步是花了比较长的时间才真正重视起来的属于典型的细节翻车。现象五把 CSV 导出的数据重新导入 geolog-app 后深度列被当成字符串排序结果完全错乱分层文件顺序全变。原因CSV 导入时 pandas 自动推断类型失败深度列含空值或单位字符被识别为 object 类型。解决导入时显式指定 dtypedepth_data pd.read_csv(depth.csv, dtype{depth: float64}) depth_sorted depth_data.sort_values(depth).reset_index(dropTrue)强制指定 float64 后排序按数值而不是按字典序进行。这个坑几乎是必踩的因为手工生成的 CSV 容易混入空格和单位后缀。养成导入时显式规定类型、然后立刻检查 dtype 的习惯比事后调错要高效得多。6. 导出剖面图与分层数据表交付前最后一步6.1 多井横向对比图的画法geolog-app 的落点常在于“把结果给人看”。多井对比图的常见做法是每口井一列深度轴间隔一致、自上而下排列。绘图时的关键点是统一深度范围并且纵轴要翻转让深度向下增大。import matplotlib.pyplot as plt fig, axes plt.subplots(1, n_wells, figsize(3 * n_wells, 8)) for ax, name in zip(axes, well_names): ax.plot(wells[name][GR], wells[name][depth], linewidth0.6) ax.invert_yaxis() ax.set_ylim(2000, 2500) # 强制所有井同一深度窗 ax.set_xlabel(name)这里 ylim 必须手动指定让图幅范围一致否则深度窗口会在各井之间跳动对比无从谈起。invert_yaxis 把深度改成向下增大符合地质图的阅读习惯。剖面图本身不是成果但它是发现问题的工具一半的深度错位问题靠这张图看得出来。6.2 分层数据表的导出分层成果最终要交出去常见格式是分层数据表加剖面对比图。导出的分层表会包含层名、顶深、底深、视厚度以及分层说明。一个实用细节是同时输出校正前后的深度对照这样收数据的一方可以独立核验。result markers.copy() result[top_corr] result[layer_top] depth_shift_total result[bottom_corr] result[layer_bottom] depth_shift_total result.to_csv(layers_result.csv, indexFalse)每个数据交付清单一律附上校正参数这是很重要的习惯可避免对方拿到数据后发现深度对不上但找不到原因。这个检查习惯帮我省了很多次后续沟通的成本也算是一个经验之谈分层的准确性不只是靠曲线识别更靠整条数据链路的每个中间台账都可追溯。如果你现在还在用“手动记录深度手工描图”的方式做分层强烈建议把 geolog-app 里这套深度校正与标记流程接起来跑一遍经历过一次多井对比导出就会感受到前后差异。希望帮到你。本文还有配套的精品资源点击获取