假设你有如下数据,
姓名 | 科目 | 成绩 |
小黑 | 语文 | 42 |
小娜 | 语文 | 23 |
小白 | 语文 | 98 |
小乐 | 语文 | 52 |
小黑 | 数学 | 30 |
小娜 | 数学 | 76 |
小白 | 数学 | 47 |
小乐 | 数学 | 73 |
小黑 | 英语 | 63 |
小娜 | 英语 | 83 |
小白 | 英语 | 4 |
小乐 | 英语 | 71 |
想生成一个透视表,你肯定要去Excel工具里面操作,但是呢,数据多了可能会出错,所以我们可以借助python提供的 pandas 模块进行透视表生成。
python透视表 生成演示
话不多说,我们先来看看生成后表格的数据项:
如上就是pandas生成的 Excel透视表,数据一目了然,看的非常清楚直观,前面两行和第四行是代码生成、便于拥有多个数据时进行区分的,如不需要,可进行删除,ALL是成绩的总和。
下面开始上代码教程
这个工具是用Tkinter模块开发的,所以先导入Tkinter相关模块。
import tkinter as tk import tkinter.font as tkFont from tkinter.filedialog import askdirectory import tkinter.messagebox import tkinter.filedialog
对于Tkinter图形界面详细开发教程这里就不多说,可自行百度。或者可查看
Python GUI之tkinter窗口视窗教程大集合
还有一些其他的模块也一并导入
import os import pandas as pd import numpy as np from pylab import mpl from matplotlib import pyplot as plt import tkinter as tk import tkinter.font as tkFont from tkinter.filedialog import askdirectory import tkinter.messagebox import tkinter.filedialog
然后新建一个GUI界面,并在GUI界面添加如下操作元素:两个输入框和两个按钮,分别用来选择需要操作的Excel表和选择保存的文件夹。还有另外三个输入框与按钮,分别用来选择显示在透视表左边和透视表上方的数据项,以及需要比较的数据项,最后是一个清除输入框内容的按钮和一个生成文件的按钮。
示例图如下:
上方的图表功能这篇文章暂不讨论,下次再拿出来分享。
好了,现在开始放代码
import os import pandas as pd import numpy as np import tkinter as tk import tkinter.font as tkFont from tkinter.filedialog import askdirectory import tkinter.messagebox import tkinter.filedialog from pylab import mpl from matplotlib import pyplot as plt #制作图表时,需要加入这段代码,不然生成的图标会乱码 mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] window = tk.Tk() window.title('透视表生成(通用版)') # 获取屏幕宽高 sw = window.winfo_screenwidth() sh = window.winfo_screenheight() # 设置屏幕的宽和高 ww = 600 wh = 500 x = (sw - ww) / 2 y = (sh - wh) / 2 # 根据屏幕宽高来让程序居中 window.geometry("%dx%d+%d+%d" % (ww, wh, x, y)) window.resizable(width=False, height=False) # 设置字体 fontStyle = tkFont.Font(family="Lucida Grande", size=15) fontStyleRadio = tkFont.Font(family="Lucida Grande", size=13) # 应用标题 tk.Label(window, text="透视表生成(通用版)", font=fontStyle).pack() dataState = "" ty = "0" def askd(): if ty == "1": tks2() global paths # 打开文件 设置只能打开xls和xlsx文件 paths = tkinter.filedialog.askopenfilename(title='打开表格', filetypes=[("xlsx", ".xlsx"), ("xls", ".xls")]) path.set(paths) cc = paths.endswith(".xls") # 进行表格数据读取,将第一行数据放入Listbox中进行后续选择 if cc == True: df = pd.read_excel(paths) else: df = pd.read_excel(paths, engine='openpyxl') labels = list(df.columns) global lb lb = tk.Listbox(window, font=fontStyle) for ite in labels: lb.insert('end', ite) lb.pack() print(paths) tks() # 如果第二次选择表格,就将ty设置为1,当ty=1时,清空 Listbox 的数据 def tks(): global ty ty = "1" def tks2(): lb.destroy() index__ = [] # 左边的数值 def lbs1(): tPath1.set(tPath1.get() + lb.get(lb.curselection()) + "、") index__.append(lb.get(lb.curselection())) # 顶部的数值 def lbs2(): tPath2.set(lb.get(lb.curselection())) global values_ values2_ = [] # 要比较的数据 def lbs3(): tPath3.set(tPath3.get() + lb.get(lb.curselection()) + "、") values2_.append(lb.get(lb.curselection())) # 选择要保存的文件夹 def askd2(): global paths2 paths2 = askdirectory() + "/" path2.set(paths2) print(paths2) # 设置frame容器 frame = tk.Frame(window, padx=3, pady=3) frame.pack() frame_left = tk.Frame(frame) frame_right = tk.Frame(frame) frame_left.pack(side='left') frame_right.pack(side='right') # 选择文件和选择文件夹的输入框 path = tk.StringVar() path2 = tk.StringVar() e1 = tk.Entry(frame_left, textvariable=path, width=50).pack(padx=5, pady=10) e2 = tk.Entry(frame_left, textvariable=path2, width=50).pack(padx=5, pady=10) # 三个数值的输入框 tPath1 = tk.StringVar() tPath2 = tk.StringVar() tPath3 = tk.StringVar() t1 = tk.Entry(frame_left, textvariable=tPath1, width=50) t2 = tk.Entry(frame_left, textvariable=tPath2, width=50) t3 = tk.Entry(frame_left, textvariable=tPath3, width=50) t1.pack(padx=5, pady=10) t2.pack(padx=5, pady=10) t3.pack(padx=5, pady=10) # 按钮 tk.Button(frame_right, text='选择文件', font=fontStyle, width=18, height=1, command=lambda: askd()).pack(padx=3, pady=3) tk.Button(frame_right, text='选择保存的文件夹', font=fontStyle, width=18, height=1, command=lambda: askd2()).pack(padx=3,pady=3) tk.Button(frame_right, text='左边的数值', font=fontStyle, width=18, height=1, command=lambda: lbs1()).pack(padx=3, pady=3) tk.Button(frame_right, text='顶部的数值', font=fontStyle, width=18, height=1, command=lambda: lbs2()).pack(padx=3, pady=3) tk.Button(frame_right, text='比较的数据', font=fontStyle, width=18, height=1, command=lambda: lbs3()).pack(padx=3, pady=3) frame2 = tk.Frame(window, padx=3, pady=3) frame2.pack() frame_left_01 = tk.Frame(frame2) frame_right_01 = tk.Frame(frame2) frame_left_01.pack(side='left') frame_right_01.pack(side='right') frame_left_02 = tk.Frame(frame_left_01) frame_right_02 = tk.Frame(frame_left_01) frame_left_02.pack(side='left') frame_right_02.pack(side='right') frame_left_03 = tk.Frame(frame_right_01) frame_right_03 = tk.Frame(frame_right_01) frame_left_03.pack(side='left') frame_right_03.pack(side='right') # 生成图表的单选按钮 var_1 = tk.StringVar() var_1.set('A') r1 = tk.Radiobutton(frame_left_02, text='不生成图表', font=fontStyleRadio, variable=var_1, value='A',).pack(padx=3, pady=3) r2 = tk.Radiobutton(frame_right_02, text='生成折线图', font=fontStyleRadio, variable=var_1, value='B',).pack(padx=3, pady=3) r3 = tk.Radiobutton(frame_left_03, text='生成柱状横图', font=fontStyleRadio, variable=var_1, value='C',).pack(padx=3, pady=3) r4 = tk.Radiobutton(frame_right_03, text='生成柱状竖图', font=fontStyleRadio, variable=var_1, value='D',).pack(padx=3, pady=3) frame = tk.Frame(window, padx=3, pady=3) frame.pack() frame_left2 = tk.Frame(frame) frame_right2 = tk.Frame(frame) frame_left2.pack(side='left') frame_right2.pack(side='right') tk.Button(frame_left2, text='清空', font=fontStyle, width=15, height=1, command=lambda: qk()).pack(padx=3, pady=3) tk.Button(frame_right2, text='开始转换', font=fontStyle, width=15, height=1, command=lambda: ts(paths, paths2, t2.get(), t3.get(), var_1.get())).pack(padx=3, pady=3) # 清空内容的方法 def qk(): lb.destroy() path.set('') path2.set('') tPath1.set('') tPath2.set('') tPath3.set('') index__.clear() values2_.clear() # 关键方法!!! 透视表生成的方法 def ts(path, paths2, columns_, values_, vars): # path 路径名 左边显示名称 # 首先检测选择的文件是xls还是xlsx,如果说xls就用xlrd读取文件,不用额外填写。 # 如果是xlsx,就要设置engine='openpyxl',使用openpyxl读取xlsx。 xlrd不能读取xlsx,openpyxl也不能读取xls文件。 cc = path.endswith(".xls") if cc == True: df = pd.read_excel(paths) else: df = pd.read_excel(paths, engine='openpyxl') # index: 左边的数值 columns: 最上面的数值 values: 要比较的数值 aggfunc:有相同数据时相加 fill_value:空值设置为0 margins:求和 c1 = df.pivot_table(index=index__, columns=[columns_], values=values2_, aggfunc=[np.sum], dropna=False, fill_value=0, margins=True) val_ = values_.replace('、', '') p11 = paths2 + val_ + '.xlsx' # 生成Excel文件 c1.to_excel(p11) if vars != 'A': if vars == 'B': c1.plot(kind='line') if vars == 'C': c1.plot(kind='barh') if vars == 'D': c1.plot(kind='bar') # 生成图表 plt.savefig(paths2 + val_ + '.png') plt.show() ts = tkinter.messagebox.showinfo(title='提示', message="转换成功!") if ts == 'ok': os.startfile(p11) # 窗口循环显示 window.mainloop()
如有不懂,可在下方提问。