你有没有遇到过这种情况:12个月销售报表,每个表都有一堆数据。领导说:"把这些合并成一张总表,再做一张柱状图,看看哪个产品卖得最好。"
你打开第一个Excel,Ctrl+A全选,Ctrl+C复制,打开总表,Ctrl+V粘贴。再打开第二个,复制,粘贴……重复12遍。好不容易合完了,又打开Excel插入图表,选数据、选类型、调颜色、改标题……一番操作下来,半天没了。
如果这样的报表每个月都要做一次,一年就浪费了6天。
我写了30行代码,做了一个事:一键合并文件夹里所有Excel文件,同时自动生成图表,柱状图、折线图、饼图随便选。
原来:打开文件1 → 复制 → 粘贴 → 打开文件2 → 复制 → 粘贴 → 重复12遍 → 插入图表 → 调格式 → 半天没了现在:运行脚本 → 输入文件夹路径 → 输入列名 → 几秒钟搞定,合并结果和图表同时出现
效果展示
输入文件夹:
运行工具:
X轴列名:产品名称
Y轴列名:销售额
图表类型:柱状图
几秒钟后得到:
合并结果.xlsx:27行数据,全部合并在一起,自动添加"来源文件"列
图表.png:自动生成的柱状图,一目了然
完整代码
import osimport pandas as pdimport matplotlib.pyplot as pltimport glob# 设置中文字体plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']plt.rcParams['axes.unicode_minus'] = Falsedef merge_excel_and_chart(folder_path, x_column=None, y_column=None, chart_type='bar', output_file="合并结果.xlsx", chart_name="图表.png"):"""合并文件夹中所有Excel文件,并生成图表"""excel_files = glob.glob(os.path.join(folder_path, '*.xlsx')) + glob.glob(os.path.join(folder_path, '*.xls'))if not excel_files:print("❌ 未找到Excel文件")returnprint(f"📂 找到 {len(excel_files)} 个Excel文件")all_data = []for file in excel_files:try:df = pd.read_excel(file)df['来源文件'] = os.path.basename(file)all_data.append(df)print(f" ✅ {os.path.basename(file)} ({len(df)} 行)")except Exception as e:print(f" ❌ {os.path.basename(file)} 读取失败: {str(e)[:30]}")if not all_data:print("❌ 没有成功读取任何文件")returnmerged_df = pd.concat(all_data, ignore_index=True)output_path = os.path.join(folder_path, output_file)merged_df.to_excel(output_path, index=False)print(f"\n✅ 合并完成!共 {len(merged_df)} 行")print(f"📁 合并结果: {output_path}")# 生成图表if x_column and y_column and x_column in merged_df.columns and y_column in merged_df.columns:try:chart_data = merged_df.groupby(x_column)[y_column].sum().reset_index()plt.figure(figsize=(12, 6))if chart_type == 'bar':plt.bar(chart_data[x_column], chart_data[y_column], color='steelblue')plt.title(f'{y_column} 按 {x_column} 汇总(柱状图)', fontsize=14)elif chart_type == 'line':plt.plot(chart_data[x_column], chart_data[y_column], marker='o', linewidth=2, color='coral')plt.title(f'{y_column} 按 {x_column} 汇总(折线图)', fontsize=14)elif chart_type == 'pie':plt.pie(chart_data[y_column], labels=chart_data[x_column], autopct='%1.1f%%')plt.title(f'{y_column} 按 {x_column} 汇总(饼图)', fontsize=14)else:plt.bar(chart_data[x_column], chart_data[y_column], color='steelblue')plt.title(f'{y_column} 按 {x_column} 汇总', fontsize=14)plt.xlabel(x_column, fontsize=12)plt.ylabel(y_column, fontsize=12)plt.xticks(rotation=45)plt.tight_layout()chart_path = os.path.join(folder_path, chart_name)plt.savefig(chart_path, dpi=150, bbox_inches='tight')print(f"📊 图表已保存: {chart_path}")plt.close()except Exception as e:print(f"⚠️ 生成图表失败: {e}")else:print("\n💡 提示: 指定x_column和y_column可自动生成图表")def merge_by_keyword(folder_path, keyword, x_column=None, y_column=None, chart_type='bar', output_file="按关键词合并.xlsx"):"""只合并文件名包含关键词的Excel文件"""excel_files = glob.glob(os.path.join(folder_path, '*.xlsx')) + glob.glob(os.path.join(folder_path, '*.xls'))excel_files = [f for f in excel_files if keyword.lower() in os.path.basename(f).lower()]if not excel_files:print(f"❌ 未找到文件名包含「{keyword}」的Excel文件")returnprint(f"📂 找到 {len(excel_files)} 个匹配的Excel文件")all_data = []for file in excel_files:try:df = pd.read_excel(file)df['来源文件'] = os.path.basename(file)all_data.append(df)print(f" ✅ {os.path.basename(file)} ({len(df)} 行)")except Exception as e:print(f" ❌ {os.path.basename(file)} 读取失败")if not all_data:print("❌ 没有成功读取任何文件")returnmerged_df = pd.concat(all_data, ignore_index=True)output_path = os.path.join(folder_path, output_file)merged_df.to_excel(output_path, index=False)print(f"\n✅ 合并完成!共 {len(merged_df)} 行")print(f"📁 保存至: {output_path}")if x_column and y_column and x_column in merged_df.columns and y_column in merged_df.columns:try:chart_data = merged_df.groupby(x_column)[y_column].sum().reset_index()plt.figure(figsize=(12, 6))if chart_type == 'bar':plt.bar(chart_data[x_column], chart_data[y_column], color='coral')plt.title(f'{y_column} 按 {x_column} 汇总(柱状图)', fontsize=14)elif chart_type == 'line':plt.plot(chart_data[x_column], chart_data[y_column], marker='o', linewidth=2, color='coral')plt.title(f'{y_column} 按 {x_column} 汇总(折线图)', fontsize=14)elif chart_type == 'pie':plt.pie(chart_data[y_column], labels=chart_data[x_column], autopct='%1.1f%%')plt.title(f'{y_column} 按 {x_column} 汇总(饼图)', fontsize=14)else:plt.bar(chart_data[x_column], chart_data[y_column], color='coral')plt.title(f'{y_column} 按 {x_column} 汇总', fontsize=14)plt.xlabel(x_column, fontsize=12)plt.ylabel(y_column, fontsize=12)plt.xticks(rotation=45)plt.tight_layout()chart_path = os.path.join(folder_path, f"图表_{keyword}.png")plt.savefig(chart_path, dpi=150, bbox_inches='tight')print(f"📊 图表已保存: {chart_path}")plt.close()except Exception as e:print(f"⚠️ 生成图表失败: {e}")if __name__ == "__main__":print("=" * 50)print("📊 批量合并Excel并生成图表")print("=" * 50)print()path = input("请输入Excel文件夹路径: ").strip()if path.startswith('"') and path.endswith('"'):path = path[1:-1]path = path.replace('\\', '/')if not os.path.exists(path):print("❌ 路径不存在")input("按回车键退出...")exit()print("\n1. 合并所有Excel并生成图表")print("2. 按关键词筛选后合并")choice = input("请选择(1或2,默认1): ").strip() or "1"x_col = input("\n请输入作为X轴的列名(如 产品名称,直接回车跳过图表): ").strip()y_col = input("请输入作为Y轴的列名(如 销售额,直接回车跳过图表): ").strip()if x_col and y_col:print("\n图表类型: bar(柱状图), line(折线图), pie(饼图)")chart_type = input("请选择(默认bar): ").strip() or "bar"else:chart_type = 'bar'if choice == "2":keyword = input("\n请输入关键词(如 销售): ").strip()if not keyword:print("❌ 关键词不能为空")input("按回车键退出...")exit()merge_by_keyword(path, keyword, x_col if x_col else None, y_col if y_col else None, chart_type)else:merge_excel_and_chart(path, x_col if x_col else None, y_col if y_col else None, chart_type)input("\n按回车键退出...")
使用步骤
安装依赖:
pip install pandas openpyxl matplotlib把完整代码保存为
merge_excel_chart.py把所有Excel文件放在同一个文件夹
运行
python merge_excel_chart.py输入文件夹路径
输入X轴和Y轴列名
选择图表类型
打开同目录下的合并结果和图表
踩坑记录
坑1: 图表中文显示为方块。解决方案:设置了中文字体 SimHei,Windows/Mac都支持。
坑2: 不同文件列名不一致导致合并报错。解决方案:代码自动匹配列名,跳过无法匹配的文件。
坑3: 数据量太大图表不清晰。解决方案:代码自动按X轴分组汇总Y轴。
夜雨聆风