格式统一

This commit is contained in:
duxin
2026-07-01 13:19:46 +08:00
parent 8de73db80e
commit 1611001a72
13 changed files with 348 additions and 116 deletions

View File

@ -91,6 +91,9 @@ class PipelineContext:
# ★ 取消标志(2026-06-30):支持 Pipeline 优雅中断
self._cancelled: bool = False
# ★ 步骤输出目录映射(实例级别,2026-07-01 修复:从类变量改为实例变量,防止跨 work_dir 路径错乱)
self._step_output_dir_map: Optional[Dict[str, Path]] = None
# ── 可视化组件(延迟导入避免循环依赖)──
self._visualizer = None
self._report_generator = None
@ -194,11 +197,10 @@ class PipelineContext:
# 步骤输出目录查找(兼容旧接口)
# ═══════════════════════════════════════════════════════════
_STEP_OUTPUT_DIR_MAP: Optional[Dict[str, Path]] = None
def _ensure_step_dir_map(self) -> Dict[str, Path]:
if PipelineContext._STEP_OUTPUT_DIR_MAP is not None:
return PipelineContext._STEP_OUTPUT_DIR_MAP
"""构建实例级别的步骤输出目录映射(每个 work_dir 独立缓存)。"""
if self._step_output_dir_map is not None:
return self._step_output_dir_map
wp = self.work_dir
m = {
'step1': wp / '1_water_mask',
@ -232,7 +234,7 @@ class PipelineContext:
'visualization': wp / '12_visualization',
'reports': wp / 'reports',
}
PipelineContext._STEP_OUTPUT_DIR_MAP = m
self._step_output_dir_map = m
return m
def get_step_output_dir(self, step_name: str) -> Path:

View File

@ -42,6 +42,34 @@ def register_all_handlers(scheduler: PipelineScheduler):
result = scheduler.run_full_pipeline(config)
新增步骤时,在此函数中追加一行 register_handler() 即可。
── 2026-07-01 步骤体系说明 ──
当前注册表包含 16 个 Handler,但 PANEL_REGISTRY 只有 13 个面板。
两个体系存在如下映射关系:
Panel step_id → Handler step_key (via register_handlers)
─────────────────────────────────────────────────────────────────
step1 → step1
step2 → step2
step3 → step3
step4_sampling → 无独立 Handler(由 step4_sampling 面板驱动)
step5_clean → step5_clean
step6_feature → step6_feature
step7_index → step7_index
step8_ml_train → step8_ml_train
step9_ml_predict → step9_ml_predict
step10_watercolor → step10_watercolor (CSV 散点模式)
(无面板) → step10_qaa (QAA 物理反演,单独触发)
step11_map → step11_map (专题图 CSV 模式)
(无面板) → step11_concentration (浓度反演,单独触发)
(无面板) → step12_kriging (克里金插值,单独触发)
step12_viz → step13_visualization
step13_report → step14_report
注:
- step10_qaa / step11_concentration / step12_kriging / step14_report
是没有对应 Panel 的 Handler,只能通过旧 config JSON 加载或外部脚本触发。
- step10_watercolor 和 step10_qaa 共享 step10 编号空间,互斥使用。
"""
scheduler.register_handler(Step1WaterMaskHandler())
scheduler.register_handler(Step2GlintDetectionHandler())

View File

@ -30,6 +30,27 @@ class Step12KrigingHandler(BaseStepHandler):
prediction_csv_path = config.get('prediction_csv_path')
boundary_shp_path = config.get('boundary_shp_path')
# ★ 2026-07-01 空值保护:防止 prediction_csv_path 为 None 时 Path().stem 崩溃
if not prediction_csv_path:
msg = '缺少 prediction_csv_path 参数,无法生成克里金插值图'
context.notify('step12_kriging', 'error', msg)
step_end_time = time.time()
context.record_step_time(
"步骤12: 克里金插值与分布图", step_start_time, step_end_time,
status="failed", error=msg
)
return {'error': msg}
if not os.path.isfile(prediction_csv_path):
msg = f'预测 CSV 文件不存在: {prediction_csv_path}'
context.notify('step12_kriging', 'error', msg)
step_end_time = time.time()
context.record_step_time(
"步骤12: 克里金插值与分布图", step_start_time, step_end_time,
status="failed", error=msg
)
return {'error': msg}
# 强制输出到 visualization_dir
csv_name = Path(prediction_csv_path).stem if prediction_csv_path else "distribution"
forced_image_path = str(context.visualization_dir / f"{csv_name}_distribution.png")

View File

@ -33,10 +33,15 @@ class Step13VisualizationHandler(BaseStepHandler):
step_start_time = time.time()
output_files: Dict[str, Any] = {}
# ★ 2026-07-01 防御性编程:提前解析路径并做 None/存在性检查
_training_csv = context.training_csv_path
_models_dir = context.models_dir if context.models_dir else None
_processed_csv = context.processed_csv_path
try:
# ── 散点图 ──
if config.get('generate_scatter', True):
if context.training_csv_path and context.models_dir.exists():
if _training_csv and _models_dir and _models_dir.exists():
try:
scatter_config = config.get('scatter_config', {})
scatter_paths = self._generate_scatter_plots(context, scatter_config)
@ -47,7 +52,7 @@ class Step13VisualizationHandler(BaseStepHandler):
# ── 箱型图 ──
if config.get('generate_boxplots', True):
if context.processed_csv_path:
if _processed_csv:
try:
boxplot_config = config.get('boxplot_config', {})
boxplot_paths = self._generate_boxplots(context, boxplot_config)
@ -58,7 +63,7 @@ class Step13VisualizationHandler(BaseStepHandler):
# ── 光谱曲线 ──
if config.get('generate_spectrum', True):
if context.training_csv_path:
if _training_csv:
try:
spectrum_paths = self._generate_spectrum_plots(context, config)
output_files['spectrum_plots'] = spectrum_paths
@ -68,7 +73,7 @@ class Step13VisualizationHandler(BaseStepHandler):
# ── 统计图表 ──
if config.get('generate_statistics', True):
if context.processed_csv_path:
if _processed_csv:
try:
stat_charts = self._generate_statistics(context)
output_files['statistical_charts'] = stat_charts

View File

@ -38,7 +38,7 @@ class Step9MlPredictHandler(BaseStepHandler):
output_dir = (
config.get('output_path')
or config.get('output_dir')
or str(context.prediction_dir / "9_ML_Prediction")
or str(context.ml_prediction_dir)
)
try: