style: Step4 图表中文排版升级,对齐Step12风格

- 添加 matplotlib rcParams 中文字体配置(Microsoft YaHei / SimHei)
- 散点图标题→'采样点空间分布',坐标轴→'经度/X'、'纬度/Y'
- 光谱图标题→'采样点 ID: X 光谱曲线',坐标轴→'波长/特征'、'反射率'
- 悬停提示框中文化:ID + 经度 + 纬度
- 标题字号统一为 fontsize=14 fontweight='bold' pad=12
- 轴标签字号统一为 fontsize=11
This commit is contained in:
duxin
2026-06-30 09:45:50 +08:00
parent 48d17ef0ca
commit 1bdd623fe7

View File

@ -14,9 +14,14 @@ import os
import sys
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# ── 全局中文字体配置(与 Step12 统一)──
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'sans-serif']
plt.rcParams['axes.unicode_minus'] = False
_HERE = os.path.dirname(os.path.abspath(__file__))
if _HERE not in sys.path:
sys.path.insert(0, _HERE)
@ -169,41 +174,44 @@ class Step4SamplingPanel(QWidget):
left_widget.setMinimumWidth(360)
# ═══════════════════════════════════════════════
# 右侧:可视化区(嵌入式 Matplotlib 视图
# 右侧:可视化区(参考 Step12 ImageViewer 的白底卡片风格
# ═══════════════════════════════════════════════
right_widget = QWidget()
right_layout = QVBoxLayout()
right_layout.setContentsMargins(12, 24, 24, 24)
right_layout.setContentsMargins(0, 0, 0, 0)
right_layout.setSpacing(0)
# 给画板穿上卡片外衣,确保视觉上的绝对统一
viz_group = QGroupBox("📊 采样点交互式探索")
viz_layout = QVBoxLayout()
viz_layout.setContentsMargins(8, 20, 8, 8)
viz_layout.setSpacing(0)
# Matplotlib 画布1×2 子图:散点图 + 光谱曲线)
self._fig = Figure(figsize=(9, 5))
self._fig = Figure(figsize=(10, 7), facecolor='white')
self._ax_scatter = self._fig.add_subplot(121)
self._ax_spectrum = self._fig.add_subplot(122)
self._canvas = FigureCanvas(self._fig)
self._canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self._canvas.setStyleSheet("background-color: white;")
# 设置子图初始状态
self._ax_scatter.set_title("采样点分布", fontsize=11, fontweight='bold')
self._ax_scatter.set_xlabel("X 坐标")
self._ax_scatter.set_ylabel("Y 坐标")
for ax, title, xlabel, ylabel in [
(self._ax_scatter, "采样点空间分布", "经度 / X", "纬度 / Y"),
(self._ax_spectrum, "光谱曲线", "波长 / 特征", "反射率"),
]:
ax.set_title(title, fontsize=14, fontweight='bold', pad=12)
ax.set_xlabel(xlabel, fontsize=11)
ax.set_ylabel(ylabel, fontsize=11)
ax.set_facecolor('white')
ax.tick_params(labelsize=9)
self._ax_scatter.text(0.5, 0.5, "等待采样数据生成...\n\n请先配置参数并运行步骤\n或选择已有的 CSV 后刷新",
ha='center', va='center', transform=self._ax_scatter.transAxes,
fontsize=12, color='#888888')
self._ax_scatter.grid(False)
self._ax_spectrum.set_title("光谱曲线", fontsize=11, fontweight='bold')
self._ax_spectrum.set_xlabel("波长 (nm)")
self._ax_spectrum.set_ylabel("反射率")
fontsize=13, color='#AAAAAA')
self._ax_spectrum.text(0.5, 0.5, "点击左侧散点\n查看光谱曲线",
ha='center', va='center', transform=self._ax_spectrum.transAxes,
fontsize=12, color='#888888')
self._ax_spectrum.grid(False)
fontsize=13, color='#AAAAAA')
self._fig.tight_layout(pad=2.0)
@ -213,13 +221,13 @@ class Step4SamplingPanel(QWidget):
viz_layout.addWidget(self._canvas)
viz_group.setLayout(viz_layout)
right_layout.addWidget(viz_group)
right_layout.addWidget(viz_group, 1)
right_widget.setLayout(right_layout)
# ── 组装分栏 ──
splitter.addWidget(left_widget)
splitter.addWidget(right_widget)
splitter.setSizes([420, 680]) # 初始比例 ≈ 38:62
splitter.setSizes([400, 700])
splitter.setStretchFactor(0, 1)
splitter.setStretchFactor(1, 2)
@ -499,53 +507,57 @@ class Step4SamplingPanel(QWidget):
# ── 绘制 ax1散点图 ──
self._ax_scatter.clear()
self._ax_scatter.set_facecolor('white')
x = df[x_col].values
y = df[y_col].values
self._scatter = self._ax_scatter.scatter(
x, y,
c='#0078D7', alpha=0.7, edgecolors='white',
linewidth=0.5, s=40, picker=True, zorder=3
c='#0078D7', alpha=0.75, edgecolors='white',
linewidth=0.6, s=45, picker=True, zorder=3
)
self._ax_scatter.set_xlabel(str(x_col), fontsize=10)
self._ax_scatter.set_ylabel(str(y_col), fontsize=10)
self._ax_scatter.set_title(f"采样点分布 (共 {len(df)} 个点)", fontsize=11, fontweight='bold')
self._ax_scatter.grid(True, alpha=0.3, linestyle='--')
self._ax_scatter.set_facecolor('#F8F9FA')
self._ax_scatter.set_xlabel("经度 / X", fontsize=11)
self._ax_scatter.set_ylabel("纬度 / Y", fontsize=11)
self._ax_scatter.set_title(f"采样点空间分布 (共 {len(df)} 个点)", fontsize=14, fontweight='bold', pad=12)
self._ax_scatter.grid(True, alpha=0.2, linestyle='-', linewidth=0.5)
self._ax_scatter.tick_params(labelsize=9)
# ── 绘制 ax2光谱曲线初始状态──
self._ax_spectrum.clear()
self._ax_spectrum.set_facecolor('white')
if band_cols:
self._ax_spectrum.set_title("光谱曲线(点击左侧散点查看)", fontsize=11, fontweight='bold')
self._ax_spectrum.set_xlabel("波长 (nm)", fontsize=10)
self._ax_spectrum.set_ylabel("反射率", fontsize=10)
self._ax_spectrum.grid(True, alpha=0.3, linestyle='--')
self._ax_spectrum.set_title("光谱曲线(点击左侧散点查看)", fontsize=14, fontweight='bold', pad=12)
self._ax_spectrum.set_xlabel("波长 / 特征", fontsize=11)
self._ax_spectrum.set_ylabel("反射率", fontsize=11)
self._ax_spectrum.grid(True, alpha=0.2, linestyle='-', linewidth=0.5)
self._ax_spectrum.tick_params(labelsize=9)
self._ax_spectrum.text(0.5, 0.5, "点击左侧散点\n查看光谱曲线",
ha='center', va='center', transform=self._ax_spectrum.transAxes,
fontsize=12, color='#999999')
fontsize=13, color='#AAAAAA')
else:
self._ax_spectrum.text(0.5, 0.5, "缺少光谱数据列",
ha='center', va='center', transform=self._ax_spectrum.transAxes,
fontsize=12, color='#999999')
fontsize=13, color='#AAAAAA')
self._fig.tight_layout(pad=2.0)
self._canvas.draw()
def _show_empty_state(self, message: str):
"""在右侧画布显示提示信息。"""
self._ax_scatter.clear()
self._ax_scatter.set_title("采样点分布", fontsize=11, fontweight='bold')
for ax in (self._ax_scatter, self._ax_spectrum):
ax.clear()
ax.set_facecolor('white')
ax.tick_params(labelsize=0)
self._ax_scatter.set_title("采样点空间分布", fontsize=14, fontweight='bold', pad=12)
self._ax_scatter.text(0.5, 0.5, message, ha='center', va='center',
transform=self._ax_scatter.transAxes,
fontsize=12, color='#888888')
self._ax_scatter.grid(False)
fontsize=13, color='#AAAAAA')
self._ax_spectrum.clear()
self._ax_spectrum.set_title("光谱曲线", fontsize=11, fontweight='bold')
self._ax_spectrum.set_title("光谱曲线", fontsize=14, fontweight='bold', pad=12)
self._ax_spectrum.text(0.5, 0.5, "等待数据...",
ha='center', va='center', transform=self._ax_spectrum.transAxes,
fontsize=12, color='#888888')
self._ax_spectrum.grid(False)
fontsize=13, color='#AAAAAA')
self._fig.tight_layout(pad=2.0)
self._canvas.draw()
@ -588,7 +600,7 @@ class Step4SamplingPanel(QWidget):
y_val = row[self._y_col]
# 创建或更新 Annotation
text = f"#{idx}\n({x_val:.4f}, {y_val:.4f})"
text = f"ID: {idx}\n经度: {x_val:.4f}\n纬度: {y_val:.4f}"
if self._annot is None:
self._annot = self._ax_scatter.annotate(
text,
@ -629,31 +641,33 @@ class Step4SamplingPanel(QWidget):
y = self._df[self._y_col].values
colors = ['#0078D7'] * len(self._df)
sizes = [40] * len(self._df)
sizes = [45] * len(self._df)
colors[idx] = '#E74C3C'
sizes[idx] = 80
self._ax_scatter.clear()
self._ax_scatter.set_facecolor('white')
self._scatter = self._ax_scatter.scatter(
x, y, c=colors, s=sizes,
alpha=0.7, edgecolors='white', linewidth=0.5,
alpha=0.75, edgecolors='white', linewidth=0.6,
picker=True, zorder=3
)
# 将选中点提升到顶层
self._ax_scatter.scatter(
[x[idx]], [y[idx]],
c='#E74C3C', s=100,
c='#E74C3C', s=110,
alpha=0.9, edgecolors='white', linewidth=1.5,
zorder=5
)
self._ax_scatter.set_xlabel(str(self._x_col), fontsize=10)
self._ax_scatter.set_ylabel(str(self._y_col), fontsize=10)
self._ax_scatter.set_title(f"采样点分布 (共 {len(self._df)} 个点)", fontsize=11, fontweight='bold')
self._ax_scatter.grid(True, alpha=0.3, linestyle='--')
self._ax_scatter.set_facecolor('#F8F9FA')
self._ax_scatter.set_xlabel("经度 / X", fontsize=11)
self._ax_scatter.set_ylabel("纬度 / Y", fontsize=11)
self._ax_scatter.set_title(f"采样点空间分布 (共 {len(self._df)} 个点)", fontsize=14, fontweight='bold', pad=12)
self._ax_scatter.grid(True, alpha=0.2, linestyle='-', linewidth=0.5)
self._ax_scatter.tick_params(labelsize=9)
# ── 绘制光谱曲线 ──
self._ax_spectrum.clear()
self._ax_spectrum.set_facecolor('white')
if self._band_cols:
wavelengths = []
reflectance = []
@ -673,24 +687,25 @@ class Step4SamplingPanel(QWidget):
wavelengths, reflectance = zip(*pairs) if pairs else ([], [])
self._ax_spectrum.plot(
wavelengths, reflectance,
color='#0078D7', lw=1.5, marker='.', markersize=3, alpha=0.8
color='#0078D7', lw=1.5, marker='.', markersize=3, alpha=0.85
)
self._ax_spectrum.fill_between(wavelengths, reflectance, alpha=0.1, color='#0078D7')
self._ax_spectrum.set_xlabel("波长 (nm)", fontsize=10)
self._ax_spectrum.set_ylabel("反射率", fontsize=10)
self._ax_spectrum.set_title(f"样本 #{idx} 光谱曲线 ({len(wavelengths)} 个波段)",
fontsize=11, fontweight='bold')
self._ax_spectrum.grid(True, alpha=0.3, linestyle='--')
self._ax_spectrum.fill_between(wavelengths, reflectance, alpha=0.08, color='#0078D7')
self._ax_spectrum.set_xlabel("波长 / 特征", fontsize=11)
self._ax_spectrum.set_ylabel("反射率", fontsize=11)
self._ax_spectrum.set_title(f"采样点 ID: {idx} 光谱曲线 ({len(wavelengths)} 个波段)",
fontsize=14, fontweight='bold', pad=12)
self._ax_spectrum.grid(True, alpha=0.2, linestyle='-', linewidth=0.5)
self._ax_spectrum.tick_params(labelsize=9)
else:
self._ax_spectrum.text(0.5, 0.5, "该样本无有效光谱数据",
ha='center', va='center',
transform=self._ax_spectrum.transAxes,
fontsize=12, color='#999999')
fontsize=13, color='#AAAAAA')
else:
self._ax_spectrum.text(0.5, 0.5, "缺少光谱波段列\n无法绘制光谱",
ha='center', va='center',
transform=self._ax_spectrum.transAxes,
fontsize=12, color='#999999')
fontsize=13, color='#AAAAAA')
self._fig.tight_layout(pad=2.0)
self._canvas.draw()