简单地图绘制
出随报告交付的单项目成果图,图种可切换。版式、配色、字号逐项照参考图复刻(参考图为某县生态环境管控单元分布图,随项目更换,照录不照抄地域)。
本技能为通用版:不绑定任何省份、单位、本机路径;涉及具体地域/单位的内容一律由用户当次提供。
> 合规声明:本技能仅作学习研究使用,不作任何商业用途。
> - 本技能为免费、非营利的学习研究工具,禁止用于任何商业目的(含职务对外交付、第三方项目投标、直接或间接获利)。
> - 行政界线数据来自 DataV.GeoAtlas(归属高德开放平台,声明"仅供学习交流使用"),卫星影像默认使用 Esri World Imagery(声明不得商用);上述数据源仅限个人学习 / 研究 / 内部参考,使用者须自行遵守其官方条款。
> - 运行时会将 DataV 行政界线数据缓存至本地 admin_cache 目录;高德开放平台条款禁止缓存 / 抓取服务内部数据,使用者应知晓并自担合规责任。
> - 法人(企业 / 事业单位 / 政府部门)将本技能用于职务图件产出,须自行取得数据源方授权或自备合规数据。
> - 含国界 / 行政界线的图件对外发布,须遵守《地图管理条例》履行地图审核(审图号);本技能默认不绘国界。
> - 本技能不内置任何地图服务密钥;天地图影像须使用者自备 --imagery-key,合规责任由使用者自负。
〇、制图区域与主体:由用户语义确定(不预设任何区域)
本技能不内置任何"选定区域"。 出图范围与主体一律从用户指令中解析:
| 用户说的 | 解析结果 |
|---|---|
| "XX省 / XX市 / XX县" | --region <名称> 自动解析 adcode,从 DataV.GeoAtlas 加载行政界线,范围 = 边界外接矩形(按 A3 图框比例适配居中) |
| "XX流域 / XX经济带 / XX保护区" | 主体 = 该区域矢量(用户提供或从公开源取),范围同理 |
| "XX校区 / XX园区 / XX矿区 / 项目场地" | 主体 = 用户提供矢量或给定 bbox;无 adcode 也能出 |
| "东经XX—XX、北纬XX—XX" | 主体 = 该 bbox 本身 |
| 只给点位(如"XX项目所在地") | 主体 = 点周边缓冲(默认按出图尺度给合适跨度,需向用户确认跨度) |
- 解析不出主体时,必须回问,不许自行假定一个省/市去画。
- 中央经线
cm = round(主体经度/3)×3、EPSG 由 pyproj 查询——都是跟着主体走的,没有固定带号、没有固定行政区划代码。 - 数据文件名一律用占位符(
<主体行政代码>.json/<主体>_full.json/<主体>_county.geojson),禁止写死任何具体代码或数量。
完整量测表见references/制图规范_两类参考图解析.md;成册图集类图件请改用生态环境分区管控制图技能。
一、硬性口径(不可改)
> 本技能的几何/配色/字体已按《"三线一单"图件制图规范(试行修订版)》校核并改造(2026-09-12)。
> 规范优先于旧参考图;仅制图单位口径保留本单位要求(不改),交通要素列为可叠加要素(后续由用户上传)。
- 画布 A3 横版 300 dpi = 4961×3508 px;
MM2PX = 300/25.4 = 11.811。(规范 4.1 指定 A3) - 椭球统一 CGCS2000;投影默认高斯-克吕格 3度带(规范 4.2),但可按需求切换(见下表,脚本参数
--proj)。 --cm中央经线可自定义输入(用户给了就用用户的,不给才自动算)。- 默认自动值:3度带
cm = round(主体经度 / 3) × 3;6度带cm = round(主体经度 / 6) × 6;
UTM 带号zone = floor((经度+180)/6)+1。 - EPSG 码一律由 pyproj 查询确认,禁止硬编码映射表(不同 PROJ 版本的编码段并不一致,写死必错)。
--proj |
投影 | 必给参数 | 适用 |
|---|---|---|---|
gk3(默认) |
高斯-克吕格 3度带 | --cm(可省,自动) |
大中比例尺、规范默认 |
gk6 |
高斯-克吕格 6度带 | --cm |
小比例尺 |
utm |
UTM 6度带 | --cm 或 --zone |
国际合作/涉外项目 |
albers |
Albers 等积圆锥 | --lat1 --lat2(双标准纬线)+ --cm |
面积统计、全国/省域 |
lcc |
Lambert 等角圆锥 | --lat1 --lat2 + --cm |
中纬度东西延展区 |
mercator |
墨卡托 | — | 仅示意图/网络底图,正式图禁用 |
| - 禁用不投影(EPSG:4490 直绘经纬差);墨卡托除示意图外不得用于正式成果。 | |||
- 标准纬线未给时,按图幅纬度跨度取 lat1 = minlat + span/6、lat2 = maxlat − span/6(Albers/LCC)。 |
|||
- 分辨率 / 纸张可自定义:默认 A3 横版 300 dpi = 4961×3508 px(MM2PX = 300/25.4 = 11.811)。 |
|||
- --dpi(默认 300,印刷 300 / 屏幕 96–150 / 大幅面喷绘 150–200)。 |
|||
- --page:a3(420×297mm)/ a4(297×210mm)/ WxHmm 自定义(如 600x400)。 |
|||
- 改 dpi 或纸张,字号/线宽/图框常量全部按 MM2PX 重算,不要改 mm 值。 |
|||
| - 坐标注记必须落图:在图幅内空白处(默认左下角,白底细边框)标注 | |||
坐标系 / 投影 / 中央经线(含"随区域自动"或"用户指定"标识)/ 标准纬线(Albers·LCC)/ false easting / EPSG。 |
|||
| 图件要能被复核,没有坐标注记的成果图视为不完整。 | |||
- EPSG 查询结论(实测 pyproj 3.8):自制 proj4 串 to_epsg() 一律返回 None(PROJ 不做反向模糊匹配), |
|||
| 必须查 EPSG 数据库按名称匹配。CGCS2000 3度带存在两套编码,勿混用: | |||
| 中央经线 | zone 命名 | CM 命名(本脚本采用) | |
| --- | --- | --- | |
| 111°E | 4525(zone 37) | 4546 | |
| 114°E | 4526(zone 38) | 4547 | |
| 117°E | 4527(zone 39) | 4548 | |
| > ⚠️ 旧版技能写的「111°E → EPSG:4534」是错的(4534 对应 138°E)。这正是禁止硬编码的理由。 | |||
UTM/Albers/LCC 在 CGCS2000 下常无标准条目,查不到就如实标 EPSG:自定义 并附 proj4 串。 |
|||
| - 指北针 统一传统样式:N 字(常规粗细)+ 左右分瓣箭头(左瓣实心黑 / 右瓣白底黑描边,中轴凹口在全高 65% 处,无外圈)。禁用风玫瑰。 | |||
| - 位置:竖栏顶部居中(照参考图;参考图该处若是气象玫瑰图则禁用,改用本传统指北针符号)。 | |||
- 凹口比例以常量 ARROW_NOTCH = 0.65 为准(几何表内 COMPASS_PROJ 同值)。 |
|||
| - 图名 / 制图单位均非必填,由用户当次提供(不设任何必填门禁): | |||
| - 提供了 → 照录,不得简写、不得改括注;未提供 → 图名置空、不落款,不阻塞出图。 | |||
- 制图单位格式:框外右下单行右对齐,只写单位名称、不写"制图单位"四个字,颜色中性灰 (140,140,140),位于框底 288.33mm 下方约 2.6mm 留白带。 |
|||
- 管控单元三色固定(规范附录V):优先保护 #4DE602、重点管控 #F57A7A、一般管控 #F6EBAB。 |
|||
- 水系 #2DB4FF(规范附录A):默认不绘,与交通要素 / 叠加矢量同级 —— 仅用户明确要求才绘;指令含糊时按不绘处理。 |
|||
- 默认底图为卫星影像图(--kind image,真彩色 Esri World Imagery): |
|||
| 影像本身即底图,不要求晕渲占比,纯影像底不判缺陷。 | |||
| - 绿色系地形晕渲(28%–33% 占比、纯白/灰白底判缺陷、禁止交付)仅适用于晕渲类图种: | |||
elevation / hillshade / hypsometric / schematic。晕渲缺失是晕渲类成图“看着空”的第一主因。 |
|||
- 行政区划图(admin)默认「不使用底图」,直接纯白(--base plain,PLAIN_RGB=(255,255,255)): |
|||
| 主体是界线分级 + 四色填充 + 驻点注记,白底即预期形态;不下载任何瓦片,零第三方数据依赖。 | |||
需要底图时才切换:--base shade 浅绿灰 + 极淡晕渲、--base image 影像; |
|||
白底不适用“纯白判缺陷”(该口径属生态环境分区管控技能场景),plain 分支只校验底色均匀(标准差 ≤1); |
|||
单元默认按地图四色原理填充(柔和配色 + 20% 透明,--fill-colors / --fill-alpha / --no-fill 可控)。 |
|||
| - 行政界线分级自动渲染(规范附录A:统一黑色 RGB(0,0,0),按线宽分级): | |||
| - 线宽(mm):国界 0.6 / 省界 0.5 / 市界 0.4 / 区县界 0.3 / 乡镇界 0.2;再按比例尺自适应系数(0.8–1.2,以 1:25 万为基准,小比例尺略细、大比例尺略粗)。 | |||
| - 按图幅跨度自动选择级别(跨度门槛 km):国界 ≥500;省界 不限;市界 ≤1500;区县界 ≤400;乡镇界 ≤150。实测:山东省 938km→国界/省界/市界;青岛市 234km→市界/区县界;即墨区 109km→区县界。 | |||
- 主题区(用户指定,如青岛市)轮廓加粗:THEME_MM=0.9,并在轮廓线外侧渲染白边(描边),白边厚度 HALO_MM=1.0 mm 为固定值,不随比例尺变化。 |
|||
| 白边只在轮廓外侧(09-19 用户要求「轮廓线内侧的描边取消」):实现上白边先画进独立图层,再把主题区外环内部擦成全透明后合成 —— 内侧不会留下一条发白的内衬压住四色填充。(不要直接在主图层上擦,否则会连填充与地市界一起擦掉。) | |||
- 乡镇界数据限制:DataV.GeoAtlas 只到区县一级,区县 _full 返回 404,故乡镇界仅在有数据时才绘制(当前自动跳过)。 |
|||
| - 图例与注记版式: | |||
- 底图不设图例:卫星影像 / 地形晕渲 / 示意底图均不占图例项;其数据源改在图例框最下方注记中说明(字号 NOTE_INK=22 px@300dpi,较原放大)。 |
|||
| - 数据源 / 坐标系注记位置:已由竖栏左上移至图例框最下方,底对齐距图框底 3mm,自动换行,不得溢出图框。 | |||
| - 图例文字自动换行:按可用宽度逐字符贪心换行,长标注不溢出线框;条目过多时自动压缩行距,保证不溢出。 | |||
| - 指北针 / 比例尺左移:不再挤在右上角,整体左移 5mm(限幅不越过竖栏左线)。 | |||
- 图号(规范 4.5(7)):图幅右下角,黑体 14–24 磅。项目版默认不添加(FIG_NO_PROJECT = None;图集版才有 FIG_NO_ATLAS = "01")。 |
|||
| - 字体规范(规范 4.4/4.5):汉字黑体、标题黑体加粗;经纬度注记宋体;数字 Times New Roman。 | |||
- 比例尺:数字式(1 : N)+ 直线式(km 分段)并列(规范 4.5(3))。N 取真实比例尺(图幅地面跨度反推、取整到千位),不写死任何固定值。 |
|||
> 1 : 2,527,000 仅为某一幅图的实测示例,随图幅变化,禁止照抄。 |
|||
| - 交通要素列为可叠加要素,由用户上传。 | |||
| - 图例条目下限:项目版 ≥8 条、行政区划图 ≥5 条(四色填充不入图例,故等于驻地 + 界线条数)。只列已绘要素,但禁止 1–2 条的简化状态(出现即说明漏绘)。 | |||
| - 数据来源优先级(缺数据时按序找,不可直接放弃或编造): | |||
| 1. 用户提供的矢量/影像 → 2. 工作区已有的同名数据 → 3. 公开渠道获取(须在图面注明来源)→ 4. 以上皆无:明确提示用户上传,不要静默出空图。 |
一之二、出图方式:默认脚本直连(PIL)
| 路线一 · 脚本直连 PIL(默认) | 路线二 · QGIS(PyQGIS headless) | |
|---|---|---|
| 脚本 | make_admin_script.py |
make_admin_qgis.py |
| 依赖 | 只 Python + pillow/numpy/requests | 本机装 QGIS,须用 apps\Python312\python.exe |
| 速度 | 约 20 s / 版 | 约 5–6 s + QGIS 启动约 2.6 s |
| 图框 | 与 QGIS 版逐像素一致(同一 build_frame_overlay) |
同 |
| 适用 | 随报告交付的单项目图(默认场景) | 要接 QGIS 现有工程/图层样式,或甲方指定 |
默认规则:用户没点名软件,一律走路线一(脚本直连)。
依据:compose_admin.py 优先读取脚本版产物 admin_project_base.png,缺失才退回 admin_project_qgis_map.png。
两路线共用同一图框覆盖层,图框/指北针/图例/比例尺完全一致,差异只在地图窗口渲染管线。
没装 QGIS 怎么办(已做优雅降级)
make_admin_qgis.py 入口会先探测 QGIS(QGIS_PREFIX_PATH → 常见安装位置 <盘符>:\Program Files\QGIS* / <盘符>:\OSGeo4W\apps\qgis*),探测不到就打印提示并 sys.exit(2),不抛 ImportError 堆栈。此时改走脚本直连即可,出图同源同框。
判断规则:要求"用 QGIS 出图" ≠ 本机必须有 QGIS。本机未装就直接说明并走脚本直连;确需 QGIS 参与,才在目标机装好后用其自带 apps\Python312\python.exe 跑。
两路线的坐标系必须一致(曾出过事故)
QGIS 路线必须 project.setCrs(<本幅 GK 3度带的 EPSG 码>)(由 pyproj 按动态选定的中央经线查询得到)+ setEllipsoid("EPSG:7019"),不得用 EPSG:3857(墨卡托)或 EPSG:4490(不投影)。QGIS 用错了坐标系而图框按高斯坐标画,会造成「图上地物位置」与「分度带注记」系统性错位——用户看到的就是"经纬度标错了"。
二、项目版几何(照参考图 B 在 A3 420mm 口径重新量测)
| 元素 | 取值 |
|---|---|
| 页面 | A3 横版 420×297 mm = 4961×3508 px |
| 外框 | 左 19.91 / 顶 14.9 / 右 400.12 / 底 288.33 mm(上下留白,不是边到边) |
| 标题带 | 底边 BY1 = 35.0 mm,底色 #F1F1F1,居中单标题 |
竖栏左线 PX0 |
339.9 mm;竖栏宽 60.1 mm(右界 = 外框右线 400.12) |
| 分度带 | 3.55 mm —— 外图廓与内图廓之间的白色留白 |
| 内图廓 | 细灰线 (135,135,135);左 23.46 / 顶 38.55 / 右 396.57 / 底 284.78 mm |
| 地图窗口 | 约 313.3×239.6 mm |
| 指北针 | 竖栏顶部居中(cx = (PX0+FX1)/2 = 370.0;VPOS.PER_VERSION["project"]:N_CY=5.2 / ARROW_T=10.2) |
| 指北针尺寸 | COMPASS_PROJ = dict(N_INK=72, ARROW_H=15.2, ARROW_HW=4.45, ARROW_NOTCH=0.65)(≈ 图集版 0.78 倍) |
| 比例尺 | 紧随指北针下方(NUM_CY=34.6 / BAR_T=37.4 / RATIO_CY=48.0);条成品长 44 mm(segs=[11,11,22],刻度 0/25/50/100 km)、条高 3.0 mm;SCALE_INK_PROJ = dict(num=43, ratio=53) |
| 比例尺条样式 | 双层黑白(上下同分格·反色)(2026-09-13 用户要求,与图集版同款):整条高度均分上/下两层,两层分格线完全对齐(共用同一组 xs),颜色逐格相反 —— 下层起黑(黑/白/黑)、上层起白(白/黑/白)。逐格 outline + 整条外框。⚠️ 不要把上层再对半分(会与下层格线错位,用户已指出「上下两层错位了」)。 |
| 分格线(竖栏内) | 相对 BY1=35.0 偏移:DIV1=51.0(比例尺|图例);底框线 288.33 |
| 图例 | 条目墨迹较小、行距较紧;文字-符号间距 txt = 18.6 mm |
| 图号 | 默认不添加(FIG_NO_PROJECT = None)。项目成果图不带图集序号 —— 2026-09-13 用户要求。 |
| 制图单位 | 框外右下:右对齐至 FX1-2mm,位于框底 288.33mm 下方约 2.6mm 的留白带,不压地图 |
| 日期 / 页码 | 无 |
> 2026-09-13 修正要点:外框右线由 399.9 → 400.12、底框线由 281.8 → 288.33(实测参考B)。
> 指北针 / 比例尺此前按 0.72 倍缩小被用户反馈"太小",已放大到 0.78 倍并将 segs 改为成品 mm
> (原按 km/SCALE 换算只有 28.6 mm)。
三、经纬度(项目版专属做法,与图集版不同)
写在外图廓与内图廓之间的白色分度带内,四边都有:
- 上 / 下:经度,横排;左 / 右:纬度,竖排(旋转 90°,自下而上读)。
- 间隔 30′(0.5°),格式 度分不带秒:110° / 110°30'。
- 颜色灰 (115,115,115),墨迹高约 1.1 mm,注记中心距分度带外缘 1.45 mm。
- 贴内图廓一侧带 1.05 mm 短刻度。
- 图内不画任何十字、不画经纬网(图集版才画十字)——这是两版最易混的差异。
- 投影改造后经纬线在 GK 平面内是曲线,交点需用 gk_forward/gk_inverse 求解(_line_x_at_lat / _px_of_gk)。
四、用户已提过的易错点(出图前逐条自查)
- 地图里有出图单位 → 落款必须在框外右下的留白带,不能压在地图框上。
- 上下留白与参考图不一致 → 必须 10.5 / 199.2 mm,不能沿用图集版的边到边。
- 落款写了"制图单位"四字 / 颜色太重 → 去掉四字,改中性灰。
- 比例尺"有点胖" / "太小" → 条高严格按
bar_h(图集 3.7mm / 项目 3.0mm),条长给成品 mm(44 mm),不要按真实 km 换算。 - 地图里有出图单位 → 落款必须在框外右下的留白带。
- 地市名称跑出市域 → 用 polylabel 取市域内代表点,逐级收字号试放,整框四角须落在市域内(现有实现 16/16 通过)。
- 漏了经纬度 / 方式与参考图不符 → 见第三节(分度带内、30′、无秒、四边、图内无十字)。
- 图外围少了一圈留白 → 补 3.55 mm 分度带 + 细灰内图廓。
四之二、叠加用户矢量(overlays.json,opt-in)
工作区放 overlays.json 即自动叠加;没有该文件时行为完全不变,图框自检不受影响。
模板见 overlays.example.json(另存为 overlays.json 生效)。
{
"layers": [{
"file": "uploads/管控单元.shp.zip",
"label": "管控单元",
"alpha": 170, "stroke": "#666666", "width": 2,
"color_by": { "field": "类型", "map": {
"优先保护": "#4DE602", "重点管控": "#F57A7A", "一般管控": "#F6EBAB" }}
}]
}
- 支持的文件类型(三选一,写进
file即可):
| 类型 | 写法 | 说明 |
|---|---|---|
| Shapefile 压缩包 |管控单元.shp.zip/.rar| 推荐。自动解压找 shp,允许带子目录、允许一包多套 |
| 单个.shp|units.shp| 要求.shx/.dbf/.prj同目录同名 |
| GeoJSON |units.geojson/.json| 直接读 | - zip 用标准库解;rar 需本机有 WinRAR/7-Zip,没有则抛可读提示(建议改 zip),不崩栈。
- 解压落在工作区
uploads/<包名>/;转换成果另存<名>_cgcs2000.geojson,下次会跳过不重复读入。 - 坐标系自动转换(
overlay_ingest.py,依赖 pyproj + pyshp,不需要 QGIS/GDAL):
| 情形 | 处理 |
|---|---|
| 有.prj/ GeoJSONcrs声明 | 用 pyproj 精确转换到 CGCS2000(EPSG:4490)。任意 PROJ 可识别坐标系:3°带 EPSG:4513-4554、UTM、Web Mercator 3857、WGS84… |
| 无声明 + 坐标是米级大数 | 自动试算 3°带/UTM/墨卡托,取落在制图主体范围内的那个 |
| 无声明 + 坐标已是度 | 直接采用(WGS84 与 CGCS2000 图上差异可忽略) | - 带号不可唯一确定是数学事实:无
.prj的投影坐标,相邻带号可能都映射进省域。此时会打印!!!告警列出所有候选并标注「不确定,待核对」,不假装确定。要消除歧义就让源数据补.prj。 - 路径支持
base_dir(相对路径基准目录),不写默认工作区。 - 几何自动识别:面 / 线 / 点;QGIS 路线按几何类型选 Fill/Line/Marker 符号。
color_by按属性分色,并为每个取值各出一条图例行(管控单元三色用它)。- 分色对面/线/点一体生效:设了
color_by就一律按属性值着色,point_color仅在未设color_by时兜底(保证图例与图面永远一致)。 - 绘制顺序:省界之上、注记之下 → 市名不会被盖。
- 图例自动追加在标准条目之后。
- 已实测(投影坐标点 + zip 包,4 点按
类型分色):取样 RGB 分别为(147,239,99)优先保护 /(247,173,173)重点管控 /(243,238,197)一般管控,4/4 命中,图例多出 3 行。
> 上述 RGB 为某一带(原 111°E 带)的取样示例,换带后数值会变,判定以「三色是否与图例条目一一对应」为准,不照抄取样值。
五、自动加载行政界线(--region)
当用户指令中出现具体省/市/县名称(如"山东省地形图""青岛市范围""即墨区"),必须自动加载行政区界线:
- 调用 make_terrain.py --region <名称>,脚本通过 DataV.GeoAtlas 自动解析 adcode、下载边界。
- 界线统一黑色、按等级分线宽、并按图幅跨度自动选级(见「六」;国界默认不绘);主题区轮廓加粗 0.9 mm 并外套 1.0 mm 固定白边(厚度不随比例尺变化),白边默认 30% 透明(--halo-trans,让底图透出)。
- 自动标注各级政府驻点(见「六之四」):级别随跨度联动升降,点状符号 + 分级注记。
- 范围以行政边界外接矩形为基准,按 A3 图框比例适配居中,避免二次大幅外扩。
- 支持省(province)、市(city)、县/区(district)三级;解析失败时改用 6 位 adcode。
五之二、坐标系与比例尺(关键坑)
- 投影后无形变:高斯-克吕格 3度带,东西/南北同尺度 1:1。旧版经纬度直绘的 1.162 倍拉伸已随投影改造消除。
- 比例尺:主体自动适配 + 居中(2026-09-13 用户要求,现行做法)
- 规则:图件主体(省界外接矩形)位于图框(=经纬网覆盖范围)正中间,其外接矩形的宽或高至少一轴占图框 95%(一轴到 95% 即可)。
- 实现:
admin_common.FILL_TARGET = 0.95+subject_bbox_m(clip)+compute_extent(g)自动求解(取较紧一轴顶到 95%,另一轴按窗口比例自然给出,保持等比不拉伸,中心对齐主体外接矩形中心)。 SCALE = 3,500,000降级为「名义比例尺」,仅作compute_extent兜底(取不到主体时)。- 数字比例尺标「真实比例尺」(由图幅地面跨度反推、取整到千位)。不要再写死 1:3,500,000,也不要凑整到 1:2.5M。
>1 : 2,527,000(图幅 790.8×622.2 km,主体占比 宽 95.0% / 高 75.2%)仅为某一幅的实测示例,随图幅变化,禁止照抄。 - 直线比例尺条长仍按成品 mm 给(44 mm),刻度值如实标 0/25/50/100 km(不按真实比例尺换算)。
- 自检:
qa_check.py frame第 7 项「主体 95% 适配 / 主体居中」纯几何判定:至少一轴占比 ∈ [0.94,0.96]、中心偏移 ≤0.5%。 - 比例尺条为双层黑白(2026-09-13):
bh/2分上下两半,两层共用同一组xs分格,i%2决定颜色且上下相反(下起黑 / 上起白),逐格outline+ 整条外框。⚠️ 不要上层再对半分(会与下层错位)。 - 图号默认不添加:
FIG_NO_PROJECT = None(图集版FIG_NO_ATLAS="01")。绘制处按version取。 - 底图晕渲必须重投影:瓦片源是 WebMercator,目标是 GK;按「目标像素 → GK 反算经纬度 → 源墨卡托像素」重采样(二维网格
_gk_inverse_np+_np.repeat),否则错位数十 km。 - 导出 GeoTIFF 时世界文件必须写对名字(踩过坑):GDAL/QGIS 的优先级是
① <name>.tif.aux.xml→② <name>.tifw→③ <name>.tfw;只写.tfw会被旧侧车抢先(如早期墨卡托版残留的.tif.aux.xml),QGIS 遂按墨卡托解释该投影栅格 → 整幅上下翻转。正确:内嵌 GeoTIFF 标签(投影 GeoKey,EPSG 取本幅动态选定的带号)+ 同时写.tfw与.tifw+ 删旧.tif.aux.xml。 - Pillow 写内嵌标签必须传数值元组(
ifd[33550] = (A, abs(E), 0.0))才会写成 DOUBLE/SHORT;传 bytes 会变 BYTE(1),GDAL 解析失败并退回像素坐标(地图挪到图外)。世界文件单位是米。 - 不要写 34737 GeoAsciiParamsTag:Pillow 写入尾随 NUL,GDAL 报 "contains null byte" 后弃用整套 GeoKey。
- 校验:QGIS 读该栅格应得
crs=<本幅 GK 带 EPSG>且 extent 等于compute_extent()返回值。 - 项目版图幅(GK 米):以
compute_extent()返回的 xmin/xmax/ymin/ymax 为准,制图主体完整落入。
六、行政边界按尺度选取(规范附录A:统一黑色、按线宽分级)
统一黑色、按线宽分级(不用红/灰配色);白色套衬仅用于影像底图(否则暗底上黑线不可辨,浅色底不加),常量 LEVEL_MM / LEVEL_SPAN / LEVEL_NAME / CASING_MM:
| 级别 | 图例名 | 线宽(mm) | 显示跨度门槛 |
|---|---|---|---|
country |
国界 | 0.6 | ≥500 km(默认不绘) |
province |
省界 | 0.5 | 恒绘 |
city |
地市界 | 0.4 | ≤1500 km |
district |
区县界 | 0.3 | ≤400 km |
town |
乡镇界 | 0.2 | ≤150 km |
- 线宽再乘比例尺自适应系数
sc_f ∈ [0.8, 1.2](以 1:25 万为基准,小比例尺略细、大比例尺略粗)。 - 图例名即上表;旧称「市界」已统一改为「地市界」。
- 国界默认不绘(09-19 用户要求):
DRAW_COUNTRY = False,脚本不下载也不绘制100000国界图层;需显式加--draw-country才绘。理由:国界表示敏感,图件对外分发涉及审图要求。 - 实测(山东省,跨度 938 km):默认为「省界/地市界」,加
--draw-country恢复「国界/省界/地市界」;两次成图差异掩膜 IoU = 1.0000(差异正是国界那 24,631 px,占图面 0.142%),完全可逆。 - 无副作用:北京市/青岛市/即墨区(跨度 <500 km,本就不绘国界)重跑后与改动前逐像素一致(0 px 差异)。
town级 DataV.GeoAtlas 无数据(各区县_full实测全部 404),脚本自动跳过且不报错;要出乡镇界须换专用数据源。- BYO 模式的本级轮廓自身即一级界线,必须并入绘制层:否则该级别不进图例,且以
drawn_levels过滤的驻点会把该级驻点(如「省会」)误删(详见「十」)。 - 图层级别取自要素自带
properties.level(_layer_level()),因此直辖市下属区县归为「区县界」而非「地市界」。 - 用户指定主题区时,该区轮廓独立加粗(
THEME_MM=0.9)+ 固定白边(HALO_MM=1.0),图例为「XX(主题区轮廓)」。
六之二、图层要素只显示于图幅范围内 + 出图前底图自检(强制)
一、裁剪(强制):所有图层要素(叠加矢量、行政界线、主题区轮廓、点位标注)一律只显示在内图廓(图幅矩形)范围内,图幅外不落任何墨迹。两级保险:
1. 几何级:折线按 Liang–Barsky 裁剪到图幅矩形(clip_polyline),完全在图幅外的要素直接跳过 —— 解决"周边同级行政区(如山东其他地市)界线画满整页"的问题。
2. 像素级:矢量统一画进独立透明图层,最后只把图幅矩形内的像素合成回图面(crop + paste),连粗描边(如主题区白边)的溢出部分一并裁掉。
- 回归脚本 scripts/test_clip.py(7 项断言,含"图幅内必须落墨"防误裁)。
二、出图前底图自检(强制,默认开启):make_terrain.py 在写文件之前对底图体检,未通过即中止出图(exit 2),绝不产出拉伸/异常的图件。
- 判废项(✗):纵横比拉伸(x/y 每像素地面米数相对偏差 >3%);瓦片覆盖不足(>0.5% 采样点落在瓦片网格边缘,会重复采样成条带);瓦片缺失 >15%;影像空白区 >1%(底色 250,250,250);整体均值 <8 或 >248;重复采样条带(最长连续相同行 >5% 图高);高程栅格含 NaN/Inf。
- 提示项(!):少量瓦片未取到、输出分辨率高于影像原生分辨率(画面发糊,建议降 --zoom)。
- 防误杀:晕渲类图种不做"空白/条带"判定(海面、平地本就恒色)。
- 条带根治:瓦片范围按投影图幅矩形四边反算经纬度(四边各 64 点)再外扩 1 圈取瓦片。按原始经纬度 bbox 取瓦片时,图幅矩形四角会落到网格外被 clip 成重复采样——这是条带的根因。
- 调试需强制出图时加 --no-qa。
- 回归脚本 scripts/test_qa.py(9 个用例,含"晕渲海面恒色应通过"防误杀)。
- 回归脚本 scripts/test_color.py(10 项:四色填充着色 —— 含 K5 非平面情形下"如实失败"、逐级试探的最少色性质、调色板不足时如实报错;纯合成数据)。
三、面数据共用与两级缓存(性能,09-19):界线、白套衬、主题区轮廓、四色填充、驻点吃的是同一份面数据。
- 此前各读一次盘 + 各解析一次 JSON,且「白边 + 轮廓」「套衬 + 黑线」对同一批顶点重复做 pyproj 逐点变换 ——
实测一次出图读盘 11 次 / 投影 6 次。
- 现有两级缓存:load_geojson_cached()(同路径只解析一次)+ _geojson_polylines()(同路径 + 同变换参数只投影一次);
实测降到 实读 2 个文件 / 复用 5 次;投影实算 2 次 / 复用 4 次(脚本收尾会打印该行,可直接复核)。
- 收益:墙钟 6.59 s → 6.43 s(约 2.4%);输出逐像素完全一致(0 px 差异),属纯结构优化。
- 本次实测耗时分布(四川省,z9,A3@300 dpi,cProfile):
| 项 | 耗时 | 占比 |
|---|---|---|
| pyproj 变换(含输出网格约 1,000 万点的反投影) | 1.59 s | 27% |
PNG 编码(ImagingEncoder.encode) |
0.98 s | 17% |
main 内联数组运算 |
0.77 s | 13% |
ink_bbox 墨迹量测(148 次) |
0.37 s | 6% |
| 磁盘读(含瓦片) | 0.19 s | 3% |
→ 真正的大头是「输出网格反投影」与「PNG 编码」,不是数据加载;数据加载方向再优化也只剩约 0.2 s 空间。
若要继续提速,优先级:① 反投影改「粗网格投影 + 双线性插值」(预计省约 1.2 s,须验证插值误差);
② 出图改 JPEG 或调 PNG 压缩级别(0.98 s);③ ink_bbox 结果缓存(0.37 s)。
六之三、竖栏元素居中(指北针 / 比例尺 / 注记 / 图例标题)
- 居中项(竖栏 = 图例栏,x ∈ [PX0, FX1],中心
cx_col = (PX0+FX1)/2):指北针、比例尺、「图 例」标题。 - 数据源 / 坐标系 / 投影注记 —— 左对齐(09-19 用户要求):左起
PX0+2mm,各行同一起始 x,仍在竖栏线框内(wrap_text按PX0+2mm .. FX1-2mm折行);不再居中。 - 不要再做左移/右移偏移(历史上有过"左移 5mm"的写法,已废弃)。比例尺不得越过
bounds=(PX0+2mm, FX1-2mm),脚本内已限幅。 - 比例尺按「整块墨迹」居中,不是只把条居中:条 44mm + 右端间距 1mm + 单位文字宽,再补偿首尾刻度数字各向外溢出的半个字宽(
left_over/right_over),否则视觉中心会偏 ~0.6mm。 - 图例条目不改:符号列
sym_cx/ 文字列ln0,ln1,txt照参考图 B 实测列式排布,属版式复刻项,不参与居中调整。 - 校验脚本
scripts/check_center.py <图.png>:居中项量墨迹 x 中心与竖栏中心的偏差(阈值 1.5mm,实测 +0.03 / -0.10 / +0.03 mm);注记项逐行量左缘一致性(极差 ≤1.0mm,实测 0.00mm,首行左缘偏差 -0.02mm,右缘距边界余 29.5mm)。
六之四、政府驻点(点状符号 + 分级注记)
触发:范围内涉及多个行政区域时自动标注各级政府驻地(--no-seats 关闭)。数据源 = 界线的 _full 图层要素 properties.center(政府驻地坐标),不额外请求接口;无 center 的要素自动跳过。
级别与符号(SEAT_MM / SEAT_FACE / SEAT_INK)
| 级别 | 图例名 | 符号 | 注记字体 / 字号(px@300) |
|---|---|---|---|
capital |
首都 | 红色五角星 | 微软雅黑 Bold / 58 |
province |
省会 | 红色双圈(环+心) | 黑体 / 53 |
city |
地市 | 红色单圈+心 | 微软雅黑 / 46 |
district |
区县 | 红色空心圈 | 宋体 / 40 |
town |
乡镇 | 红色实心点 | 宋体 / 34 |
- 级别判定:
properties.level == province且adcode == 110000(北京市)→ 首都;其余直辖市(天津/上海/重庆)按「省会」处理。 - 每个符号先铺白色圆底(
halo)、注记加白色描边——保证在卫星影像底图上可读。
级别自动升降(与界线联动,以图面清爽为先)
- 门槛与界线共用 SEAT_SPAN(省会恒显/地市 ≤1500 km/区县 ≤400 km/乡镇 ≤150 km),且只标界线级别里已有的等级。
- 同级过多时保留离图幅中心最近的(SEAT_LV_MAX:区县 26、其余 40);全图总数超 SEAT_TOTAL_MAX=34 时从最低级起逐级舍弃。
- 实测:山东省 938 km → 省会 3 / 地市 15;青岛市 234 km → 地市 2 / 区县 9;即墨区 109 km → 区县 5。
硬约束
- 驻点必须落在图幅内(1.8 mm 内缩),图幅外一律不标注。
- 注记四向试排(右→左→上→下)贪心避让,避免互相压盖与越出图框;四向都放不下则整条舍弃(宁缺勿乱)。
- 舍弃一律打印明细(如 [驻点] 绘制 14 个 / 舍弃 3 个 → 浦东新区(符号占位冲突)、静安区(注记放不下)):
图面少了驻点必须可追溯;MT_SEAT_DEBUG=1 另可逐条打印成功项与像素坐标。
- 同址的上下级驻地只保留高级别(踩过的坑):「山东省」省会与「济南市」、「北京市」首都与「东城区」、「青岛市」与「市北区」的驻地是同一个坐标。若都画,后画者符号的白底圆盘会盖掉先画的符号(位图上表现为符号缺角、计数对不上)。故符号占位与已画符号/注记冲突时整条舍弃,高级别优先(SEAT_ORDER 决定先后)。
- 调试开关 MT_SEAT_DEBUG=1:打印每个驻点的名称/级别/像素坐标、字号 fs= 与注记落点,便于与成图逐点核对。
图例排序(强制,09-19 用户要求)
- 点状组恒在线状组之上;组内行政级别越高越靠上 —— 点组:首都→省会→地市→区县→乡镇;线组:国界→省界→地市界→区县界→乡镇界。
- 非行政级别的点/线排在各组末尾:标注点(点组末)、范围红线 / 主题区轮廓(线组末);专题填充类(高程色带 / 高程渐变)在最上。
- 校验:check_seats.py 打印图例自上而下的「点 / 线 / 块」序列并断言点组全部位于线组之上(实测:青岛/北京「点 点 线 线 线」、山东「点 点 线 线 线 线」、即墨「点 线 线」)。
图上文字与比例尺解耦(强制,09-19 用户要求)
- 图上所有注记字号只与「画布(页面)尺寸 × dpi」有关:FS(px300) = px300 × (dpi/300) × (页宽/420mm)。--page a4 按画布等比缩小;--dpi 只改像素密度,物理尺寸不变。
- 与比例尺完全无关:改 --zoom、图幅跨度、中央经线都不会改变任何字号。比例尺只影响线宽系数 sc_f(0.8–1.2)与比例尺数字本身。
- 注记字号(本轮放大后,px@300dpi):首都 58 / 省会 53 / 地市 46 / 区县 40 / 乡镇 34;--mark 标注文字 30。
- 实测:区县注记在即墨区(1:11 万)与青岛市(1:24 万)均为 fs=43px;地市注记在两幅均为 fs=47px —— 尺度相差 8 倍以上,字号不变。MT_SEAT_DEBUG=1 输出的 fs= 可直接复核。
主题区白边(09-19 用户要求)
- 白边只在轮廓外侧:--base plain 白底下尤其明显 —— 双侧白边会在轮廓内侧压出一条发白的带子,盖住四色填充的边缘。
实现:白边画进独立 RGBA 图层 → 把主题区外环内部擦成全透明 → alpha_composite 合成 → 再画黑色轮廓线。
实测(四川省,白底):差异 175,589 px,其中纯白→填充色 175,584 px(比值 1.00), 即每一处变化都是"内侧白带还原为填充色",外侧白底像素与其它要素零改动。
- 白边默认 30% 透明(HALO_TRANS=30,--halo-trans 0..100 可调):RGBA 图层写 alpha = 255×(1−透明度),合成时按 alpha 与底图混合,底图可透出;轮廓线本身仍为不透明黑。
- 实测(青岛市,透明 30%):白边带 363,928 px,取值 min=178(= 0.7×255,正好是 α=178/255 压在黑底上的结果)、均值 202.2、标准差 10.3 > 0(随底图起伏 → 确为半透明,而非不透明纯白);同一位置改前为纯白 255、标准差 0;轮廓线与各界线的纯黑像素数改前改后完全一致(2,516,591)。白边单侧约 12 px = 1.0 mm,与 HALO_MM 相符。
- 同级统一字号与字面(制图惯例),不逐点缩放。
- 校验脚本 scripts/check_seats.py <图.png>:位图量测 ①符号连通域数 ②每符号附近必有注记墨迹 ③图例驻点符号数 ④符号越界 ⑤图例文字距外框余量 ⑥图框外墨迹。三级实测全过(18 / 11 / 5 个符号,越界 0、缺注记 0、图框外墨迹 0、图例文字距框 8+ mm)。
七、出图流程(顺序不能乱)
- 量测参考图:numpy 像素分析(白边检测、暗线聚类、灰度采样、墨迹高)。
> 环境现象:模型调用返回图片时可能被过滤("Content filtered"),看不了图。 判断必须靠 numpy 数值输出,不要凭"看起来"。 - 设基线 → 换算成 mm → 写进几何常量。
- 按 mm 落位,不用估的坐标。
- 自检(强制):
-qa_check.py frame—— 图框几何自检(project 版竖栏 339.9/400.1mm;含主体 95% 适配 + 居中、图号默认不添加两项,两版式合计 31/31 PASS)。
-qa_check.py content—— 内容自检(与几何并列,缺一不可):底图晕渲像素占比是否落在 28%–33%、图例条数是否满足下限(项目版 ≥8 / 行政区划图 ≥6)、要素是否缺失(管控单元三色、界线分级、经纬度注记)。几何全 PASS 但白底 / 要素缺 → 判 FAIL,禁止交付。
-compare_refs.py—— 与参考图对照。注:项目版参考图是县域大比例尺图,其"分格线 / 图例标题字号"若干项会 FAIL,属参考图自身特性(图幅不同),非缺陷,已加注说明。
-preflight.py—— 门禁,几何有 FAIL 不得出图。
- 底图自检(新,内置) ——make_terrain.py出图前自动体检:拉伸 / 采样越界 / 缺瓦 / 空白 / 条带,任一项判废即中止出图(见「六之二」)。回归测试scripts/test_clip.py、scripts/test_qa.py。 build_montages.py重拼对照图。
八、本机环境坑(照做,别踩)
- 缓存位置(不写技能目录):瓦片缓存与行政区缓存统一放在
MAP_CACHE_DIR>%LOCALAPPDATA%\简单地图绘制\{tiles_cache,admin_cache}(Linux 用XDG_CACHE_HOME,都没有则系统临时目录)。技能目录内不落任何缓存,保证技能包始终干净、可直接打包发布;缓存丢失只导致一次重新下载,不影响出图结果。 - 本机安装位置:技能实体(单源)在
D:\AI\自建skill\<技能名>\;D:\AI\skills\<技能名>是指向实体的 junction,~/.workbuddy/skills又是指向D:\AI\skills的 junction。改内容只改D:\AI\自建skill\那份,不要直接改D:\AI\skills\下的副本。 - 旧技能
项目制图已退休(09-19):能力全部并入本技能,真身移到D:\AI\_retired_skills\项目制图_2026-09-19\留档;生态环境分区管控制图中指向它的引用已改为本技能。 - bash 被 shim 破坏:
cd / dirname / tail / grep / mkdir均不可用。 - 建目录/复制/列文件用 Python 一行命令;不要接管道(
| tail、| grep会让整条命令失败)。 - 输出重定向到
.log文件后用 Read 读取。 - 跑脚本用绝对路径直调,不
cd(路径按本机实际填写):
<系统python> <脚本绝对路径>
(以 numpy/PIL/requests 为准;Windows 常见为%LOCALAPPDATA%\Programs\Python\Python3xx\python.exe;
托管 venv 为~/.workbuddy/binaries/python/envs/default/Scripts/python.exe,注意是Scripts/不是bin/) - 同一文件并行编辑会丢更新——改同一文件必须串行。
- 参考图会被清理,工作区须留副本
ref_project.jpg,自检脚本依赖它。
十、图种切换:行政区划图 / 高程图 / 地形图 / 地势图 / 示意图
所有图种共用同一图框骨架(A3、双线图框 + 3.55mm 分度带、指北针竖栏顶、比例尺、经纬度分度带注记、
图名/单位非必填)。差异只在地图主体内容 + 图例。切换图种不改版式。
默认图种为卫星影像图(--kind image):用户未指定图种时一律出卫星影像图;指定行政区划图(admin)/ 地形图 / 高程图 / 地势图 / 示意图时按指定图种出图。
| 图种 | --kind |
主体内容 | 图例 |
|---|---|---|---|
| 行政区划图 | admin |
界线分级 + 驻地 + 注记 + 四色填充(默认白底、不使用底图;--base image/shade 可选底图) |
四色区分、界线等级、驻地符号 |
| 管控单元分布图 | units |
三色管控单元 + 界线 | 三色单元、界线等级 |
| 高程图 | elevation |
DEM 高程连续/分级色带 | 色带 + 分级高程值(m) |
| 地形图(晕渲) | hillshade |
灰阶晕渲(±等高线) | 等高距、色带(若叠设色) |
| 地势图(分层设色) | hypsometric |
高程分层设色 + 晕渲叠合 | 分层色带 + 高程区间 |
| 示意图 | schematic |
简化底图 + 标注/引线/范围 | 标注项、范围红线 |
| 卫星影像图 | image |
真彩色影像 | 影像源、标注 |
高程图 / 地势图配色(分层设色表,规范参考值)
| 高程区间 (m) | 颜色 | 说明 |
|---|---|---|
| < 0(洼地/水下) | #9CC7F0 浅蓝 |
负值区单独判定,勿混进 0 档 |
| 0 – 200 | #4CAF50 绿 |
平原 |
| 200 – 500 | #A5D06A 黄绿 |
丘陵 |
| 500 – 1000 | #E8D16A 黄 |
低山 |
| 1000 – 2000 | #D9A05B 橙黄 |
中山 |
| 2000 – 3000 | #C07840 褐 |
高中山 |
| 3000 – 5000 | #9C5B3C 深褐 |
高山 |
| > 5000 | #F2F2F2 灰白 |
雪线以上 |
- 连续色带(高程图)用上表线性插值;分层设色(地势图)按档取色,档界即等高线。
- 地势图叠晕渲:晕渲图层不透明度 30%–40%,只增强立体感,不得压掉设色色相。
- 色带方向一律低值在下 / 高值在上(图例竖排)或左低右高(横排),不得反转。
地形晕渲参数
- 光源:方位角 315°、高度角 45°(国际通用;不得用 0°/90° 这种压平地形的值)。
- 由 DEM 计算:
slope/aspect → hillshade = cos(zenith)·cos(slope) + sin(zenith)·sin(slope)·cos(az−aspect),
输出灰阶 0–255,再按需要调 gamma。 - 等高线:以分层设色档界为计曲线(加粗 + 注记高程值),档界间按等高距插值出首曲线(细线)。
等高距按图幅尺度选(大比例尺 10/20/50 m,中小比例尺 100/250/500 m),必须写进图例。
示意图(schematic)专用规则
- 必须标注"示意图"字样(图名或图幅角注),不得冒充精确成果图。
- 不要求严格比例尺:可只给概略比例尺或省去数字比例尺,但指北针与图例不能省。
- 底图简化:单色/淡化晕渲 + 少量界线,突出标注对象。
- 组成:范围红线(
#E03B3B)+ 引线标注 + 关键地名 + 关系箭头(路线示意)。 - 允许用非投影的示意性排布,但若图上保留了经纬度分度带,就必须仍是 GK 投影真坐标,不得随手画。
行政区划图(admin)专用规则
- 底图(默认影像):
admin默认与image图种同源,即可商用影像底图
(遵「默认使用卫星影像图作为底图」口径);--base shade切浅绿灰#E9EFE0+ 极淡晕渲 12%
(主体是界线与注记,底图退居其次)。 - 浅色底(
shade)不得纯白 / 无起伏:qa_check_base的admin分支判底图均值 ≤249、标准差 ≥2。 - 影像底走影像判据(空白区 / 亮度 / 条带),不套用浅色底判据。
- 影像底界线必须加白套衬(踩过的坑,09-19):统一黑界线压在影像上会「消失」——
实测影像底图中位亮度仅 55.9、88.4% 像素亮度 <80,黑线(亮度 0)外侧几乎没有对比。
故影像底先压一层不透明白套衬(CASING_MM = 0.18/ 侧)再画黑线;两遍绘制
(先全部套衬、再全部黑线),避免相邻界线的套衬互相切出白缝。--no-line-casing可关。
实测套衬带 64,461 px(占图面 0.59%),带宽 2–3 px/侧 ≈ 0.18 mm,带内 100% 纯白(均值 255.0);
同一位置在无套衬版为影像(中位 55.9)。浅色底(shade)不加套衬(改动前后逐像素一致,0 px 差异)。 - 图面组成:界线按跨度自动选级 + 政府驻点分级标注 + 主题区轮廓加粗 0.9 mm 及固定白边;
图例下限 ≥6 条(界线等级 + 驻地符号)。 - BYO 模式必须让本级轮廓并入绘制层(踩过的坑):
--boundary给出的本级轮廓自身就是一级界线
(省界 / 地市界 / 区县界),必须入列;否则 ① 该级别不进图例;②drawn_levels缺该级别,
而驻点正是按drawn_levels过滤的 —— 该级驻点(如「省会」)会被一并误删。
DataV 模式因上级图层恰含本级而掩盖了该缺陷,切到 BYO 才暴露。 - 实测(四川省,BYO,跨度 1331 km):界线级别
省界/地市界;驻点省会 1 / 地市 19(成都与省会同址,
按「同址只留高级别」并入省会,故 21 个地市计入 19 个)。 - 四色填充(
admin默认开启,地图四色原理): - 邻接判定用「共享顶点法」:同源行政区数据沿公共边界共用顶点,两要素共享 ≥1 个顶点即判相邻。
本机无 shapely,此法比几何求交快且稳。实测四川省 21 个地市:共享顶点 2,276 个、邻接边 45 条、无孤立点。 - 着色:DSATUR(饱和度优先)+ 回溯,从 4 色起逐级尝试,直到在调色板色数内解出:
能 4 色解出的图仍输出 4 色;确实需要更多色时自动升到 5/6 色 —— 不硬卡 4 色(用户 09-19 要求:
「配色至少 4 种,需要填色的比较多时可以是 5 种或更多,不要限制那么死」)。
超 400 个单元时退回贪心;超过调色板色数才如实告警并提示用--fill-colors加色,不假装成功。 - ⚠ 不要用纯贪心(Welsh–Powell):贪心不保证 4 色 —— 实测上海市 16 个区贪心要用 5 色,
而取色是palette[col % len(palette)],第 5 色会折回第 1 色 → 视觉上相邻同色(上海实测 2 处)。
「用色数 / 同色相邻」也必须按调色板索引统计,否则报告与图面不一致(旧实现按原始色号统计 → 误报"0 冲突")。 - 默认配色(柔和清新,6 色):
#A8D5E2淡天蓝 /#BFE3B4淡草绿 /#FBE7A1淡鹅黄 /
#F5C2B8淡珊瑚粉 /#C9B6E4淡薰衣草紫 /#A8DCD4淡青绿(同明度、同低饱和粉彩系)。
前 4 色已满足地图四色原理,后 2 色供单元较多、4 色解不出时自动启用;
--fill-colors "#RRGGBB,..."可换(色数可增减;少于 4 色也能跑,但冲突由用户自负)。 - 默认 20% 透明:
FILL_ALPHA_TRANS = 20→alpha = 204(与--halo-trans同口径);
--fill-alpha 0..100可调,--no-fill关闭。 - 层序:填面画在界线之前 → 位于图层最下层,界线与注记压在填色之上。
- 表意与图例:四色只用于区分相邻单元,不表示数值大小(非专题分级),
因此默认不写入图例(用户 09-19 要求);确需入图例才加--fill-legend(patch4类型:4 个色块并排)。
故行政区划图的图例 = 驻地(点)+ 界线(线),实测 5 条。 - 实测(四川省,BYO,z9):21 个单元 / 用色 4 / 同色相邻 0 处;与
--no-fill版差异 3,210,943 px,
其中 3,194,689 px(99.49%)精确命中0.8×配色 + 0.2×底图(误差 ≤2/255)→ 确认 20% 透明按 alpha 正确合成;
填充覆盖图面 29.5%。通用版 DataV 模式(青岛市)同类通过:10 个单元 / 用色 4 / 同色相邻 0 处。
各图种数据来源(免 key 优先)
| 用途 | 源 | 取值方式 |
|---|---|---|
| 高程 DEM | AWS Terrarium 高程瓦片 https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png |
PNG 三通道解码:h = R*256 + G + B/256 − 32768(米) |
| 地形晕渲 | Esri World Hillshade .../World_Hillshade/MapServer/tile/{z}/{y}/{x} |
直接取图(免 key) |
| 影像(默认) | Esri World Imagery(--imagery esri) |
免 key 直连;官方:不得商用、不得导出瓦片离线——仅限职务内部使用 |
| 影像(备选) | 天地图(--imagery tianditu --imagery-key <tk>) |
需实名申请 tk(个人日配额 1 万次);按条款不落盘缓存;批量拉瓦片仍可能被判为"下载行为",key 与用途合规自负 |
| 行政边界 | DataV GeoAtlas(民间参考) | <主体行政代码>.json |
| 用户自备 | GeoTIFF / Shapefile / GeoJSON | 优先级最高 |
> 正式上报、对外发布必须用自然资源部标准地图服务(bzdt.ch.mnr.gov.cn)审图号底图或天地图(需 key);
> 高程/晕渲/影像类公开源只适合内部参考与方案附图。
图种级质量判定(内容自检 qa_check.py content)
- 高程/地形/地势图:无数据(纯白/纯灰)区块 > 2% 即 FAIL,先查 DEM 覆盖与投影再出图。
- 色带与图例必须一一对应:图例分级数 = 分层数,区间端点闭合(如
200–500、500–1000不得写成200–500、501–1000)。 - 图例条数下限:高程/地势 ≥5 条分级;行政区划图 ≥5(四色填充不入图例);项目成果图 ≥8。
- 示意图豁免"主体 95% 适配"几何项,但必须有"示意图"标识 + 指北针 + 图例。
出图脚本:scripts/make_terrain.py
行政区划 / 高程 / 地形 / 地势 / 示意 / 影像六图种 + 可选投影 + 可自定义 dpi,一条命令出图。
<venv-python> scripts/make_terrain.py \
--bbox "116.6513,40.3983,116.7087,40.4217" \
--kind hypsometric --zoom 15 --proj gk3 --dpi 300 --page a3 \
--contour --name "某区域地势图" --out out.png
| 参数 | 说明 |
|---|---|
--kind |
admin / elevation / hillshade / hypsometric / schematic / image(默认 image 卫星影像图) |
--base |
行政区划图底图:plain 纯白、不下载任何瓦片(默认)/ image 影像 / shade 浅绿灰+淡晕渲 |
--fill-colors |
填充配色:逗号分隔十六进制色(默认柔和清新 6 色,前 4 色满足四色原理,多余色按需自动启用) |
--fill-alpha |
填充透明度%(默认 20,即 80% 不透明) |
--no-fill |
行政区划图不做四色填充 |
--fill-legend |
把四色填充写入图例(默认不写:四色只区分相邻单元,非专题分级) |
--no-line-casing |
影像底图不给界线加白色套衬(默认加,保证暗底上界线可辨) |
--proj |
gk3(默认) / gk6 / utm / albers / lcc / mercator |
--cm |
中央经线(不给则随制图区域自动取带) |
--zone / --lat1 / --lat2 |
UTM 带号 / 双标准纬线(不给则自动) |
--dpi |
默认 300,可自定义(印刷 300 / 屏幕 96–150) |
--page |
a3 / a4 / WxHmm 自定义 |
--zoom |
数据瓦片层级(DEM 用 Terrarium,最高 z15)。影像源会按自身 max_z 自动降级(esri 19 / 天地图 18),超限时打印提示 |
--imagery |
影像源:esri(默认,Esri World Imagery)/ tianditu(天地图) |
--imagery-key |
天地图密钥(tk);也可用环境变量 MAP_IMAGERY_KEY。--imagery tianditu 时不填直接 exit 2 |
--vmin / --vmax |
色带上下限(默认 2%/98% 分位裁剪,防离群值压扁色带) |
--contour |
叠加等高线(分层边界) |
--region |
行政区名称或 6 位 adcode(省/市/县),自动加载行政界线并以边界出图 |
--draw-country |
绘制国界(默认不绘;国界表示敏感,对外分发需按审图要求处理) |
--no-seats |
不标注各级政府驻点(默认按图幅跨度自动分级标注,见「六之四」) |
--halo-trans |
主题区轮廓白边透明度%(默认 30,即 30% 透明、底图可透出);白边只在轮廓外侧 |
--overlay |
本地 GeoJSON,叠加红色范围线(常与 schematic 合用) |
--mark |
标注点,格式 lon,lat,名称;... |
--workers |
并行下载线程(默认 16) |
实测(怀柔校区 4.88×2.62 km、z15、A3@300dpi):21 块瓦片,出图 约 6 秒;
--proj gk3 自动取中央经线 117°E → EPSG:4548,坐标注记自动落图幅左下角。
<venv-python> make_terrain.py --region 青岛市 --kind hillshade --zoom 11 --dpi 300 --page a3 --unit "某单位" --out 青岛市地形图.png
--region 支持省/市/县三级名称(如 山东省、青岛市、即墨区),自动解析 adcode、下载本级+下级边界、按跨度自动选级绘制行政界线(国界/省界/地市界/区县界)、范围按图框比例居中,并自动分级标注政府驻点。
换 --proj utm / --proj albers 同样可出(无标准 EPSG 时如实标"自定义"并附 proj4)。
九、参考实现
参考实现位置:工作区 <制图工作目录>/(即本技能脚本所在目录,随项目变动):
- admin_common.py —— 高斯-克吕格 gk_forward/gk_inverse/_gk_inverse_np、GEO/geo(version) 中 project 分支的 COLLAR_MM=3.55 内缩、NEATLINE_COLOR、GRAT_*(分度带与经纬度)常量、fmt_dm()(度分不带秒)、text_rot90()(竖排纬度)、COMPASS(指北针图廓右上)、BOUND_W_MM(界线线宽)、FIG_NO_ATLAS/FIG_NO_PROJECT(图号,项目版 None)、FILL_TARGET+subject_bbox_m()+compute_extent()(主体 95% 适配)、build_frame_overlay(version) 的 HAS_COLLAR 分支、load_overlays()。
- overlay_ingest.py —— 上传矢量接入:解 zip/rar、读 Shapefile(pyshp)、自动坐标系转换(pyproj)到 CGCS2000。命令行可独立跑:python overlay_ingest.py 包.zip 看转换报告。
- test_ingest.py —— 6 项自测(带 .prj / 无 .prj 试算 / 经纬度 GeoJSON / WGS84 / 墨卡托 3857 / rar 缺工具降级)。
- make_admin_script.py —— 图内十字仅图集版绘制(project 必须为 0);叠加矢量按 color_by 对面/线/点一体分色。
- compose_admin.py / qa_check.py / compare_refs.py / preflight.py / build_montages.py / verify_labels.py / verify_collar.py(分度带量化自检)。
项目版调用参数:version="project"。
两路线命令(绝对路径直调,不 cd):
# 路线一 · 脚本直连(默认)
<系统python> make_admin_script.py project
<系统python> compose_admin.py project
# 路线二 · QGIS(必须用 QGIS 自带解释器,不能用 bin\python.exe 启动器)
"<QGIS安装目录>\apps\Python312\python.exe" make_admin_qgis.py project
脚本直连顺带产出 admin_terrain_<版式>.tif(GK 投影 + 内嵌 GeoKey,EPSG 取本幅动态选定的带号),QGIS 路线与外部软件复核可复用;缺失时 QGIS 路线现场生成,保证两路线底图同源。
QGIS 导出宽有时为 4960 而非 4961,脚本已自动 resize 归一后再叠框。
十一、数据源授权与合规(对外分发前必读)
> 以下为依据各源官方文档/官方答复核实的结果(2026-09-19)。内部职务使用 ≠ 对外商业分发,风险量级不同。
| 数据 | 授权状况(已核实) | 结论 |
|---|---|---|
| 行政界线(DataV.GeoAtlas) | 阿里云文档原话:数据来自高德开放平台,仅供学习交流使用,版权问题以高德开放平台为准 | 学习/内部研究可用;商业分发超范围,需向高德取得商务授权 |
| 卫星影像(Esri World Imagery 直连瓦片) | Esri 官方答复:该瓦片服务需 ArcGIS Online/Enterprise 许可、不得商用;World Imagery 不得导出瓦片离线 | 本脚本直连瓦片并落盘缓存(tiles_cache)——商用/再分发属越界 |
卫星影像备选(天地图,--imagery tianditu) |
官方「服务调用配额说明」原文:(2) 如果服务调用过程中存在数据爬取或者下载行为,服务调用会被自动拒绝;个人开发者日配额 1 万次,企业 300 万次(需上传执照认证)。配额页:cloudcenter.tianditu.gov.cn/center/development/quotaDesc |
已按此条禁用该源瓦片落盘(cache=False,瓦片仅内存流转)+不内置任何 key(须 --imagery-key 自带)。但仍须使用者自负:批量拉瓦片出图本身仍可能被判定为"下载行为";商用另需按协议处理 |
| DEM(AWS Terrarium;SRTM) | 开放数据计划托管 / 美国公有领域 | 相对宽松,仍应注明来源 |
| 字体(微软雅黑 / 黑体 / 宋体) | 商用输出需字体厂商授权(微软雅黑版权属方正) | 内部使用可;商业输出建议换开源字体 |
- 中国地图合规:图件含国界/行政界线并对外发布时,涉及《地图管理条例》的地图审核(审图号)与国界表示要求;对外成果建议统一采用标准地图服务底图或经审图的地图。
- 图例下方已内置来源注记(如「影像源:Esri World Imagery」「行政界线:DataV.GeoAtlas」),但注记不等于授权,不能替代商用许可。
- 若要商业化改造,建议顺序:① 影像换 NASA GIBS(美国政府作品、不受版权保护) / Landsat(公有领域)/ MapTiler·Mapbox(自带 key,按条款可商用)。注意:不要直接引用 EOX 的 Sentinel-2 cloudless —— 其 2018–2024 版为 CC BY-NC-SA 4.0(非商业),CC BY 4.0 的 2016 版端点已 404(2026-09-19 实测);天地图虽合规性好,但其条款禁止"数据爬取或下载行为",与本技能批量下载瓦片并落盘缓存的方式直接冲突,须改成用户侧自申请 key 且放弃服务端缓存;② 边界改自有授权数据,或改为 BYO-key(用户自带凭据,责任前移);③ 字体改内置思源黑体/思源宋体(SIL OFL,可商用可分发),顺带解决跨平台;④ 国界已默认不绘(
--draw-country才绘),对外成果仍建议加「示意」字样声明。