Skip to content

数据库操作

dimine_python_sdk.lib.db 与 dimine_python_sdk.lib.prospecting 模块提供对 Dimine 本地数据库(.dmf / .dmd)的原生访问能力,无需启动 Dimine GUI 即可读取和处理数据。

前置条件: - 环境变量 DIMINE_HOME 指向包含 DmPyBindInterface.pyd 的目录 - Python >= 3.12


模块定位

SDK 的数据处理层目前分为三个概念清晰的模块:

模块 用途 典型类
lib.db 数据库/数据表业务封装 DmDbDatabase、DmDbLayer、DmDataTable、TableRow
models 对外 Pydantic 纯数据模型 Point、Line、Shell

本文档覆盖 lib.db 中的通用数据库/数据表操作,以及 lib.prospecting 中的钻孔数据库专用操作。


一、通用数据库操作

1.1 几何数据库(DmDbDatabase)

DmDbDatabase 用于加载和操作本地 .dmf 几何数据库文件。

直接加载

from dimine_python_sdk.lib.db import DmDbDatabase

db = DmDbDatabase("E:/data/mine.dmf")
print(f"图层数: {db.get_layers_count()}")

使用上下文管理器(推荐)

from dimine_python_sdk.lib.db import data_database_conn

with data_database_conn("E:/data/mine.dmf") as db:
    print(f"图层数: {db.get_layers_count()}")

访问图层和实体

from dimine_python_sdk.lib.db import data_database_conn

with data_database_conn("E:/data/mine.dmf") as db:
    # 遍历所有图层
    for i in range(db.get_layers_count()):
        layer = db.get_layer_by_index(i)
        if layer is None:
            continue

        print(f"图层 {i} 实体数量: {layer.get_entities_count()}")

        # 遍历图层内实体
        layer.start_query_entity()
        entity = layer.open_next_entity()
        while entity is not None:
            print(f"  实体类型: {entity.get_entity_type_name()}")
            entity = layer.open_next_entity()

常用操作

from dimine_python_sdk.lib.db import DmDbDatabase

db = DmDbDatabase("E:/data/mine.dmf")

# 插入新图层
new_layer = db.insert_layer("新图层")

# 在当前图层插入几何实体
new_layer.insert_line(start_point, end_point)
new_layer.insert_polyline(points)

# 保存(覆盖原文件或另存为)
db.save()
db.save("E:/data/mine_backup.dmf")

# 创建空白本地数据库
empty_db = DmDbDatabase.create_local_db()

1.2 数据表(DmDataTable / TableRow)

DmDataTable 是 lib.db 提供的通用数据表类,支持类似 pandas 的多态索引和遍历。钻孔数据库的三大表(孔口表、测斜表、岩性表)统一返回 pandas.DataFrame,便于与 Python 数据科学生态集成。

加载数据表

from dimine_python_sdk.lib.db import DmDataTable, data_table_conn

# 方式一:直接加载
dt = DmDataTable("E:/data/table.dmd")

# 方式二:上下文管理器(退出时自动保存)
with data_table_conn("E:/data/table.dmd") as dt:
    print(f"字段数: {dt.get_field_count()}")
    print(f"记录数: {len(dt)}")

获取字段信息

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    # 所有字段名
    print(f"字段: {dt.columns}")

    # 记录数
    print(f"记录数: {len(dt)}")

按列访问

通过字段名获取整列数据:

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    # 获取整列
    names = dt["Name"]
    print(f"记录数量: {len(names)}")
    print(f"前5条: {names[:5]}")

按行访问

通过索引获取单行数据,返回 TableRow 对象:

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    # 获取第一条记录
    row = dt[0]

    # 双访问模式
    print(row["Name"])     # dict 风格
    print(row.Name)        # 属性风格
    print(row.to_dict())   # 转为原生 dict
    print(f"行索引: {row.index}")

TableRow 是轻量级字典代理,为数据表每一行提供双访问模式:

from dimine_python_sdk.lib.db import TableRow

row = TableRow({"HoleID": "ZK001", "Depth": 500.0, "Au": 3.5}, index=0)

# dict 风格
row["HoleID"]        # "ZK001"

# 属性风格
row.Depth            # 500.0
row.Au               # 3.5

# 工具方法
row.to_dict()        # {"HoleID": "ZK001", "Depth": 500.0, "Au": 3.5}
row.keys()
row.values()
row.items()
row.get("Missing", "default")
len(row)             # 3

切片访问

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    # 获取前10条记录
    first_10 = dt[0:10]
    for row in first_10:
        print(f"{row.Name}: {row.Value}")

遍历数据表

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    for row in dt:
        print(f"索引 {row.index}: {row.to_dict()}")

转换为 pandas / numpy

数据表可直接转换为 pandas DataFrame 或 numpy 数组,便于数据分析。

转为 pandas DataFrame:

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    df = dt.to_pandas()
    print(df.head())
    print(df.describe())

注意:使用 to_pandas() 前需安装 pandas:

uv add pandas

转为 numpy 数组:

from dimine_python_sdk.lib.db import data_table_conn

with data_table_conn("E:/data/table.dmd") as dt:
    # 整表转为二维 numpy 数组
    arr = dt.to_numpy()
    print(arr.shape)

    # 单列转为一维数组
    values = dt.to_numpy(column="Value")
    print(f"平均值: {values.mean()}")

二、钻孔数据库操作

dimine_python_sdk.lib.prospecting 提供对 Dimine 钻孔数据库(.dmd)的专用访问能力。钻孔数据库包含三大核心表:孔口表、测斜表、岩性表,API 统一返回 pandas.DataFrame,列名均为中文标准格式,与 Python 数据科学生态无缝衔接。

列名规范:写入时 DataFrame 的列名必须使用中文标准列名;读取时返回的列名也为中文标准格式。

前置导入:

from dimine_python_sdk.lib.prospecting import DrillDBManager, drill_conn
from dimine_python_sdk.lib.prospecting._adapter import (
    DrillDBError,
    DrillDBLoadError,
    DrillDBProcessError,
)

兼容路径 dimine_python_sdk.lib.prospecting.drill_db 仍可导入,但会触发弃用警告,建议直接改为上述路径。


2.1 加载与创建

从文件加载

from dimine_python_sdk.lib.prospecting import DrillDBManager

# 加载钻孔数据库
db = DrillDBManager("C:/Projects/Mine/钻孔数据.dmd")

# 支持相对路径
db = DrillDBManager("钻孔数据.dmd", base_path="C:/Projects/Mine")

创建空对象(从 DataFrame 写入)

初始化时不传路径,可以创建一个空白钻孔数据库对象,通过赋值 DataFrame 后再保存:

import pandas as pd
from dimine_python_sdk.lib.prospecting import DrillDBManager

db = DrillDBManager()

# 准备 DataFrame(必须使用中文标准列名)
df_collar = pd.DataFrame({
    "工程号": ["ZK001", "ZK002"],
    "横坐标": [100.0, 200.0],
    "纵坐标": [300.0, 400.0],
    "高程": [500.0, 550.0],
    "总深度": [100.0, 120.0],
    "勘探线": ["L1", "L2"],
})

# 赋值到数据库
db.collar = df_collar

# 保存到文件
db.save("C:/Projects/Mine/新钻孔数据.dmd")

显式加载方法

也可以在创建空对象后,通过 load() 方法加载文件:

db = DrillDBManager()
db.load("C:/Projects/Mine/钻孔数据.dmd")
print(db.collar.head())

使用上下文管理器(推荐)

使用 drill_conn 可确保资源自动释放,避免内存泄漏。支持传文件路径或创建空对象:

from dimine_python_sdk.lib.prospecting import drill_conn

# 从文件加载
with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    print(db.collar.head())
    # 离开 with 块后自动释放资源

# 创建空对象,赋值后保存
with drill_conn() as db:
    db.collar = df_collar
    db.save("C:/Projects/Mine/新钻孔数据.dmd")

2.2 访问钻孔数据表

钻孔数据库包含四大核心表,通过属性即可访问,返回类型均为 pandas.DataFrame:

属性 说明 返回类型
db.collar 孔口表(钻孔基本信息:孔号、坐标、深度等) pd.DataFrame
db.survey 测斜表(钻孔轨迹测斜数据) pd.DataFrame
db.lithology 岩性表(钻孔岩性分层信息) pd.DataFrame
db.sample 样品表(化验样品数据) pd.DataFrame
from dimine_python_sdk.lib.prospecting import drill_conn

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 访问四大表(均为 pd.DataFrame)
    collar = db.collar       # 孔口表
    survey = db.survey       # 测斜表
    lithology = db.lithology # 岩性表
    sample = db.sample       # 样品表

    # 也可以使用 dict 风格访问
    collar = db["collar"]
    survey = db["survey"]
    lithology = db["lithology"]
    sample = db["sample"]

    print(f"孔口表记录数: {len(collar)}")
    print(f"测斜表记录数: {len(survey)}")
    print(f"岩性表记录数: {len(lithology)}")
    print(f"样品表记录数: {len(sample)}")

DataFrame 操作示例

由于返回的是 pd.DataFrame,可直接使用 pandas 原生操作:

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 获取所有钻孔孔号(Series)
    hole_ids = db.collar["工程号"]
    print(f"钻孔数量: {len(hole_ids)}")

    # 查看第一条孔口记录(Series)
    row = db.collar.iloc[0]
    print(row["工程号"], row["总深度"])

    # 获取前5条
    print(db.collar.head(5))

    # 字段名列表(均为中文标准列名)
    print(db.collar.columns.tolist())

    # 条件筛选
    deep_holes = db.collar[db.collar["总深度"] > 500]
    print(f"深孔数量: {len(deep_holes)}")

通过 setter 修改数据表

可以将修改后的 DataFrame 赋值回数据库:

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 读取
    df = db.collar.copy()

    # 修改(保持中文标准列名)
    df["总深度"] = df["总深度"] * 1.1

    # 写回(仅更新内存缓存)
    db.collar = df

    # 保存(写入 .dmt 子表 + .dmd 引用)
    db.save()

2.3 标准列名映射规范

DrillDBManager 对三大表的 DataFrame 列名有严格的格式要求。写入时必须使用中文标准列名;读取时返回中文标准列名。

孔口表(db.collar)

中文列名(输入) 英文列名(存储) 说明
工程号 BHID 钻孔唯一标识
横坐标 EAST X 坐标
纵坐标 NOTRH Y 坐标
高程 ELEVATION Z 高程
总深度 TOTALDEPTH 钻孔总深度
勘探线 SECTION 所属勘探线
其他 OTHERFIELDS 其他扩展字段
from dimine_python_sdk.lib.prospecting import DrillDBManager

# 通过类属性查看完整映射
print(DrillDBManager.COLLAR_COLUMN_MAP)
# {'工程号': 'BHID', '横坐标': 'EAST', ...}

测斜表(db.survey)

中文列名(输入) 英文列名(存储) 说明
工程号 SURBHID 钻孔编号
测斜深度 SDEPTH 测斜深度
方位角 AZIMUTH 方位角
倾角 DIP 倾角

岩性表(db.lithology)

中文列名(输入) 英文列名(存储) 说明
工程号 LITHBHID 钻孔编号
起始 LITHFROM 起始深度
结束 LITHTO 结束深度
岩性编号 ROCK-TYPE 岩性编号

样品表(db.sample)

中文列名(输入) 英文列名(存储) 说明
工程号 SAMBHID 工程编号
样本编号 SAMPLE-ID 样品编号
起始 SAMFROM 样品起始深度
结束 SAMTO 样品结束深度
# 通过类属性查看完整映射
print(DrillDBManager.SAMPLE_COLUMN_MAP)
# {'工程号': 'SAMBHID', '样本编号': 'SAMPLE-ID', ...}

列名校验规则

  • 写入时,DataFrame 的所有列名必须全部在对应表的映射字典的 key 中
  • 出现未定义列名时,抛出 DrillDBError 并提示非法列和允许列
  • 读取时,只保留映射字典中定义的列,多余列自动过滤;列顺序按标准顺序排列
import pandas as pd
from dimine_python_sdk.lib.prospecting import DrillDBManager

db = DrillDBManager()

# 正确:所有列名均为中文标准列名
db.collar = pd.DataFrame({
    "工程号": ["ZK001"],
    "横坐标": [100.0],
    "纵坐标": [200.0],
    "高程": [50.0],
})

# 错误:包含非法列名 'depth'
db.collar = pd.DataFrame({"工程号": ["ZK001"], "depth": [100.0]})
# DrillDBError: 孔口表 列名不符合标准格式。非法列: ['depth']。允许的列: [...]

2.4 保存与重新加载

from dimine_python_sdk.lib.prospecting import DrillDBManager

db = DrillDBManager("C:/Projects/Mine/钻孔数据.dmd")

# 修改后保存(覆盖原文件)
db.save()

# 另存为新文件
db.save("C:/Projects/Mine/钻孔数据备份.dmd")

# 重新加载文件(清空缓存)
db.reload()

# 释放资源
db.close()

空对象调用 save() 不指定路径会抛出 DrillDBError,必须传入 output_path。


2.5 钻孔数据处理

钻孔数据库模块提供三种常用数据处理方法,均通过 Pydantic 参数模型传入。

样长组合

将不等长样品按指定长度重新组合:

from dimine_python_sdk.lib.prospecting import drill_conn
from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    params = SampleLengthCombineParam(
        input_file="C:/Projects/Mine/样品数据.dmf",
        combine_length=1.0,      # 组合长度 1m
        combine_percent=1.0,     # 组合百分比 100%
        output_file="C:/Projects/Mine/组合后样品.dmf",
    )

    result = db.process_samples(params)
    print(f"处理结果: {result}")

参数说明:

参数 类型 说明
input_file str 输入样品数据文件路径
combine_length float 组合长度,必须 > 0
combine_percent float 组合百分比,0-1 之间,默认 1.0
output_file str 输出文件路径

台阶组合

按台阶高程对样品数据进行组合:

from dimine_python_sdk.lib.prospecting import drill_conn
from dimine_python_sdk.lib.prospecting.models import StepCombineParam

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    params = StepCombineParam(
        input_file="C:/Projects/Mine/样品数据.dmf",
        step_height=10.0,     # 台阶高度 10m
        start_height=0.0,     # 起始高程
        end_height=100.0,     # 结束高程
        calculate_model=0,    # 计算方式
        low_dip=5.0,          # 忽略最小倾角 5°
        output_file="C:/Projects/Mine/台阶组合后.dmf",
    )

    result = db.process_steps(params)
    print(f"处理结果: {result}")

特高品位处理

对超过阈值的特高品位样品进行处理:

from dimine_python_sdk.lib.prospecting import drill_conn
from dimine_python_sdk.lib.prospecting.models import HighGradeProcessParam

with drill_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    params = HighGradeProcessParam(
        input_file="C:/Projects/Mine/样品数据.dmf",
        grade_field="Cu",           # 品位字段
        process_mode=0,             # 0:国内标准
        average_multiple=5.0,       # 平均倍数
        frequency=0.1,              # 频率阈值
        replace_method=1,           # 1:给定值替换
        assign_value=2.5,           # 替换给定值
        result_field="Cu_processed", # 结果字段名
    )

    result = db.process_high_grade(params)
    print(f"处理结果: {result}")

replace_method 枚举:

值 说明
0 剔除法
1 给定值
2 相邻样品平均值
3 矿体平均品位法
4 单一工程法
5 截止品位法

2.8 异常处理

from dimine_python_sdk.lib.prospecting import drill_conn
from dimine_python_sdk.lib.prospecting._adapter import (
    DrillDBError,
    DrillDBLoadError,
    DrillDBProcessError,
)

try:
    with drill_conn("不存在的文件.dmd") as db:
        print(db.collar.head())
except DrillDBLoadError as e:
    print(f"加载失败: {e}")

# 处理异常
try:
    from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam

    params = SampleLengthCombineParam(
        input_file="无效路径.dmf",
        combine_length=1.0,
        output_file="输出.dmf",
    )
    result = db.process_samples(params)
except DrillDBProcessError as e:
    print(f"处理失败: {e}")
    print(f"原始响应: {e.response}")
except DrillDBError as e:
    print(f"数据库错误: {e}")

三、完整示例

示例一:读取并分析已有钻孔数据库

from dimine_python_sdk.lib.prospecting import drill_conn
from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam


def main():
    file_path = "C:/Projects/Mine/钻孔数据.dmd"

    with drill_conn(file_path) as db:
        # 1. 打印数据库概况
        print("=" * 40)
        print("钻孔数据库概况")
        print("=" * 40)
        print(f"文件路径: {db.file_path}")
        print(f"孔口表记录数: {len(db.collar)}")

        # 2. 查看孔口表结构
        print("\n" + "=" * 40)
        print("孔口表信息")
        print("=" * 40)
        print(f"字段: {db.collar.columns.tolist()}")
        print(f"记录数: {len(db.collar)}")

        # 3. 查看前3条孔口记录
        print("\n前3条孔口记录:")
        print(db.collar.head(3))

        # 4. 提取所有孔号
        hole_ids = db.collar["工程号"]
        print(f"\n所有钻孔: {hole_ids.tolist()}")

        # 5. pandas 分析
        print(f"\npandas DataFrame 形状: {db.collar.shape}")
        print(db.collar.describe())

        # 6. 样长组合示例
        print("\n" + "=" * 40)
        print("样长组合处理")
        print("=" * 40)
        params = SampleLengthCombineParam(
            input_file="C:/Projects/Mine/样品数据.dmf",
            combine_length=1.0,
            combine_percent=1.0,
            output_file="C:/Projects/Mine/组合后样品.dmf",
        )
        result = db.process_samples(params)
        print(f"处理结果: {result}")


if __name__ == "__main__":
    main()

示例二:从 DataFrame 创建新的钻孔数据库

import pandas as pd
from dimine_python_sdk.lib.prospecting import DrillDBManager


def create_drill_db():
    # 1. 创建空对象
    db = DrillDBManager()

    # 2. 准备孔口表
    df_collar = pd.DataFrame({
        "工程号": ["ZK001", "ZK002", "ZK003"],
        "横坐标": [100.0, 200.0, 300.0],
        "纵坐标": [400.0, 500.0, 600.0],
        "高程": [700.0, 750.0, 800.0],
        "总深度": [150.0, 200.0, 180.0],
        "勘探线": ["L1", "L2", "L3"],
        "其他": ["备注1", "备注2", "备注3"],
    })

    # 3. 准备测斜表
    df_survey = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002", "ZK002"],
        "测斜深度": [0.0, 50.0, 0.0, 80.0],
        "方位角": [30.0, 32.0, 45.0, 47.0],
        "倾角": [-60.0, -62.0, -55.0, -58.0],
    })

    # 4. 准备岩性表
    df_lithology = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002"],
        "起始": [0.0, 50.0, 0.0],
        "结束": [50.0, 150.0, 200.0],
        "岩性编号": ["花岗岩", "砂岩", "页岩"],
    })

    # 5. 准备样品表(可选)
    df_sample = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002"],
        "样本编号": ["S001", "S002", "S003"],
        "起始": [0.0, 50.0, 0.0],
        "结束": [50.0, 100.0, 80.0],
    })

    # 6. 赋值到数据库
    db.collar = df_collar
    db.survey = df_survey
    db.lithology = df_lithology
    db.sample = df_sample

    # 7. 保存
    db.save("C:/Projects/Mine/新钻孔数据.dmd")
    print("数据库已保存")


if __name__ == "__main__":
    create_drill_db()

示例三:从 CSV 导入数据并保存为钻孔数据库

从外部系统导出的 CSV 文件,通过列名映射转换为标准格式后,可直接保存为 .dmd 钻孔数据库,在 Dimine 中打开使用。

完整代码见 examples/import_csv_to_drill_db.md,核心步骤如下:

import pandas as pd
from dimine_python_sdk.lib.prospecting import DrillDBManager

# 1. 读取外部 CSV,映射为中文标准列名
df_collar = pd.read_csv("raw_collar.csv").rename(columns={
    "HoleID": "工程号",
    "X": "横坐标",
    "Y": "纵坐标",
    "Z": "高程",
    "Depth": "总深度",
    "Line": "勘探线",
})

# 2. 同理导入测斜表、岩性表
df_survey = pd.read_csv("raw_survey.csv").rename(columns={
    "HoleID": "工程号",
    "Depth": "测斜深度",
    "Azimuth": "方位角",
    "Dip": "倾角",
})

df_lithology = pd.read_csv("raw_lithology.csv").rename(columns={
    "HoleID": "工程号",
    "From": "起始",
    "To": "结束",
    "Rock": "岩性编号",
})

# 3. 赋值并保存
db = DrillDBManager()
db.collar = df_collar
db.survey = df_survey
db.lithology = df_lithology

db.save("钻孔数据.dmd")
print("已保存为钻孔数据库,可在 Dimine 中直接打开")