Skip to content

数据库操作

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

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


模块定位

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

模块 用途 典型类
lib.db 数据库/数据表业务封装 DmDbDatabaseDmDbLayerDmDataTableTableRow
models 对外 Pydantic 纯数据模型 PointLineShell

本文档覆盖 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)

DmDataTablelib.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 中直接打开")