数据库操作
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 中直接打开")