测试修改
This commit is contained in:
@ -166,7 +166,7 @@ ROUTES = [
|
||||
{
|
||||
# data/icons/ 没有 12.png/13.png;Step11/12/13 暂时复用 9.png(11 个 png 对 13 个 step 必然有共用)
|
||||
"id": "step11",
|
||||
"name": "11. 专题图生成",
|
||||
"name": "11. 分布图生成",
|
||||
"icon": "9.png",
|
||||
"view_module": "src.new.views.step11_view",
|
||||
"view_class": "Step11View",
|
||||
|
||||
@ -25,7 +25,8 @@ Step11 后端计算服务(专题图生成 / 克里金插值)
|
||||
"boundary_shp_path": "D:/boundary.shp", # 边界 shp(可选)
|
||||
"resolution": 30.0, # 空间分辨率(米)
|
||||
"input_crs": "EPSG:32651",
|
||||
"output_crs": "EPSG:4326",
|
||||
# ★★★ 强制默认 output_crs = input_crs,禁止从 service 配置误改为 EPSG:4326 ★★★
|
||||
"output_crs": "EPSG:32651",
|
||||
"output_dir": "D:/11_Thematic_Map", # 输出目录
|
||||
"enabled": True,
|
||||
"work_dir": "D:/workspace", # 工作目录
|
||||
|
||||
@ -46,7 +46,7 @@ Step12 后端计算服务(数据可视化——散点/光谱/箱线/掩膜缩
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from src.new.services._output_resolver import get_user_output_path, is_user_specified, resolve_output_dir
|
||||
|
||||
@ -168,18 +168,115 @@ def _try_sampling_maps(work_dir: str, output_dir: Path) -> Dict[str, Any]:
|
||||
return {"status": "completed" if p else "error", "path": p, "output_dir": str(output_dir / "sampling_maps")}
|
||||
|
||||
|
||||
def _resolve_thematic_map_dir(work_dir: str) -> "Optional[Path]":
|
||||
"""自动推断 Step 11 分布图输出目录
|
||||
|
||||
与 step11_service._resolve_output_dir 的 default 分支完全镜像——
|
||||
用户未指定 output_dir 时默认为 ``work_dir/11_Thematic_Map``。
|
||||
"""
|
||||
if not work_dir:
|
||||
return None
|
||||
cand = Path(work_dir) / "11_Thematic_Map"
|
||||
return cand if cand.is_dir() else None
|
||||
|
||||
|
||||
def _try_distribution_maps(work_dir: str, output_dir: Path) -> Dict[str, Any]:
|
||||
"""渲染/汇集 Step 11 生成的分布图到 14_visualization/distribution_maps
|
||||
|
||||
处理两类产物(独立子步骤,单个失败不影响另一个):
|
||||
|
||||
1. **PNG 直拷** —— ``11_Thematic_Map/*_专题图.png``
|
||||
(Step 11 GeoTIFF 栅格模式的产物,已带外框/图例/采样点,直接复制即可)
|
||||
2. **GeoTIFF 渲染** —— ``11_Thematic_Map/*_kriging.tif``
|
||||
(Step 11 CSV 插值模式的纯 GeoTIFF 产物,调用 ``ContentMapper.visualize_raster``
|
||||
渲染为同风格的 PNG)
|
||||
|
||||
Returns:
|
||||
{"status": "completed"|"skipped", "count": int,
|
||||
"png_copied": int, "tif_rendered": int,
|
||||
"output_dir": str, "details": [{"src", "dst", "kind"}, ...]}
|
||||
"""
|
||||
import shutil
|
||||
|
||||
src_dir = _resolve_thematic_map_dir(work_dir)
|
||||
if src_dir is None:
|
||||
raise FileNotFoundError(
|
||||
f"Step 11 输出目录不存在: {work_dir}/11_Thematic_Map"
|
||||
f"(请先运行 Step 11 生成分布图)"
|
||||
)
|
||||
|
||||
out_sub = output_dir / "distribution_maps"
|
||||
out_sub.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
details: List[Dict[str, str]] = []
|
||||
n_png_copy = 0
|
||||
n_tif_render = 0
|
||||
|
||||
# --- 1. PNG 直拷(GeoTIFF 模式已有产物) ---
|
||||
for src_png in sorted(src_dir.glob("*_专题图.png")):
|
||||
dst_png = out_sub / src_png.name
|
||||
try:
|
||||
shutil.copy2(src_png, dst_png)
|
||||
details.append({"src": str(src_png), "dst": str(dst_png), "kind": "png_copy"})
|
||||
n_png_copy += 1
|
||||
except Exception as copy_err: # noqa: BLE001
|
||||
print(f"[distribution_maps] ⚠ 复制失败 {src_png.name}: {copy_err}")
|
||||
|
||||
# --- 2. GeoTIFF 渲染(CSV 模式纯栅格产物) ---
|
||||
tif_paths = sorted(src_dir.glob("*_kriging.tif"))
|
||||
if tif_paths:
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
from src.postprocessing.map import ContentMapper
|
||||
|
||||
mapper = ContentMapper()
|
||||
for tif_path in tif_paths:
|
||||
stem = tif_path.stem
|
||||
chinese_title = mapper._get_chinese_title(stem)
|
||||
dst_png = out_sub / f"{chinese_title}_分布图.png"
|
||||
try:
|
||||
mapper.visualize_raster(
|
||||
raster_tif_path=str(tif_path),
|
||||
output_file=str(dst_png),
|
||||
boundary_shp_path=None,
|
||||
nodata_value=-9999.0,
|
||||
figsize=(14, 10),
|
||||
alpha=0.9,
|
||||
)
|
||||
details.append({"src": str(tif_path), "dst": str(dst_png), "kind": "tif_render"})
|
||||
n_tif_render += 1
|
||||
except Exception as render_err: # noqa: BLE001
|
||||
print(f"[distribution_maps] ⚠ 渲染失败 {tif_path.name}: {render_err}")
|
||||
|
||||
total = n_png_copy + n_tif_render
|
||||
if total == 0:
|
||||
raise FileNotFoundError(
|
||||
f"Step 11 输出目录 {src_dir} 中无 *_专题图.png 也无 *_kriging.tif"
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "completed",
|
||||
"count": total,
|
||||
"png_copied": n_png_copy,
|
||||
"tif_rendered": n_tif_render,
|
||||
"output_dir": str(out_sub),
|
||||
"details": details,
|
||||
}
|
||||
|
||||
|
||||
def execute_step12(config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Step 12 后端计算入口——纯函数"""
|
||||
work_dir: str = config.get("work_dir") or ""
|
||||
img_dir: str = config.get("img_dir") or ""
|
||||
enabled: bool = bool(config.get("enabled", True))
|
||||
output_dir: str = config.get("output_dir") or ""
|
||||
# 5 个开关:缺省默认 True(与旧 panel 行为一致)
|
||||
# 6 个开关:缺省默认 True(与旧 panel 行为一致;新增 distribution_maps 用于闭环 Step 11)
|
||||
gen_scatter = bool(config.get("generate_scatter", True))
|
||||
gen_spectrum = bool(config.get("generate_spectrum", True))
|
||||
gen_boxplots = bool(config.get("generate_boxplots", True))
|
||||
gen_glint = bool(config.get("generate_glint_previews", True))
|
||||
gen_sampling = bool(config.get("generate_sampling_maps", True))
|
||||
gen_distribution = bool(config.get("generate_distribution_maps", True))
|
||||
|
||||
output_path, _source = _resolve_output_dir(config, work_dir)
|
||||
mode = "viz_generate"
|
||||
@ -228,12 +325,14 @@ def execute_step12(config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
tasks.append(("glint_previews", _try_glint_previews))
|
||||
if gen_sampling:
|
||||
tasks.append(("sampling_maps", _try_sampling_maps))
|
||||
if gen_distribution:
|
||||
tasks.append(("distribution_maps", _try_distribution_maps))
|
||||
|
||||
if not tasks:
|
||||
return {
|
||||
"status": "completed",
|
||||
"output_path": str(output_path).replace("\\", "/"),
|
||||
"message": "无可视化任务(5 个开关全部 False)",
|
||||
"message": "无可视化任务(6 个开关全部 False)",
|
||||
"mode": mode,
|
||||
}
|
||||
|
||||
|
||||
@ -181,7 +181,10 @@ class Step11View(BaseView):
|
||||
params_layout.addRow("输入坐标系:", self.input_crs)
|
||||
|
||||
self.output_crs = QLineEdit()
|
||||
self.output_crs.setText("EPSG:4326")
|
||||
# ★★★ 强制默认输出坐标系与输入一致,禁止从 GUI 误改为 EPSG:4326 ★★★
|
||||
# 历史默认值 'EPSG:4326' 会让 ContentMapper 把栅格重投影到经纬度,
|
||||
# 与基于 EPSG:32651 的水域掩膜叠加时发生仿射变换撕裂(栅格错位、坐标轴扭曲)。
|
||||
self.output_crs.setText("EPSG:32651")
|
||||
params_layout.addRow("输出坐标系:", self.output_crs)
|
||||
|
||||
self.show_points = QCheckBox("显示采样点")
|
||||
@ -302,7 +305,8 @@ class Step11View(BaseView):
|
||||
"boundary_shp_path": self.boundary_file.get_path(),
|
||||
"resolution": self.resolution.value(),
|
||||
"input_crs": self.input_crs.text(),
|
||||
"output_crs": self.output_crs.text(),
|
||||
# ★★★ 强制 output_crs = input_crs,不再信任 GUI 的 output_crs 输入框 ★★★
|
||||
"output_crs": self.input_crs.text(),
|
||||
"show_sample_points": self.show_points.isChecked(),
|
||||
"use_distance_diffusion": self.use_diffusion.isChecked(),
|
||||
"enabled": self.enable_checkbox.isChecked(),
|
||||
@ -342,8 +346,9 @@ class Step11View(BaseView):
|
||||
self.resolution.setValue(config["resolution"])
|
||||
if "input_crs" in config:
|
||||
self.input_crs.setText(config["input_crs"])
|
||||
if "output_crs" in config:
|
||||
self.output_crs.setText(config["output_crs"])
|
||||
# ★★★ 反灌入时强制 output_crs = input_crs,避免旧 config 中的 EPSG:4326 回填 ★★★
|
||||
if "output_crs" in config or "input_crs" in config:
|
||||
self.output_crs.setText(config.get("input_crs") or config.get("output_crs") or "EPSG:32651")
|
||||
if "show_sample_points" in config:
|
||||
self.show_points.setChecked(config["show_sample_points"])
|
||||
if "use_distance_diffusion" in config:
|
||||
|
||||
@ -100,6 +100,14 @@ class Step12View(BaseView):
|
||||
self.gen_sampling_map.setChecked(True)
|
||||
config_layout.addWidget(self.gen_sampling_map)
|
||||
|
||||
self.gen_distribution_map = QCheckBox("空间分布图(Step 11 产物)")
|
||||
self.gen_distribution_map.setChecked(True)
|
||||
self.gen_distribution_map.setToolTip(
|
||||
"渲染/汇集 Step 11 生成的分布图(PNG 直拷 + GeoTIFF 渲染)"
|
||||
"到 14_visualization/distribution_maps"
|
||||
)
|
||||
config_layout.addWidget(self.gen_distribution_map)
|
||||
|
||||
config_layout.addSpacing(10)
|
||||
line = QFrame()
|
||||
line.setFrameShape(QFrame.HLine)
|
||||
@ -186,6 +194,7 @@ class Step12View(BaseView):
|
||||
"generate_boxplots": self.gen_boxplots.isChecked(),
|
||||
"generate_glint_previews": self.gen_mask_glint.isChecked(),
|
||||
"generate_sampling_maps": self.gen_sampling_map.isChecked(),
|
||||
"generate_distribution_maps": self.gen_distribution_map.isChecked(),
|
||||
"enabled": True,
|
||||
}
|
||||
|
||||
@ -207,6 +216,8 @@ class Step12View(BaseView):
|
||||
self.gen_mask_glint.setChecked(config["generate_glint_previews"])
|
||||
if "generate_sampling_maps" in config:
|
||||
self.gen_sampling_map.setChecked(config.get("generate_sampling_maps", True))
|
||||
if "generate_distribution_maps" in config:
|
||||
self.gen_distribution_map.setChecked(config.get("generate_distribution_maps", True))
|
||||
|
||||
def update_work_directory(self, work_dir: str):
|
||||
super().update_work_directory(work_dir)
|
||||
|
||||
Reference in New Issue
Block a user