如何在单个PDF中并排生成多个DataFrame图表并保存原表格?
解决方案:Pandas图表与表格合并PDF+每周自动邮件发送
针对你需要将Pandas生成的图表并排展示在PDF中、嵌入原始表格并每周自动发送邮件的需求,以下是完整实现步骤:
1. 数据加载与预处理
先把JSON/CSV数据转为DataFrame,并做基础清洗(以你提供的JSON数据为例,CSV直接用pd.read_csv即可):
import pandas as pd import json # 加载JSON数据 with open('match_data.json', 'r', encoding='utf-8') as f: data = json.load(f) df = pd.DataFrame(data) # 格式化日期列,清理无用字段 df['MatchDate'] = pd.to_datetime(df['MatchDate']).dt.date df = df.drop('FIELD8', axis=1)
2. 生成并排图表+嵌入表格到PDF
用Matplotlib创建多子图布局实现图表并排,再在页面底部添加原始表格,直接输出为PDF:
import matplotlib.pyplot as plt from matplotlib.backends.backend_pdf import PdfPages # 初始化PDF对象 with PdfPages('match_stat_report.pdf') as pdf: # 创建2x2的子图布局,设置画布大小适配多图表 fig, axes = plt.subplots(2, 2, figsize=(16, 12)) fig.suptitle('赛事数据统计报告', fontsize=16, y=0.95) # 图表1:球员总得分柱状图 total_runs = df.groupby('batsman')['Runs'].sum().sort_values(ascending=False) axes[0,0].bar(total_runs.index, total_runs.values, color='#1f77b4') axes[0,0].set_title('球员总得分排名') axes[0,0].tick_params(axis='x', rotation=45) # 图表2:出局类型占比饼图 issue_dist = df['IssueType'].str.lower().value_counts() axes[0,1].pie(issue_dist.values, labels=issue_dist.index, autopct='%1.1f%%') axes[0,1].set_title('出局类型分布') # 图表3:Rohit Sharma出局类型统计 rohit_out = df[df['batsman'] == 'Rohit Sharma']['IssueType'].str.lower().value_counts() axes[1,0].bar(rohit_out.index, rohit_out.values, color='#ff7f0e') axes[1,0].set_title('Rohit Sharma 出局类型明细') # 图表4:Bumra得分趋势折线图 bumra_trend = df[df['batsman'] == 'Bumra'].sort_values('MatchDate') axes[1,1].plot(bumra_trend['MatchDate'], bumra_trend['Runs'], marker='o', color='#2ca02c') axes[1,1].set_title('Bumra 得分趋势') axes[1,1].tick_params(axis='x', rotation=45) # 调整子图间距,避免重叠 plt.tight_layout(rect=[0, 0.2, 1, 0.92]) # 在画布底部添加原始表格(显示前10行,数据多可分页) table_ax = fig.add_axes([0.1, 0.05, 0.8, 0.15]) table_ax.axis('off') table_data = df.head(10).values.tolist() table_cols = df.columns.tolist() table = table_ax.table(cellText=table_data, colLabels=table_cols, cellLoc='center', loc='center') table.auto_set_font_size(False) table.set_fontsize(8) table.scale(1.2, 1.2) # 保存当前页面到PDF pdf.savefig(fig) plt.close()
3. 发送PDF邮件
用Python内置的smtplib和email库实现邮件发送,注意配置邮箱SMTP服务(比如QQ邮箱需要开启授权码):
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.application import MIMEApplication def send_report(): # 邮箱配置 sender = 'your_email@example.com' receiver = 'target_email@example.com' auth_code = 'your_email_auth_code' smtp_host = 'smtp.example.com' smtp_port = 465 # 构建邮件 msg = MIMEMultipart() msg['From'] = sender msg['To'] = receiver msg['Subject'] = '每周赛事数据统计报告' # 添加正文 msg.attach(MIMEText('附件为最新一周的赛事数据报告,请查收。', 'plain', 'utf-8')) # 添加PDF附件 with open('match_stat_report.pdf', 'rb') as f: pdf_part = MIMEApplication(f.read(), _subtype='pdf') pdf_part.add_header('Content-Disposition', 'attachment', filename='match_stat_report.pdf') msg.attach(pdf_part) # 发送邮件 try: with smtplib.SMTP_SSL(smtp_host, smtp_port) as server: server.login(sender, auth_code) server.send_message(msg) print('邮件发送成功') except Exception as e: print(f'邮件发送失败:{str(e)}')
4. 每周自动执行
方式1:用schedule库实现脚本内定时
import schedule import time def weekly_job(): # 依次调用数据加载、PDF生成、邮件发送的函数 send_report() # 设置每周一上午9点执行 schedule.every().monday.at("09:00").do(weekly_job) # 保持脚本运行 while True: schedule.run_pending() time.sleep(60)
方式2:系统级定时任务(推荐,更稳定)
- Linux/macOS:编辑crontab任务,执行
crontab -e添加以下内容:
表示每周一9点自动运行脚本。0 9 * * 1 /usr/bin/python3 /full/path/to/your_script.py - Windows:打开「任务计划程序」,创建基本任务,设置触发条件为每周一,操作选择启动Python解释器,参数填脚本路径。
内容的提问来源于stack exchange,提问作者Hound
相关产品推荐
相关产品推荐

