修改色域画图及重绘方式
This commit is contained in:
@@ -136,12 +136,15 @@ def create_custom_template_result_panel(self):
|
||||
label="单步测试",
|
||||
command=self.start_custom_row_single_step,
|
||||
)
|
||||
|
||||
# self.custom_result_menu.add_separator()
|
||||
# self.custom_result_menu.add_command(
|
||||
# label="单步测试",
|
||||
# command=self.fill_custom_result_test_data,
|
||||
# )
|
||||
self.custom_result_menu.add_separator()
|
||||
self.custom_result_menu.add_command(
|
||||
label="生成模板",
|
||||
command=self.export_custom_template_excel,
|
||||
)
|
||||
self.custom_result_menu.add_command(
|
||||
label="生成图表",
|
||||
command=self.export_custom_template_charts,
|
||||
)
|
||||
self.custom_result_tree.bind("<Button-3>", self.show_custom_result_context_menu)
|
||||
|
||||
table_container.grid_rowconfigure(0, weight=1)
|
||||
@@ -181,6 +184,14 @@ def show_custom_result_context_menu(self, event):
|
||||
1,
|
||||
state=("normal" if can_single_step else "disabled"),
|
||||
)
|
||||
self.custom_result_menu.entryconfigure(
|
||||
3,
|
||||
state=("normal" if has_rows else "disabled"),
|
||||
)
|
||||
self.custom_result_menu.entryconfigure(
|
||||
4,
|
||||
state=("normal" if has_rows else "disabled"),
|
||||
)
|
||||
self.custom_result_menu.tk_popup(event.x_root, event.y_root)
|
||||
finally:
|
||||
self.custom_result_menu.grab_release()
|
||||
@@ -614,3 +625,290 @@ def update_custom_button_visibility(self):
|
||||
# self.status_var.set("已填充 147 行客户模板测试数据")
|
||||
# if hasattr(self, "log_gui"):
|
||||
# self.log_gui.log("已填充 147 行客户模板测试数据", level="success")
|
||||
|
||||
|
||||
def export_custom_template_excel(self):
|
||||
"""将客户模板结果表导出为 Excel 文件(14 列完整数据)"""
|
||||
if not hasattr(self, "custom_result_tree"):
|
||||
return
|
||||
|
||||
items = self.custom_result_tree.get_children()
|
||||
if not items:
|
||||
messagebox.showinfo("提示", "当前没有可导出的数据")
|
||||
return
|
||||
|
||||
import datetime
|
||||
from tkinter import filedialog
|
||||
|
||||
default_name = (
|
||||
f"客户模板结果_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
||||
)
|
||||
save_path = filedialog.asksaveasfilename(
|
||||
title="保存客户模板 Excel 报告",
|
||||
defaultextension=".xlsx",
|
||||
filetypes=[("Excel 文件", "*.xlsx")],
|
||||
initialfile=default_name,
|
||||
)
|
||||
if not save_path:
|
||||
return
|
||||
|
||||
try:
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "客户模板测试结果"
|
||||
|
||||
columns = tuple(self.custom_result_tree["columns"])
|
||||
num_cols = len(columns)
|
||||
# 列字母辅助(A-N,共 14 列,全在单字母范围内)
|
||||
def col_letter(idx_1based):
|
||||
return chr(64 + idx_1based)
|
||||
|
||||
last_col = col_letter(num_cols)
|
||||
|
||||
# ---- 标题行 ----
|
||||
ws.merge_cells(f"A1:{last_col}1")
|
||||
ws["A1"] = "客户模板测试结果"
|
||||
ws["A1"].font = Font(name="微软雅黑", size=16, bold=True, color="FFFFFF")
|
||||
ws["A1"].fill = PatternFill(
|
||||
start_color="4472C4", end_color="4472C4", fill_type="solid"
|
||||
)
|
||||
ws["A1"].alignment = Alignment(horizontal="center", vertical="center")
|
||||
ws.row_dimensions[1].height = 35
|
||||
|
||||
# 写入测试时间
|
||||
ws.merge_cells(f"A2:{last_col}2")
|
||||
ws["A2"] = (
|
||||
f"测试时间:{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
)
|
||||
ws["A2"].font = Font(name="微软雅黑", size=10, color="CCCCCC")
|
||||
ws["A2"].fill = PatternFill(
|
||||
start_color="2F2F2F", end_color="2F2F2F", fill_type="solid"
|
||||
)
|
||||
ws["A2"].alignment = Alignment(horizontal="left", vertical="center")
|
||||
ws.row_dimensions[2].height = 20
|
||||
|
||||
# ---- 表头行 ----
|
||||
thin = Side(style="thin")
|
||||
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||
header_font = Font(name="微软雅黑", size=10, bold=True, color="FFFFFF")
|
||||
header_fill = PatternFill(
|
||||
start_color="70AD47", end_color="70AD47", fill_type="solid"
|
||||
)
|
||||
header_align = Alignment(
|
||||
horizontal="center", vertical="center", wrap_text=True
|
||||
)
|
||||
|
||||
for col_idx, col_name in enumerate(columns, start=1):
|
||||
cell = ws.cell(row=3, column=col_idx, value=col_name)
|
||||
cell.font = header_font
|
||||
cell.fill = header_fill
|
||||
cell.alignment = header_align
|
||||
cell.border = border
|
||||
ws.row_dimensions[3].height = 22
|
||||
|
||||
# ---- 数据行 ----
|
||||
data_font = Font(name="微软雅黑", size=10)
|
||||
data_align = Alignment(horizontal="center", vertical="center")
|
||||
# 数值列(跳过 Pattern 和 No.)以 4 位小数格式输出
|
||||
numeric_col_indices = set(range(2, num_cols))
|
||||
|
||||
for row_offset, item in enumerate(items):
|
||||
row_num = 4 + row_offset
|
||||
values = self.custom_result_tree.item(item, "values")
|
||||
for col_idx, value in enumerate(values, start=1):
|
||||
cell = ws.cell(row=row_num, column=col_idx)
|
||||
cell.font = data_font
|
||||
cell.alignment = data_align
|
||||
cell.border = border
|
||||
# 占位符保持文本,非占位符数值列尝试转为浮点数
|
||||
if (
|
||||
col_idx - 1 in numeric_col_indices
|
||||
and str(value) not in ("---", "--", "")
|
||||
):
|
||||
try:
|
||||
cell.value = float(value)
|
||||
cell.number_format = "0.0000"
|
||||
except (ValueError, TypeError):
|
||||
cell.value = value
|
||||
else:
|
||||
cell.value = value
|
||||
ws.row_dimensions[row_num].height = 20
|
||||
|
||||
# ---- 列宽 ----
|
||||
col_widths = {
|
||||
"Pattern": 14,
|
||||
"No.": 8,
|
||||
"X": 11,
|
||||
"Y": 11,
|
||||
"Z": 11,
|
||||
"x": 10,
|
||||
"y": 10,
|
||||
"Lv": 10,
|
||||
"u'": 10,
|
||||
"v'": 10,
|
||||
"Tcp": 12,
|
||||
"duv": 10,
|
||||
"\u03bbd/\u03bbc": 12,
|
||||
"Pe": 10,
|
||||
}
|
||||
for col_idx, col_name in enumerate(columns, start=1):
|
||||
ws.column_dimensions[col_letter(col_idx)].width = col_widths.get(
|
||||
col_name, 11
|
||||
)
|
||||
|
||||
wb.save(save_path)
|
||||
|
||||
if hasattr(self, "status_var"):
|
||||
self.status_var.set("已导出客户模板 Excel 报告")
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(
|
||||
f"已导出客户模板 Excel 报告: {save_path}", level="success"
|
||||
)
|
||||
messagebox.showinfo("成功", f"Excel 报告已保存到:\n{save_path}")
|
||||
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"导出 Excel 失败: {str(e)}", level="error")
|
||||
messagebox.showerror("错误", f"导出失败:{str(e)}")
|
||||
|
||||
|
||||
def export_custom_template_charts(self):
|
||||
"""生成客户模板图表:xy 色度散点图 + Lv 亮度曲线图,保存为 PNG"""
|
||||
if not hasattr(self, "custom_result_tree"):
|
||||
return
|
||||
|
||||
items = self.custom_result_tree.get_children()
|
||||
if not items:
|
||||
messagebox.showinfo("提示", "当前没有可绘制的数据")
|
||||
return
|
||||
|
||||
import datetime
|
||||
from tkinter import filedialog
|
||||
|
||||
default_name = (
|
||||
f"客户模板图表_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
|
||||
)
|
||||
save_path = filedialog.asksaveasfilename(
|
||||
title="保存客户模板图表",
|
||||
defaultextension=".png",
|
||||
filetypes=[("PNG 图片", "*.png")],
|
||||
initialfile=default_name,
|
||||
)
|
||||
if not save_path:
|
||||
return
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
columns = tuple(self.custom_result_tree["columns"])
|
||||
col_idx_map = {col: idx for idx, col in enumerate(columns)}
|
||||
|
||||
pattern_names, x_vals, y_vals, lv_vals = [], [], [], []
|
||||
for item in items:
|
||||
vals = self.custom_result_tree.item(item, "values")
|
||||
pattern_names.append(str(vals[col_idx_map.get("Pattern", 0)]))
|
||||
for container, key, fallback in (
|
||||
(x_vals, "x", 5),
|
||||
(y_vals, "y", 6),
|
||||
(lv_vals, "Lv", 7),
|
||||
):
|
||||
raw = vals[col_idx_map.get(key, fallback)]
|
||||
try:
|
||||
v = float(raw)
|
||||
container.append(v if np.isfinite(v) and v > -99999998 else None)
|
||||
except (ValueError, TypeError):
|
||||
container.append(None)
|
||||
|
||||
# ---- 绘图 ----
|
||||
fig, (ax_xy, ax_lv) = plt.subplots(
|
||||
1, 2, figsize=(16, 7), facecolor="#1a1a2e"
|
||||
)
|
||||
|
||||
# ── 左图:xy 色度散点图 ──
|
||||
ax_xy.set_facecolor("#0f0f23")
|
||||
ax_xy.set_xlim(0, 0.8)
|
||||
ax_xy.set_ylim(0, 0.9)
|
||||
ax_xy.set_xlabel("x", color="#cccccc", fontsize=11)
|
||||
ax_xy.set_ylabel("y", color="#cccccc", fontsize=11)
|
||||
ax_xy.set_title("xy 色度图", color="#ffffff", fontsize=13, fontweight="bold")
|
||||
ax_xy.tick_params(colors="#aaaaaa", which="both")
|
||||
for spine in ax_xy.spines.values():
|
||||
spine.set_color("#444444")
|
||||
ax_xy.grid(color="#333333", linestyle="--", linewidth=0.5, alpha=0.7)
|
||||
|
||||
# D65 白点标注
|
||||
ax_xy.scatter(
|
||||
[0.3127], [0.3290],
|
||||
c="#ffffff", s=100, zorder=5,
|
||||
marker="+", linewidths=2, label="D65",
|
||||
)
|
||||
|
||||
valid_pairs = [
|
||||
(x, y, i)
|
||||
for i, (x, y) in enumerate(zip(x_vals, y_vals))
|
||||
if x is not None and y is not None
|
||||
]
|
||||
if valid_pairs:
|
||||
xs, ys, idxs = zip(*valid_pairs)
|
||||
sc = ax_xy.scatter(
|
||||
xs, ys,
|
||||
c=idxs,
|
||||
cmap="plasma",
|
||||
s=60, zorder=4,
|
||||
edgecolors="#cccccc", linewidths=0.5, alpha=0.9,
|
||||
)
|
||||
cbar = fig.colorbar(sc, ax=ax_xy, pad=0.01)
|
||||
cbar.set_label("测量序号", color="#cccccc", fontsize=10)
|
||||
cbar.ax.yaxis.set_tick_params(color="#aaaaaa")
|
||||
plt.setp(cbar.ax.yaxis.get_ticklabels(), color="#aaaaaa")
|
||||
|
||||
ax_xy.legend(
|
||||
fontsize=9,
|
||||
facecolor="#2a2a3e",
|
||||
edgecolor="#555555",
|
||||
labelcolor="#cccccc",
|
||||
)
|
||||
|
||||
# ── 右图:Lv 亮度曲线 ──
|
||||
ax_lv.set_facecolor("#0f0f23")
|
||||
ax_lv.set_title(
|
||||
"Lv 亮度曲线", color="#ffffff", fontsize=13, fontweight="bold"
|
||||
)
|
||||
ax_lv.set_xlabel("测量序号", color="#cccccc", fontsize=11)
|
||||
ax_lv.set_ylabel("Lv (cd/m²)", color="#cccccc", fontsize=11)
|
||||
ax_lv.tick_params(colors="#aaaaaa", which="both")
|
||||
for spine in ax_lv.spines.values():
|
||||
spine.set_color("#444444")
|
||||
ax_lv.grid(color="#333333", linestyle="--", linewidth=0.5, alpha=0.7)
|
||||
|
||||
valid_lv = [(i + 1, lv) for i, lv in enumerate(lv_vals) if lv is not None]
|
||||
if valid_lv:
|
||||
seq, lvs = zip(*valid_lv)
|
||||
ax_lv.plot(
|
||||
seq, lvs,
|
||||
color="#4fc3f7", linewidth=1.5,
|
||||
marker="o", markersize=4,
|
||||
markerfacecolor="#ff8c00", markeredgecolor="#ff8c00",
|
||||
)
|
||||
ax_lv.fill_between(seq, lvs, alpha=0.15, color="#4fc3f7")
|
||||
|
||||
plt.tight_layout(pad=2.0)
|
||||
fig.savefig(save_path, dpi=200, bbox_inches="tight",
|
||||
facecolor=fig.get_facecolor())
|
||||
plt.close(fig)
|
||||
|
||||
if hasattr(self, "status_var"):
|
||||
self.status_var.set("已生成客户模板图表")
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(
|
||||
f"已生成客户模板图表: {save_path}", level="success"
|
||||
)
|
||||
messagebox.showinfo("成功", f"图表已保存到:\n{save_path}")
|
||||
|
||||
except Exception as e:
|
||||
if hasattr(self, "log_gui"):
|
||||
self.log_gui.log(f"生成图表失败: {str(e)}", level="error")
|
||||
messagebox.showerror("错误", f"生成图表失败:{str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user