Tkinter Treeview转DataFrame绘Matplotlib图表无折线问题排查
问题:Tkinter Treeview数据转Pandas DataFrame后,Matplotlib折线图无显示
我编写了Python代码,试图将Tkinter Treeview中插入的数据转换为Pandas DataFrame,筛选出年份为2023、2024且dc_options为Pondok Ungu的数据后绘制Matplotlib折线图表,但点击图表按钮后图表中无折线显示。
原代码
#create a function for the insert data button def insert_data(): from tkinter import messagebox year = year_button.get() month = month_button.get() product_categories = product_categories_button.get() dc_options = dc_options_button.get() actual_data = int(actual_spinbox.get()) forecast_data = int(forecast_spinbox.get()) accuracy = (((forecast_data - actual_data) / actual_data) * 100 ) messagebox.askyesno("Confirmation", "Do You Want to Input this Data?") value = year, month, product_categories, dc_options, forecast_data, actual_data, accuracy forecast_table.insert("", index='end', values=value) return accuracy #create a function to option of show forecast accuracy chart for 2023 row_list = [] column = ('year', 'month', 'product_categories', 'dc_options', 'forecast_data', 'actual_data', 'accuracy') for child in forecast_table.get_children(): row_list.append([forecast_table.item(child)['values']]) forecast_table_dataframe = pd.DataFrame(row_list, columns=column) #create a multi-condition filter to show the forecast accuracy chart for year 2023, dc place = pondok ungu filtered_forecast_table_dataframe_2023_pondok_ungu = forecast_table_dataframe.loc[(forecast_table_dataframe['year'] == 2023) & (forecast_table_dataframe['dc_options']=='Pondok Ungu')] #create a graph for forecasta accuracy chart year 2023, dc place pondok ungu: Forecast Accuracy in Each Month for Each Product Categories in 2023 fig1, ax1 = plt.subplots() ax1.set_xlabel('Month') ax1.set_ylabel('Forecast Accuracy') ax1.xaxis.set_major_formatter(mdates.DateFormatter('%b')) ax1.set_title("Forecast Accuracy in Each Month for Each Product Categories in 2023") ax1.plot(filtered_forecast_table_dataframe_2023_pondok_ungu['month'], filtered_forecast_table_dataframe_2023_pondok_ungu['accuracy'], label='Accuracy') ax1.plot(filtered_forecast_table_dataframe_2023_pondok_ungu['month'], filtered_forecast_table_dataframe_2023_pondok_ungu['product_categories'], label= 'Product Categories') ax1.legend() #create a graph for forecast accuracy chart year 2023, dc place pondok ungu: Actual vs Forecast Data for Each Month in 2023 fig2, ax2 = plt.subplots() ax2.set_xlabel('Month') ax2.set_ylabel('Actual Data') ax2.xaxis.set_major_formatter(mdates.DateFormatter('%b')) ax2.plot(filtered_forecast_table_dataframe_2023_pondok_ungu['month'], filtered_forecast_table_dataframe_2023_pondok_ungu['actual_data'], label='Actual Data') ax2.plot(filtered_forecast_table_dataframe_2023_pondok_ungu['month'], filtered_forecast_table_dataframe_2023_pondok_ungu['forecast_data'], label='Forecast Data') ax2.legend() ax2.set_title('Actual vs Forecast Data for Each Month in 2023') #create a multi-condition filter to show the forecast accuracy chart for year 2024, dc place = pondok ungu filtered_forecast_table_dataframe_2024_pondok_ungu = forecast_table_dataframe.loc[(forecast_table_dataframe['year'] == 2024) & (forecast_table_dataframe['dc_options'] == 'Pondok Ungu')] #create a graph for forecast accuracy chart year 2023, dc place pondok ungu: Actual vs Forecast Data for Each Month in 2024 fig3, ax3 = plt.subplots() ax3.set_xlabel('Month') ax3.set_ylabel('Actual Data') ax3.xaxis.set_major_formatter(mdates.DateFormatter('%b')) ax3.plot(filtered_forecast_table_dataframe_2024_pondok_ungu['month'], filtered_forecast_table_dataframe_2024_pondok_ungu['actual_data'], label='Actual Data') ax3.plot(filtered_forecast_table_dataframe_2024_pondok_ungu['month'], filtered_forecast_table_dataframe_2024_pondok_ungu['forecast_data'], label='Forecast Data') ax3.legend() ax3.set_title('Actual vs Forecast Data for Each Month in 2024') #create a graph for forecasta accuracy chart year 2024, dc place pondok ungu: Forecast Accuracy in Each Month for Each Product Categories in 2023 fig4, ax4 = plt.subplots() ax4.xaxis.set_major_formatter(mdates.DateFormatter('%b')) ax4.set_xlabel('Month') ax4.set_ylabel('Forecast Accuracy') ax4.set_title("Forecast Accuracy in Each Month for Each Product Categories in 2024") ax4.plot(filtered_forecast_table_dataframe_2024_pondok_ungu['month'], filtered_forecast_table_dataframe_2024_pondok_ungu['forecast_data'], label='Forecast Data') ax4.plot(filtered_forecast_table_dataframe_2024_pondok_ungu['month'], filtered_forecast_table_dataframe_2024_pondok_ungu['product_categories'], label='Product Categories') ax4.legend()
问题分析与修复方案
1. Treeview数据转换错误
原代码中row_list.append([forecast_table.item(child)['values']])添加了嵌套列表,导致DataFrame的每一行都是列表对象,而非扁平的数值,后续筛选逻辑完全失效。
修复:直接appendforecast_table.item(child)['values'],去掉外层列表:
row_list.append(forecast_table.item(child)['values'])
2. 数据类型不匹配
year_button.get()获取的是字符串类型,而筛选条件用的是整数2023/2024,两者比较结果为空,导致筛选后的数据框无内容,自然画不出折线。
修复:插入数据时将year转为整数:
year = int(year_button.get())
3. 日期格式化与无效绘图逻辑错误
month是字符串(如"01"),不是日期类型,使用mdates.DateFormatter('%b')会报错;product_categories是分类文本,无法用折线图绘制(折线图要求数值型数据)。
修复:将month转为月份缩写,移除对product_categories的折线绘制:
month_map = {1:'Jan',2:'Feb',3:'Mar',4:'Apr',5:'May',6:'Jun',7:'Jul',8:'Aug',9:'Sep',10:'Oct',11:'Nov',12:'Dec'} forecast_table_dataframe['month_name'] = forecast_table_dataframe['month'].astype(int).map(month_map)
4. 图表逻辑未绑定到按钮回调
原代码中数据读取和绘图逻辑是直接执行的,不是绑定到图表按钮的点击事件,导致点击按钮时不会重新读取Treeview的最新数据,始终使用初始空数据。
修复:将所有数据读取、筛选、绘图逻辑封装到一个函数,绑定到图表按钮的command参数:
def show_charts(): row_list = [] columns = ('year', 'month', 'product_categories', 'dc_options', 'forecast_data', 'actual_data', 'accuracy') for child in forecast_table.get_children(): row_list.append(forecast_table.item(child)['values']) if not row_list: messagebox.showwarning("Warning", "No data available to plot") return # 后续筛选和绘图逻辑放在这里...
5. 消息框确认未生效
原代码中messagebox.askyesno的返回值未处理,不管用户点击"是"还是"否"都会插入数据。
修复:根据返回值判断是否插入:
if messagebox.askyesno("Confirmation", "Do You Want to Input this Data?"): value = year, month, product_categories, dc_options, forecast_data, actual_data, accuracy forecast_table.insert("", index='end', values=value)
修正后的完整代码示例
import tkinter as tk from tkinter import ttk, messagebox import pandas as pd import matplotlib.pyplot as plt # 初始化主窗口 root = tk.Tk() root.title("Forecast Data Manager") # 基础控件定义 year_button = ttk.Entry(root) month_button = ttk.Entry(root) product_categories_button = ttk.Entry(root) dc_options_button = ttk.Entry(root) actual_spinbox = ttk.Spinbox(root, from_=0, to=10000) forecast_spinbox = ttk.Spinbox(root, from_=0, to=10000) forecast_table = ttk.Treeview(root, columns=('year', 'month', 'product_categories', 'dc_options', 'forecast_data', 'actual_data', 'accuracy'), show='headings') # 设置Treeview表头 for col in ('year', 'month', 'product_categories', 'dc_options', 'forecast_data', 'actual_data', 'accuracy'): forecast_table.heading(col, text=col) forecast_table.column(col, width=100) # 插入数据函数 def insert_data(): try: year = int(year_button.get()) month = int(month_button.get()) product_categories = product_categories_button.get() dc_options = dc_options_button.get() actual_data = int(actual_spinbox.get()) forecast_data = int(forecast_spinbox.get()) accuracy = (((forecast_data - actual_data) / actual_data) * 100 ) if messagebox.askyesno("Confirmation", "Do You Want to Input this Data?"): value = (year, month, product_categories, dc_options, forecast_data, actual_data, accuracy) forecast_table.insert("", index='end', values=value) return accuracy except ValueError: messagebox.showerror("Error", "Please enter valid numeric values for year, month, actual and forecast data") # 显示图表函数 def show_charts(): row_list = [] columns = ('year', 'month', 'product_categories', 'dc_options', 'forecast_data', 'actual_data', 'accuracy') for child in forecast_table.get_children(): row_list.append(forecast_table.item(child)['values']) if not row_list: messagebox.showwarning("Warning", "No data available to plot") return forecast_table_dataframe = pd.DataFrame(row_list, columns=columns) # 转换数据类型 forecast_table_dataframe['year'] = forecast_table_dataframe['year'].astype(int) forecast_table_dataframe['month'] = forecast_table_dataframe['month'].astype(int) # 映射月份为缩写 month_map = {1:'Jan',2:'Feb',3:'Mar',4:'Apr',5:'May',6:'Jun',7:'Jul',8:'Aug',9:'Sep',10:'Oct',11:'Nov',12:'Dec'} forecast_table_dataframe['month_name'] = forecast_table_dataframe['month'].map(month_map) # 2023年Pondok Ungu数据筛选 filtered_2023 = forecast_table_dataframe.loc[(forecast_table_dataframe['year'] == 2023) & (forecast_table_dataframe['dc_options']=='Pondok Ungu')] # 2024年Pondok Ungu数据筛选 filtered_2024 = forecast_table_dataframe.loc[(forecast_table_dataframe['year'] == 2024) & (forecast_table_dataframe['dc_options']=='Pondok Ungu')] # 绘制2023年准确率图表 if not filtered_2023.empty: fig1, ax1 = plt.subplots() ax1.set_xlabel('Month') ax1.set_ylabel('Forecast Accuracy') ax1.set_title("Forecast Accuracy in Each Month (2023, Pondok Ungu)") ax1.plot(filtered_2023['month_name'], filtered_2023['accuracy'], marker='o', label='Accuracy') ax1.legend() plt.xticks(rotation=45) plt.tight_layout() plt.show() else: messagebox.showinfo("Info", "No data for 2023, Pondok Ungu") # 绘制2023年实际vs预测图表 if not filtered_2023.empty: fig2, ax2 = plt.subplots() ax2.set_xlabel('Month') ax2.set_ylabel('Data Value') ax2.set_title('Actual vs Forecast Data (2023, Pondok Ungu)') ax2.plot(filtered_2023['month_name'], filtered_2023['actual_data'], marker='s', label='Actual Data') ax2.plot(filtered_2023['month_name'], filtered_2023['forecast_data'], marker='^', label='Forecast Data') ax2.legend() plt.xticks(rotation=45) plt.tight_layout() plt.show() # 绘制2024年实际vs预测图表 if not filtered_2024.empty: fig3, ax3 = plt.subplots() ax3.set_xlabel('Month') ax3.set_ylabel('Data Value') ax3.set_title('Actual vs Forecast Data (2024, Pondok Ungu)') ax3.plot(filtered_2024['month_name'], filtered_2024['actual_data'], marker='s', label='Actual Data') ax3.plot(filtered_2024['month_name'], filtered_2024['forecast_data'], marker='^', label='Forecast Data') ax3.legend() plt.xticks(rotation=45) plt.tight_layout() plt.show() else: messagebox.showinfo("Info", "No data for 2024, Pondok Ungu") # 绘制2024年准确率图表 if not filtered_2024.empty: fig4, ax4 = plt.subplots() ax4.set_xlabel('Month') ax4.set_ylabel('Forecast Accuracy') ax4.set_title("Forecast Accuracy in Each Month (2024, Pondok Ungu)") ax4.plot(filtered_2024['month_name'], filtered_2024['accuracy'], marker='o', label='Accuracy') ax4.legend() plt.xticks(rotation=45) plt.tight_layout() plt.show() # 按钮布局 insert_btn = ttk.Button(root, text="Insert Data", command=insert_data) chart_btn = ttk.Button(root, text="Show Charts", command=show_charts) # 放置控件 year_button.pack(pady=2) month_button.pack(pady=2) product_categories_button.pack(pady=2) dc_options_button.pack(pady=2) actual_spinbox.pack(pady=2) forecast_spinbox.pack(pady=2) insert_btn.pack(pady=5) forecast_table.pack(pady=5, fill=tk.BOTH, expand=True) chart_btn.pack(pady=5) root.mainloop()
内容的提问来源于stack exchange,提问作者Dahlia Harahap
相关产品推荐
相关产品推荐

