表格内容如下图所示


绘图后的数据如下图所示:

代码
python
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
'''
20260911 hao
简化版:提取指定行列,第一行表头直接作为图例
表格样例:第1行表头A B C D,第2行起数据,X轴取自指定列
'''
class SimpleTablePlotGUI:
def __init__(self, root):
self.root = root
self.root.title("简单表格绘图|表头作为图例")
self.root.geometry("1000x720")
self.file_path = tk.StringVar()
self.sheet_list = []
self.df_raw = None
# ========= 行列配置:Excel原生行号从1开始 =========
self.cfg_header_row = tk.StringVar(value="1") # 表头(图例)行
self.cfg_data_start_row = tk.StringVar(value="2") # 数据起始行
self.cfg_col_x = tk.StringVar(value="1") # X轴所在列
self.full_header = []
# -------- 文件选择区 --------
frame_file = ttk.LabelFrame(root, text="1.选择Excel文件 & Sheet")
frame_file.pack(fill="x", padx=10, pady=4)
ttk.Label(frame_file, text="文件路径:").grid(row=0, column=0, padx=5, pady=6)
ttk.Entry(frame_file, textvariable=self.file_path, width=70).grid(row=0, column=1)
ttk.Button(frame_file, text="浏览", command=self.select_file).grid(row=0, column=2, padx=5)
ttk.Label(frame_file, text="Sheet名称:").grid(row=1, column=0, padx=5, pady=6)
self.sheet_combo = ttk.Combobox(frame_file, state="readonly", width=66)
self.sheet_combo.grid(row=1, column=1)
# -------- 行列配置区 --------
frame_cfg = ttk.LabelFrame(root, text="2.行列配置【Excel原生行号,从1开始】")
frame_cfg.pack(fill="x", padx=10, pady=4)
ttk.Label(frame_cfg, text="表头(图例)行号:").grid(row=0, column=0, padx=4, pady=4, sticky="e")
ttk.Entry(frame_cfg, textvariable=self.cfg_header_row, width=8).grid(row=0, column=1, padx=4)
ttk.Label(frame_cfg, text="数据起始行号:").grid(row=0, column=2, padx=4, pady=4, sticky="e")
ttk.Entry(frame_cfg, textvariable=self.cfg_data_start_row, width=8).grid(row=0, column=3, padx=4)
ttk.Label(frame_cfg, text="X轴数据列号:").grid(row=0, column=4, padx=4, pady=4, sticky="e")
ttk.Entry(frame_cfg, textvariable=self.cfg_col_x, width=8).grid(row=0, column=5, padx=4)
# -------- 勾选绘图数据列 --------
frame_col = ttk.LabelFrame(root, text="3.勾选要绘制的数据列(表头自动作为图例名称)")
frame_col.pack(fill="both", expand=True, padx=10, pady=4)
self.col_check_frame = ttk.Frame(frame_col)
self.col_check_frame.pack(fill="both", expand=True, padx=4, pady=3)
self.col_vars = {}
# -------- 按钮 --------
frame_btn = ttk.Frame(root)
frame_btn.pack(pady=6)
ttk.Button(frame_btn, text="加载Sheet数据", command=self.load_sheet_data).grid(row=0, column=0, padx=12)
ttk.Button(frame_btn, text="执行绘图", command=self.do_plot).grid(row=0, column=1, padx=12)
# -------- 日志输出 --------
self.info_text = tk.Text(root, height=10, wrap="word")
self.info_text.pack(fill="x", padx=10, pady=3)
self.log("就绪:选择Excel,设置行列,勾选数据列绘图,表格第一行直接作为图例")
def log(self, msg):
self.info_text.insert(tk.END, msg + "\n")
self.info_text.see(tk.END)
self.root.update_idletasks()
@staticmethod
def normalize_str(val):
if pd.isna(val):
return ""
return str(val).strip()
def _parse_int(self, text):
try:
return int(text.strip())
except ValueError:
return None
def select_file(self):
fp = filedialog.askopenfilename(filetypes=[("Excel xlsx", "*.xlsx")])
if not fp:
return
self.file_path.set(fp)
excel_file = pd.ExcelFile(fp)
self.sheet_list = excel_file.sheet_names
self.sheet_combo["values"] = self.sheet_list
if self.sheet_list:
self.sheet_combo.current(0)
self.log(f"已选择文件:{fp}")
def load_sheet_data(self):
fp = self.file_path.get()
sheet_name = self.sheet_combo.get()
if not fp or not sheet_name:
messagebox.showwarning("警告", "请先选择文件和sheet")
return
h_row = self._parse_int(self.cfg_header_row.get())
data_start_excel = self._parse_int(self.cfg_data_start_row.get())
x_col = self._parse_int(self.cfg_col_x.get())
if None in [h_row, data_start_excel, x_col]:
messagebox.showerror("输入错误", "行列号必须填写整数(Excel原生行/列号)")
return
try:
self.df_raw = pd.read_excel(fp, sheet_name=sheet_name, header=None)
# 读取表头行
header_pd_idx = h_row - 1
self.full_header = []
for c in range(len(self.df_raw.columns)):
self.full_header.append(self.normalize_str(self.df_raw.iloc[header_pd_idx, c]))
self.log(f"✅加载成功|表头行={h_row}, 数据起始行={data_start_excel}")
self.refresh_column_checkbox()
except Exception as e:
self.log(f"❌读取异常:{str(e)}")
messagebox.showerror("错误", str(e))
def refresh_column_checkbox(self):
for widget in self.col_check_frame.winfo_children():
widget.destroy()
self.col_vars.clear()
ui_row = 0
for col_idx, col_name in enumerate(self.full_header):
disp = f"列{col_idx+1}|{col_name}"
var = tk.BooleanVar()
cb = ttk.Checkbutton(self.col_check_frame, text=disp, variable=var)
cb.grid(row=ui_row//4, column=ui_row%4, sticky="w", padx=4, pady=2)
self.col_vars[col_idx] = var
ui_row += 1
@staticmethod
def is_invalid(val):
if pd.isna(val):
return True
s = str(val).strip()
return s in ["#N/A", "#DIV/0!", "nan", ""]
def do_plot(self):
if self.df_raw is None:
messagebox.showwarning("警告", "请先加载Sheet数据")
return
data_start_pd = self._parse_int(self.cfg_data_start_row.get()) - 1
x_col_idx = self._parse_int(self.cfg_col_x.get()) - 1
selected_cols = [c for c, v in self.col_vars.items() if v.get()]
if len(selected_cols) == 0:
messagebox.showwarning("警告", "请至少勾选一列绘图数据")
return
marker_list = ["o", "s", "^", "D", "v", "*", "p", "X"]
color_list = plt.cm.tab10(np.linspace(0,1,10))
fig, ax = plt.subplots(figsize=(13, 7))
for plot_idx, c in enumerate(selected_cols):
label_text = self.full_header[c]
x_data = []
y_data = []
for ridx in range(data_start_pd, len(self.df_raw)):
x_cell = self.df_raw.iloc[ridx, x_col_idx]
y_cell = self.df_raw.iloc[ridx, c]
if self.is_invalid(x_cell) or self.is_invalid(y_cell):
continue
try:
xv = float(x_cell)
yv = float(y_cell)
x_data.append(xv)
y_data.append(yv)
except ValueError:
continue
if len(x_data) == 0:
self.log(f"⚠️列{c+1}({label_text})无有效数值,跳过")
continue
mk = marker_list[plot_idx % len(marker_list)]
clr = color_list[plot_idx % len(color_list)]
ax.plot(x_data, y_data, marker=mk, linestyle="-", label=label_text, color=clr)
ax.set_xlabel(f"X轴 - 列{x_col_idx+1}", fontsize=14)
ax.set_ylabel("Y值", fontsize=14)
ax.set_title("表格数据绘图(表头作为图例)", fontsize=15)
ax.grid(alpha=0.35)
ax.legend(fontsize=11)
plt.tight_layout()
fig.show()
self.log(f"✅绘图完成,共绘制 {len(selected_cols)} 条曲线")
if __name__ == "__main__":
root = tk.Tk()
app = SimpleTablePlotGUI(root)
root.mainloop()