Tkinter+Matplotlib绘图X轴日期时间标签与网格显示异常求助
Tkinter+Matplotlib图表X轴刻度/网格未对齐最后一条数据的问题
我编写了一个基于Tkinter的图表生成代码,需将DataFrame中的Date与Time字段合并后作为X轴,但X轴的标签和网格显示不符合预期——最后一个网格未对应DataFrame的最后一条日期时间数据。希望X轴能像Y轴一样,从第一条数据的索引位置开始,到最后一条数据的索引位置结束。
代码实现
import tkinter as tk import os from tkinter import filedialog from matplotlib.figure import Figure import pandas as pd import numpy as np import time import tkinter.messagebox from matplotlib.font_manager import FontProperties from pathlib import Path fontP = FontProperties() fontP.set_size('x-small') root= tk.Tk() canvas1 = tk.Canvas(root, width = 800, height = 300) canvas1.pack() label1 = tk.Label(root, text='Data Analyser') label1.config(font=('Arial', 20)) date1=time.strftime("%H-%M-%S,%d-%m-%Y") def get1lineGraph (): global df import_file_path = filedialog.askopenfilename(parent=root) filename=Path(import_file_path).stem isExist = os.path.exists(filename) if not isExist: os.makedirs(filename) df = pd.read_excel (import_file_path) df['Date'] = pd.to_datetime(df['Date']) daytime=df['Time'].astype(str) + '\n' + df['Date'].astype(str) major_ticks_x1 = np.arange(0, len(df.index+1)+3.9, len(df.index+1)/4) minor_ticks_x1 = np.arange(0, len(df.index+1)+3.9, len(df.index+1)/8) if(df[clicked1.get()].max()==df[clicked1.get()].min()): major_ticks_y11 = np.arange(0,14,2) minor_ticks_y11 = np.arange(0,14,4) else: major_ticks_y11 = np.arange(df[clicked1.get()].min(), df[clicked1.get()].max()+3.9, (df[clicked1.get()].max()-df[clicked1.get()].min())/4) minor_ticks_y11 = np.arange(df[clicked1.get()].min(), df[clicked1.get()].max()+3.9, (df[clicked1.get()].max()-df[clicked1.get()].min())/8) x1 = daytime y11 = df[clicked1.get()].astype(float) figure11 = Figure(figsize=(11,4), dpi=100) subplot11 = figure11.add_subplot(1,1,1) t11, = subplot11.plot(x1, y11, color='blue', linestyle='solid', linewidth = 2, label=clicked1.get()) subplot11.set_ylabel(clicked1.get()) subplot11.set_xlabel('Date & Time') subplot11.set_xticks(major_ticks_x1) subplot11.set_xticks(minor_ticks_x1, minor=True) subplot11.set_yticks(major_ticks_y11) subplot11.set_yticks(minor_ticks_y11, minor=True) subplot11.grid(which='both') subplot11.grid(which='minor', alpha=0.2) subplot11.grid(which='major', alpha=0.5) subplot11.set_title(clicked1.get()+' VS Time') subplot11.legend(loc = 'upper left', bbox_to_anchor=(1, 1), prop=fontP) figure11.tight_layout() figure11.savefig(filename+'/Bldg1_'+clicked1.get()+'_'+date1+'.png') tkinter.messagebox.showinfo("Message from Bldg 1.", "Graph is saved in .png file format in your PC.",parent=root) options1 = [ "P1", "P2", "P3", "P4" ] clicked1 = tk.StringVar() clicked1.set( "Select Y-axis Parameter" ) drop1 = tk.OptionMenu( root , clicked1 , *options1 ) canvas1.create_window(250, 100, window=drop1) browseButton_Excel1line = tk.Button(root, text='Generate graph with selected Y-axis', command=get1lineGraph, bg='green', fg='white', font=('helvetica', 12, 'bold')) canvas1.create_window(500, 100, window=browseButton_Excel1line) button1 = tk.Button (root, text='Exit from Building 1!', command=root.destroy, bg='green', fg='white', font=('helvetica', 11, 'bold')) canvas1.create_window(400, 180, window=button1) root.mainloop()
测试用Excel数据
Date Time P1 P2 P3 P4 1-9-2019 9:57:00 114.33 21.07 21.01 0 1-9-2019 9:58:00 114.33 21.07 21.01 0 1-9-2019 9:59:00 6.6 4.63 21.01 0 1-9-2019 10:00:00 5.72 4.05 21.01 0 1-9-2019 10:01:00 5.28 4.05 21.01 0 1-9-2019 10:02:00 5.28 4.05 21.01 0 1-9-2019 10:03:00 5.72 4.05 21.01 0 1-9-2019 10:04:00 5.72 3.76 21.01 0 1-9-2019 10:05:00 5.72 4.05 21.01 0 1-9-2019 10:06:00 5.72 4.05 21.01 0 1-9-2019 10:07:00 5.72 4.05 21.01 0 1-9-2019 10:08:00 5.72 4.05 21.01 0 1-9-2019 10:09:00 5.72 4.05 21.01 0 1-9-2019 10:10:00 5.72 4.34 16.82 0 1-9-2019 10:11:00 5.72 4.34 16.79 0 1-9-2019 10:12:00 5.72 4.34 16.7 0 1-9-2019 10:13:00 5.72 4.34 16.79 0
当前生成的图表

解决方案
问题出在X轴刻度的计算逻辑上,原代码中len(df.index+1)的写法错误,且刻度范围没有精准覆盖到最后一条数据的索引位置。修改以下代码片段即可解决:
修改X轴刻度计算部分
将原代码中的:
major_ticks_x1 = np.arange(0, len(df.index+1)+3.9, len(df.index+1)/4) minor_ticks_x1 = np.arange(0, len(df.index+1)+3.9, len(df.index+1)/8)
替换为:
# 获取最后一条数据的索引值 data_last_index = len(df) - 1 # 生成主刻度:从0到最后索引,均匀分成4段(共5个刻度点) major_ticks_x1 = np.linspace(0, data_last_index, 5) # 生成次刻度:从0到最后索引,均匀分成8段(共9个刻度点) minor_ticks_x1 = np.linspace(0, data_last_index, 9)
代码说明
len(df)-1是DataFrame最后一条数据的索引(因为索引从0开始)np.linspace会生成指定区间内均匀分布的数值,确保首尾刻度精准对应第一条和最后一条数据的位置- 主刻度分成4段(5个点)、次刻度分成8段(9个点),和原代码的分段逻辑保持一致,但范围精准覆盖数据区间
修改后,X轴的网格和刻度会完全对齐到数据的首尾位置,和Y轴的显示逻辑保持一致。
内容的提问来源于stack exchange,提问作者Amit K Kushwaha
相关产品推荐
相关产品推荐

