最近遇到一个需求是需要将客户提供的csv或者excel,按照某个字段进行分类然后转换为简单的分类符号,即csv里有对应的名字和颜色,需要把这些转化为qml。由于QGIS里可以使用python脚本,所以直接使用pyrhon去处理。在这里以面符号为例,点线面原理相同
1
首先随便加载一个客户的面数据
2
然后打开qgis python控制台,把如下代码粘进去
python
from qgis.core import QgsProject, QgsVectorLayer, QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol
import math
import chardet # 用于检测文件编码
# ===== 配置参数 (根据实际情况修改这些值) =====
# 面图层的名称(在QGIS图层面板中显示的名称)
polygon_layer_name = "岩体"
# CSV文件的路径(确保已导出为CSV格式)
csv_path = "C:/D/Dev/project/dzsjk/其它/长大符号/V2/土体merge.csv" # 请确认路径正确
# 输出QML文件的路径
output_qml_path = "C:/D/Dev/project/dzsjk/其它/长大符号/V2/土体一万.qml"
# CSV中的字段名称配置
label_field = "label" # 编码字段名
name_field = "名称" # 图例名称字段名
r_field = "R" # 红色字段名
g_field = "G" # 绿色字段名
b_field = "B" # 蓝色字段名
# ===== 主程序开始 =====
# 获取面图层
polygon_layer = QgsProject.instance().mapLayersByName(polygon_layer_name)
if not polygon_layer:
raise ValueError(f"找不到图层: {polygon_layer_name}")
polygon_layer = polygon_layer[0]
# 创建分类列表
categories = []
# 检测文件编码
with open(csv_path, 'rb') as f:
raw_data = f.read()
encoding_detection = chardet.detect(raw_data)
file_encoding = encoding_detection['encoding'] or 'gbk' # 默认使用gbk
print(f"检测到文件编码: {file_encoding} (置信度: {encoding_detection['confidence']})")
# 读取CSV数据
with open(csv_path, 'r', encoding=file_encoding, errors='ignore') as f:
# 读取所有行
lines = f.readlines()
# 如果第一行有BOM标记,则移除
if lines and lines[0].startswith('\ufeff'):
lines[0] = lines[0][1:]
# 获取字段行
headers = lines[0].strip().split(',')
print(f"CSV头部字段: {headers}")
# 获取字段索引
try:
label_idx = headers.index(label_field)
name_idx = headers.index(name_field)
r_idx = headers.index(r_field)
g_idx = headers.index(g_field)
b_idx = headers.index(b_field)
except ValueError as e:
print(f"错误: CSV文件中缺少必要字段: {str(e)}")
print(f"可用字段: {headers}")
raise
print(f"找到 {len(lines)-1} 条颜色记录")
# 处理数据行
for i, line in enumerate(lines[1:]):
# 清理行并分割字段
cleaned_line = line.strip().replace('\ufeff', '')
parts = cleaned_line.split(',')
# 确保有足够字段
if len(parts) < max(label_idx, name_idx, r_idx, g_idx, b_idx) + 1:
print(f"跳过第 {i+2} 行: 字段不足 ({len(parts)}/{max(label_idx, name_idx, r_idx, g_idx, b_idx) + 1})")
continue
label = parts[label_idx].strip()
name_value = parts[name_idx].strip()
print(f"处理记录 {i+1}: label={label}, name={name_value}")
try:
# 尝试解析RGB值
r_val = parts[r_idx].strip()
g_val = parts[g_idx].strip()
b_val = parts[b_idx].strip()
# 转换RGB值为浮点数
r_float = float(r_val)
g_float = float(g_val)
b_float = float(b_val)
# 浮点数转整数 (四舍五入)
r = math.floor(r_float + 0.5)
g = math.floor(g_float + 0.5)
b = math.floor(b_float + 0.5)
# 确保RGB值在0-255范围内
r = max(0, min(255, r))
g = max(0, min(255, g))
b = max(0, min(255, b))
# 创建RGB颜色字符串
color_rgb = f"{int(r)},{int(g)},{int(b)}"
# 创建符号
symbol = QgsFillSymbol.createSimple({
'color': color_rgb,
'color_border': '0,0,0', # 黑色边框
'width_border': '0.26', # 边框宽度
'style': 'solid', # 实心填充
'style_border': 'solid' # 实线边框
})
# 创建分类 - 使用名称字段作为图例标签
category = QgsRendererCategory(label, symbol, name_value)
categories.append(category)
print(f"添加分类: {label} ({name_value}) -> RGB({r}, {g}, {b})")
except (ValueError, TypeError) as e:
print(f"无效的RGB值: 行 {i+2} - label={label}, R={r_val}, G={g_val}, B={b_val}")
print(f"错误详情: {str(e)}")
# 检查是否找到有效分类
if not categories:
raise ValueError("未创建任何有效分类,请检查数据和字段名")
# 创建分类渲染器
renderer = QgsCategorizedSymbolRenderer(label_field, categories)
polygon_layer.setRenderer(renderer)
# 刷新地图
polygon_layer.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(polygon_layer.id())
# 导出QML文件
success = polygon_layer.saveNamedStyle(output_qml_path)
print("="*50)
if success:
print(f"成功导出QML文件: {output_qml_path}")
else:
print(f"导出QML文件失败,请检查写入权限和路径")
print(f"处理了 {len(categories)} 个有效分类")
print("图例标签使用字段: " + name_field)
print("="*50)
一定要注意,这个代码是根据下面的csv字段配置的,大家使用代码一定要结合自己的csv再去修改,同时注意要把路径修改为自己的,csv字段如下:
需要按照label字段进行分类,然后图例就是名称字段
3
复制完之后再去运行,最后就得到了自己想要的qml
