Python—一键实现Excel自动分组合并单元格

大家好,我们经常会有这样的需求。比如下图
在这里插入图片描述
我们需要把同一个省份的合并起来,如下图的效果
在这里插入图片描述
如何实现呢,这是原有的df
在这里插入图片描述
直观的操作是这样的:

df.to_excel('test.xlsx',index=False)
from openpyxl import load_workbook
wb=load_workbook('test.xlsx')
ws=wb.active()
ws.merge_cells(start_row=2,end_row=8,start_column=1,end_column=1)
ws.merge_cells(start_row=2,end_row=8,start_column=2,end_column=2)
ws.merge_cells(start_row=9,end_row=14,start_column=1,end_column=1)
ws.merge_cells(start_row=9,end_row=14,start_column=2,end_column=2)
ws.merge_cells(start_row=15,end_row=18,start_column=1,end_column=1)
ws.merge_cells(start_row=15,end_row=18,start_column=2,end_column=2)
wb.save()

只是问题在于我们不能总是人工判断start_row和end_row,如何能使程序自动获取row的起始点呢?其实我们使用一个groupby就发现了方法了!大家看到了吗?
在这里插入图片描述
真是柳暗花明又一村啊,完整解决方案已经有了,我封装到了tkinter里面,请看!

#-*- coding:utf-8 -*-
import tkinter as tk #使用Tkinter前需要先导入
from tkinter import filedialog,messagebox,ttk
from openpyxl import load_workbook
from openpyxl.styles import Alignment
import os
import pandas as pd
#建立窗口window
window = tk.Tk()
window.title('Excel合并单元格工具')
w_width=630
w_height=600
scn_width=window.maxsize()[0]
x_point=(scn_width-w_width)//2
window.geometry('%dx%d+%d+%d' %(w_width,w_height,x_point,100))
window.wm_attributes('-topmost',True)
window.tk_focusFollowsMouse()
window.bind("<Escape>",lambda event:window.iconify())

path_tar=tk.StringVar()
sheetvar=tk.StringVar()       #目标工作表
#打开目标文件
def getmergefile():
  file_path=filedialog.askopenfilename(title=u'选择文件',filetype=[('Excel','.xlsx')])
  path_tar.set(file_path)
  alldata=pd.read_excel(file_path,None)
  ttk.Label(frame1,text="请选择目标工作表:").grid(row=1,column=0,sticky='w')
  global sheetvar
  chosen_sheet=ttk.Combobox(frame1,width=16,textvariable=sheetvar) 
  chosen_sheet['values']=list(alldata)
  chosen_sheet.grid(row=1,column=1,sticky='w')
  chosen_sheet.bind("<<ComboboxSelected>>",lambda event:getmergeseg(event,alldata,sheetvar.get()))
#勾选目标字段
def getmergeseg(event,alldata,sheet):
  global frame2,segvars
  segvars=[] 
  try:
    frame2.destroy()
  except:
    pass
  frame2=tk.Frame(window,padx=15,pady=6)
  frame2.grid(row=1,column=0,sticky='w')
  ttk.Label(frame2,text="请勾选分组合并的目标字段(第一个勾选框为分组合并依据,必须事先进行排序:").grid(row=0,column=0,columnspan=4,sticky='w')
  data=alldata[sheet]
  for index,item in enumerate(data.columns):
    segvars.append(tk.StringVar()) 
    ttk.Checkbutton(frame2,text=item,variable=segvars[-1],onvalue=item,offvalue='').grid(row=(index//4+1),column=index%4,sticky='w')
#合并字段单元格
def merging(file,sheet,segvars):
  selected=[i.get() for i in segvars if i.get()]
  df=pd.read_excel(file,sheet)
  wb=load_workbook(file)
  ws=wb[sheet]
  mergecells(ws,df,selected)
  try:
    wb.save(file)
    messagebox.showinfo('提示',file+'-'+sheet+'指定单元格合并完成')
    os.system('start '+os.path.dirname(file))
  except Exception as e:
    messagebox.showerror('警告',str(e))
#合并单元格函数
def mergecells(ws,df,cols):
  col=cols[0]
  gdic=df.groupby(col).groups 
  aligncenter=Alignment(horizontal='center',vertical='center')
  for gname in gdic:
    indexs=gdic[gname]+2
    indexs=indexs.sort_values()
    for col in cols:		#每一个要合并的字段
      colindex=df.columns.tolist().index(col)+1
      ws.merge_cells(start_row=indexs[0],end_row=indexs[-1],start_column=colindex,end_column=colindex)	#合并
      for i in range(1,ws.max_row+1):		#实现居中
        ws.cell(row=i,column=colindex).alignment=aligncenter

def manual(): #使用说明
  info="""
  作用是合并单元格,把同样内容的单元格合并到一起,所以必须实现对目标字段进行排序,否则无法实现合并
  """
  messagebox.showinfo('提示',info)

frame1=tk.Frame(window,pady=6,padx=15)
frame1.grid(row=0,column=0,sticky='w')
ttk.Button(frame1,text="打开目标文件",command=getmergefile).grid(row=0,column=0,sticky='w')
ttk.Entry(frame1,textvariable=path_tar,width=40).grid(row=0,column=1)
frame3=tk.Frame(window,pady=10,padx=15)
frame3.grid(row=2,column=0,sticky='w')
ttk.Button(frame3,text="点击合并单元格",command=lambda:merging(path_tar.get(),sheetvar.get(),segvars)).grid(row=0,column=0,sticky='w')
ttk.Button(frame3,text="使用说明",command=manual).grid(row=0,column=1)

window.mainloop()

效果如图:
在这里插入图片描述

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值