2026-05-27 11:26:28 +08:00
|
|
|
|
"""Gamma 曲线绘制。
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamma 原样搬迁。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
2026-06-05 16:58:46 +08:00
|
|
|
|
from app.views.modern_styles import get_theme_palette
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
2026-05-27 11:26:28 +08:00
|
|
|
|
from typing import TYPE_CHECKING
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
2026-05-27 11:26:28 +08:00
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
|
from pqAutomationApp import PQAutomationApp
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-05 16:58:46 +08:00
|
|
|
|
def _is_dark_palette(palette: dict[str, str]) -> bool:
|
|
|
|
|
|
"""根据主题背景色亮度判断是否深色主题。"""
|
|
|
|
|
|
bg = palette.get("bg", "#FFFFFF").lstrip("#")
|
|
|
|
|
|
try:
|
|
|
|
|
|
r = int(bg[0:2], 16)
|
|
|
|
|
|
g = int(bg[2:4], 16)
|
|
|
|
|
|
b = int(bg[4:6], 16)
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return False
|
|
|
|
|
|
return (r * 299 + g * 587 + b * 114) / 1000 < 128
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-27 11:26:28 +08:00
|
|
|
|
|
|
|
|
|
|
def plot_gamma(self: "PQAutomationApp", L_bar, results_with_gamma_list, target_gamma, test_type):
|
2026-04-20 10:00:44 +08:00
|
|
|
|
"""绘制Gamma曲线 + 数据表格(包含实测亮度)"""
|
2026-06-05 16:58:46 +08:00
|
|
|
|
palette = get_theme_palette()
|
|
|
|
|
|
dark_mode = _is_dark_palette(palette)
|
|
|
|
|
|
line_actual = "#3FA7FF" if dark_mode else "#0A4BFF"
|
|
|
|
|
|
line_ideal = "#FF6B6B" if dark_mode else "#D62828"
|
|
|
|
|
|
grid_color = "#566070" if dark_mode else "#B8BDC3"
|
|
|
|
|
|
legend_bg = "#131821" if dark_mode else "#FFFFFF"
|
|
|
|
|
|
legend_edge = "#A4B2C6" if dark_mode else palette["border"]
|
|
|
|
|
|
table_edge = "#738196" if dark_mode else palette["border"]
|
|
|
|
|
|
table_body_fg = "#EEF3FA" if dark_mode else palette["fg"]
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
# ========== 1. 清空并重置左侧曲线 ==========
|
|
|
|
|
|
self.gamma_ax.clear()
|
2026-06-05 16:58:46 +08:00
|
|
|
|
self.gamma_fig.patch.set_facecolor(palette["bg"])
|
|
|
|
|
|
self.gamma_ax.set_facecolor(palette["card_bg"])
|
2026-04-20 10:00:44 +08:00
|
|
|
|
self.gamma_ax.set_xlim(0, 105)
|
|
|
|
|
|
self.gamma_ax.set_ylim(0, 1.1)
|
2026-06-05 16:58:46 +08:00
|
|
|
|
self.gamma_ax.set_xlabel("灰阶 (%)", fontsize=10, color=palette["fg"])
|
|
|
|
|
|
self.gamma_ax.set_ylabel("L_bar", fontsize=10, color=palette["fg"])
|
|
|
|
|
|
self.gamma_ax.grid(True, linestyle="--", alpha=0.45 if dark_mode else 0.3, color=grid_color)
|
2026-04-20 10:00:44 +08:00
|
|
|
|
self.gamma_ax.tick_params(labelsize=9)
|
2026-06-05 16:58:46 +08:00
|
|
|
|
self.gamma_ax.tick_params(colors=palette["fg"])
|
|
|
|
|
|
for spine in self.gamma_ax.spines.values():
|
|
|
|
|
|
spine.set_color(palette["border"])
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
# 生成横坐标(灰阶百分比)
|
|
|
|
|
|
x_values = np.linspace(0, 100, len(L_bar))
|
|
|
|
|
|
|
|
|
|
|
|
# 反转 L_bar(确保从左到右是 0% → 100%)
|
|
|
|
|
|
if len(L_bar) > 1 and L_bar[0] > L_bar[-1]:
|
|
|
|
|
|
L_bar = L_bar[::-1]
|
|
|
|
|
|
results_with_gamma_list = results_with_gamma_list[::-1]
|
|
|
|
|
|
|
|
|
|
|
|
# 计算平均Gamma
|
|
|
|
|
|
gamma_values = []
|
|
|
|
|
|
for item in results_with_gamma_list:
|
|
|
|
|
|
if isinstance(item, (list, tuple)) and len(item) >= 4:
|
|
|
|
|
|
gamma = item[3]
|
|
|
|
|
|
if 0.5 < gamma < 5.0:
|
|
|
|
|
|
gamma_values.append(gamma)
|
|
|
|
|
|
|
|
|
|
|
|
avg_gamma = np.mean(gamma_values) if gamma_values else target_gamma
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制实测曲线
|
|
|
|
|
|
self.gamma_ax.plot(
|
|
|
|
|
|
x_values,
|
|
|
|
|
|
L_bar,
|
2026-06-05 16:58:46 +08:00
|
|
|
|
color=line_actual,
|
|
|
|
|
|
marker="o",
|
2026-04-20 10:00:44 +08:00
|
|
|
|
label=f"实测 (平均γ={avg_gamma:.2f})",
|
|
|
|
|
|
linewidth=2,
|
|
|
|
|
|
markersize=4,
|
|
|
|
|
|
zorder=5,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制理想曲线(使用 target_gamma)
|
|
|
|
|
|
ideal_L_bar = [(x / 100) ** target_gamma for x in x_values]
|
|
|
|
|
|
self.gamma_ax.plot(
|
|
|
|
|
|
x_values,
|
|
|
|
|
|
ideal_L_bar,
|
2026-06-05 16:58:46 +08:00
|
|
|
|
color=line_ideal,
|
|
|
|
|
|
linestyle="--",
|
2026-04-20 10:00:44 +08:00
|
|
|
|
label=f"理想 (γ={target_gamma})",
|
|
|
|
|
|
linewidth=2,
|
2026-06-05 16:58:46 +08:00
|
|
|
|
alpha=0.9 if dark_mode else 0.7,
|
2026-04-20 10:00:44 +08:00
|
|
|
|
zorder=3,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 图例
|
2026-06-05 16:58:46 +08:00
|
|
|
|
legend = self.gamma_ax.legend(
|
|
|
|
|
|
fontsize=9,
|
|
|
|
|
|
loc="upper left",
|
|
|
|
|
|
framealpha=0.9 if dark_mode else 0.95,
|
|
|
|
|
|
facecolor=legend_bg,
|
|
|
|
|
|
edgecolor=legend_edge,
|
|
|
|
|
|
)
|
|
|
|
|
|
for text in legend.get_texts():
|
|
|
|
|
|
text.set_color(palette["fg"])
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
# ========== 2. 清空并绘制右侧表格 ==========
|
|
|
|
|
|
self.gamma_table_ax.clear()
|
|
|
|
|
|
self.gamma_table_ax.axis("off")
|
|
|
|
|
|
|
|
|
|
|
|
# 构建表格数据(4列)
|
|
|
|
|
|
table_data = [["灰阶", "实测亮度\n(cd/m²)", "L_bar", "Gamma"]]
|
|
|
|
|
|
|
|
|
|
|
|
for i, (x_val, L_val, result) in enumerate(
|
|
|
|
|
|
zip(x_values, L_bar, results_with_gamma_list)
|
|
|
|
|
|
):
|
|
|
|
|
|
# 提取实测亮度
|
|
|
|
|
|
if isinstance(result, (list, tuple)) and len(result) >= 3:
|
|
|
|
|
|
measured_lv = result[2]
|
|
|
|
|
|
measured_lv_str = f"{measured_lv:.2f}"
|
|
|
|
|
|
else:
|
|
|
|
|
|
measured_lv_str = "--"
|
|
|
|
|
|
|
|
|
|
|
|
# 提取 Gamma
|
|
|
|
|
|
if isinstance(result, (list, tuple)) and len(result) >= 4:
|
|
|
|
|
|
gamma = result[3]
|
|
|
|
|
|
if gamma < 0.5 or gamma > 5.0:
|
|
|
|
|
|
gamma_str = "--"
|
|
|
|
|
|
else:
|
|
|
|
|
|
gamma_str = f"{gamma:.2f}"
|
|
|
|
|
|
else:
|
|
|
|
|
|
gamma_str = "--"
|
|
|
|
|
|
|
|
|
|
|
|
table_data.append(
|
|
|
|
|
|
[
|
|
|
|
|
|
f"{x_val:.0f}%",
|
|
|
|
|
|
measured_lv_str,
|
|
|
|
|
|
f"{L_val:.3f}",
|
|
|
|
|
|
gamma_str,
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制表格(4列)
|
|
|
|
|
|
table = self.gamma_table_ax.table(
|
|
|
|
|
|
cellText=table_data,
|
|
|
|
|
|
cellLoc="center",
|
|
|
|
|
|
loc="center",
|
|
|
|
|
|
colWidths=[0.18, 0.28, 0.27, 0.27],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 美化表格
|
|
|
|
|
|
table.auto_set_font_size(False)
|
|
|
|
|
|
table.set_fontsize(7.5)
|
|
|
|
|
|
table.scale(1, 1.5)
|
|
|
|
|
|
|
|
|
|
|
|
# 表头样式
|
|
|
|
|
|
for i in range(4):
|
|
|
|
|
|
cell = table[(0, i)]
|
2026-06-05 16:58:46 +08:00
|
|
|
|
cell.set_facecolor(palette["primary"])
|
|
|
|
|
|
cell.set_text_props(weight="bold", color=palette["select_fg"])
|
|
|
|
|
|
cell.set_edgecolor(table_edge)
|
|
|
|
|
|
cell.set_linewidth(0.8)
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
# 数据行交替颜色
|
|
|
|
|
|
for i in range(1, len(table_data)):
|
|
|
|
|
|
for j in range(4):
|
|
|
|
|
|
cell = table[(i, j)]
|
|
|
|
|
|
if i % 2 == 0:
|
2026-06-05 16:58:46 +08:00
|
|
|
|
cell.set_facecolor(palette["surface_alt_bg"])
|
2026-04-20 10:00:44 +08:00
|
|
|
|
else:
|
2026-06-05 16:58:46 +08:00
|
|
|
|
cell.set_facecolor(palette["card_bg"])
|
|
|
|
|
|
cell.set_text_props(color=table_body_fg)
|
|
|
|
|
|
cell.set_edgecolor(table_edge)
|
|
|
|
|
|
cell.set_linewidth(0.6)
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
# ========== 3. 总标题 ==========
|
|
|
|
|
|
test_type_name = self.get_test_type_name(test_type)
|
|
|
|
|
|
self.gamma_fig.suptitle(
|
|
|
|
|
|
f"{test_type_name} - Gamma曲线",
|
|
|
|
|
|
fontsize=12,
|
|
|
|
|
|
y=0.98,
|
|
|
|
|
|
fontweight="bold",
|
2026-06-05 16:58:46 +08:00
|
|
|
|
color=palette["fg"],
|
2026-04-20 10:00:44 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 4. 绘制到画布 ==========
|
|
|
|
|
|
self.gamma_canvas.draw()
|
2026-04-20 10:16:31 +08:00
|
|
|
|
self.chart_notebook.select(self.gamma_chart_frame)
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
self.log_gui.log("Gamma曲线 + 数据表格绘制完成", level="success")
|
2026-05-27 11:26:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PlotGammaMixin:
|
|
|
|
|
|
"""由 tools/refactor_to_mixins.py 自动生成。
|
|
|
|
|
|
把本模块的自由函数挂到 PQAutomationApp 上,便于 F12 跳转与类型推断。
|
|
|
|
|
|
"""
|
|
|
|
|
|
plot_gamma = plot_gamma
|