Pandas + Jinja,轻松创建一个 PDF 报表

来源:萝卜大杂烩

我们都知道,Pandas 擅长处理大量数据并以多种文本和视觉表示形式对其进行总结,它支持将结构输出到 CSV、Excel、HTML、json 等。但是如果我们想将多条数据合并到一个文档中,就有些复杂了。例如,如果要将两个 DataFrames 放在一张 Excel 工作表上,则需要使用 Excel 库手动构建输出。虽然可行,但并不简单。本文将介绍一种将多条信息组合成 HTML 模板,然后使用 Jinja 模板和 WeasyPrint 将其转换为独立 PDF 文档的方法,一起来看看吧~

总体流程

如报告文章所示,使用 Pandas 将数据输出到 Excel 文件中的多个工作表或从 pandas DataFrames 创建多个 Excel 文件都非常方便。但是,如果我们想将多条信息组合到一个文件中,那么直接从 Pandas 中完成的简单方法却并不多,下面我们来探索一条可行的简单方法

在本文中,我将使用以下流程来创建多页 PDF 文档

873224ef6af59ad053023d5221544f3b.png

这种方法的好处是我们可以将自己的工具替换到此工作流程中。不喜欢用 Jinja?那么可以插入 mako 或其他任何模板工具

工具选择

首先,我们使用 HTML 作为模板语言,因为它可能是生成结构化数据并允许设置相对丰富的格式的最简单方法

其次,选择 Jinja 是因为我有使用 Django/Flask 的经验,上手比较容易

这个工具链中最困难的部分是弄清楚如何将 HTML 呈现为 PDF。我觉得目前还没有非常好的解决方案,我这里选择了 WeasyPrint,大家也可以尝试一下其他的工具

数据处理

导入模块,读取销售信息

from __future__ import print_function
import pandas as pd
import numpy as np
df = pd.read_excel("sales-funnel.xlsx")
df.head()

Output:

91ba2c8c13bcc9b32de85e46eb65fb4f.png

将数据进行透视表汇总处理

sales_report = pd.pivot_table(df, index=["Manager", "Rep", "Product"], values=["Price", "Quantity"],
                           aggfunc=[np.sum, np.mean], fill_value=0)
sales_report.head()

Output:

f79391f9b9ea55de2fc43b41c94a7fd3.png

模板

Jinja 模板非常强大,支持许多高级功能,例如沙盒执行和自动转义等等

Jinja 的另一个不错的功能是它包含多个内置过滤器,这将允许我们以在 Pandas 中难以做到的方式格式化我们的一些数据

为了在我们的应用程序中使用 Jinja,我们需要做 3 件事:

  • 创建模板

  • 将变量添加到模板上下文中

  • 将模板渲染成 HTML

我们先创建一个简单的模板 myreport.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h2>Sales Funnel Report - National</h2>
     {{ national_pivot_table }}
</body>
</html>

此代码的两个关键部分是 {{ title }} 和 {{ national_pivot_table }}。它们本质上是我们在渲染文档时将提供的变量的占位符

要填充这些变量,我们需要创建一个 Jinja 环境并获取我们的模板:

from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template("myreport.html")

在上面的示例中,我们假设模板位于当前目录中

另一个关键组件是 env 的创建,这个变量是我们将内容传递给模板的方式。我们创建一个名为 template_var 的字典,其中包含我们要传递给模板的所有变量

变量的名称与我们的模板匹配

template_vars = {"title" : "Sales Funnel Report - National",
                 "national_pivot_table": sales_report.to_html()}

最后一步是使用输出中包含的变量来呈现 HTML,这将创建一个字符串,我们最终将传递给我们的 PDF 创建引擎

html_out = template.render(template_vars)

生成 PDF

PDF 创建部分也相对简单,我们需要做一些导入并将一个字符串传递给 PDF 生成器

from weasyprint import HTML
HTML(string=html_out).write_pdf("report.pdf")

此命令会创建一个如下所示的 PDF 报告:

904576eb43e50c4fe211eb1b4df76ab0.png

虽然报告生成了,但是看起来很难看啊,我们来优化下,添加 CSS

这里使用 blue print 的 typography.css 作为我们的 style.css 的基础,它有以下几个优点:

  • 它比较小且易于理解

  • 它可以在 PDF 引擎中工作而不会引发错误和警告

  • 它包括看起来相当不错的基本表格格式

HTML(string=html_out).write_pdf(args.outfile.name, stylesheets=["style.css"])

1509d0ca74a175c58b91fb9e0c280ca9.png

可以看到,仅仅添加一行代码,产生的效果却大大不同

更复杂的模板

为了生成更有用的报告,我们将结合上面显示的汇总统计数据,并将报告拆分为每个经理包含一个单独的 PDF 页面

让我们从更新的模板(myreport.html)开始:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>{{ title }} </title>
</head>
<body>
<div class="container">
    <h2>Sales Funnel Report - National</h2>
     {{ national_pivot_table }}
    {% include "summary.html" %}
</div>
<div class="container">
    {% for manager in Manager_Detail %}
        <p style="page-break-before: always" ></p>
        <h2>Sales Funnel Report - {{manager.0}}</h2>
        {{manager.1}}
        {% include "summary.html" %}
    {% endfor %}
</div>
</body>
</html>

我们注意到的第一件事是有一个包含语句,它提到了另一个文件。包含允许我们引入一段 HTML 并在代码的不同部分重复使用它。在这种情况下,摘要包含一些我们希望在每个报告中包含的简单的国家级统计数据,以便管理人员可以将他们的绩效与全国平均水平进行比较。

以下是 summary.html 的样子:

<h3>National Summary: CPUs</h3>
    <ul>
        <li>Average Quantity: {{CPU.0|round(1)}}</li>
        <li>Average Price: {{CPU.1|round(1)}}</li>
    </ul>
<h3>National Summary: Software</h3>
    <ul>
        <li>Average Quantity: {{Software.0|round(1)}}</li>
        <li>Average Price: {{Software.1|round(1)}}</li>
    </ul>

在此代码段中,看到我们可以访问一些其他变量:CPU 和 Software 。其中每一个都是一个 python 列表,其中包括 CPU 和软件销售的平均数量和价格

还注意到我们使用管道|将每个值四舍五入到小数点后 1 位。这是使用 Jinja 过滤器的一个具体示例

还有一个 for 循环允许我们在报告中显示每个经理的详细信息。Jinja 的模板语言只包含一个非常小的代码子集,它会改变控制流

附加统计信息

下面编写供模板调用的函数和代码

一个简单的汇总函数

def get_summary_stats(df,product):
    """
    For certain products we want National Summary level information on the reports
    Return a list of the average quantity and price
    """
    results = []
    results.append(df[df["Product"]==product]["Quantity"].mean())
    results.append(df[df["Product"]==product]["Price"].mean())
    return results

创建经理详细信息

manager_df = []
for manager in sales_report.index.get_level_values(0).unique():
    manager_df.append([manager, sales_report.xs(manager, level=0).to_html()])

最后,使用以下变量调用模板

template_vars = {"title" : "National Sales Funnel Report",
                 "CPU" : get_summary_stats(df, "CPU"),
                 "Software": get_summary_stats(df, "Software"),
                 "national_pivot_table": sales_report.to_html(),
                 "Manager_Detail": manager_df}
# Render our file and create the PDF using our css style file
html_out = template.render(template_vars)
HTML(string=html_out).write_pdf("report.pdf",stylesheets=["style.css"])

这样我们的 pdf 报表就完成了,整体效果如下

4d0357be151fb0ea6ae47fe78c45938a.gif

完整代码:

from __future__ import print_function
import pandas as pd
import numpy as np
import argparse
from jinja2 import Environment, FileSystemLoader
from weasyprint import HTML


def create_pivot(df, infile, index_list=["Manager", "Rep", "Product"], value_list=["Price", "Quantity"]):
    """
    Create a pivot table from a raw DataFrame and return it as a DataFrame
    """
    table = pd.pivot_table(df, index=index_list, values=value_list,
                           aggfunc=[np.sum, np.mean], fill_value=0)
    return table

def get_summary_stats(df,product):
    """
    For certain products we want National Summary level information on the reports
    Return a list of the average quantity and price
    """
    results = []
    results.append(df[df["Product"]==product]["Quantity"].mean())
    results.append(df[df["Product"]==product]["Price"].mean())
    return results

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Generate PDF report')
    parser.add_argument('infile', type=argparse.FileType('r'),
    help="report source file in Excel")
    parser.add_argument('outfile', type=argparse.FileType('w'),
    help="output file in PDF")
    args = parser.parse_args()

    df = pd.read_excel(args.infile.name)
    sales_report = create_pivot(df, args.infile.name)

    manager_df = []
    for manager in sales_report.index.get_level_values(0).unique():
        manager_df.append([manager, sales_report.xs(manager, level=0).to_html()])

    env = Environment(loader=FileSystemLoader('.'))
    template = env.get_template("myreport.html")
    template_vars = {"title" : "National Sales Funnel Report",
                     "CPU" : get_summary_stats(df, "CPU"),
                     "Software": get_summary_stats(df, "Software"),
                     "national_pivot_table": sales_report.to_html(),
                     "Manager_Detail": manager_df}

    html_out = template.render(template_vars)
    HTML(string=html_out).write_pdf(args.outfile.name,stylesheets=["style.css"])

-------- End --------

1e6c187a4a7e99dc8f20e35d64853a8d.png
精选资料

回复关键词,获取对应的资料:

关键词资料名称
600《Python知识手册》
md《Markdown速查表》
time《Python时间使用指南》
str《Python字符串速查表》
pip《Python:Pip速查表》
style《Pandas表格样式配置指南》
mat《Matplotlib入门100个案例》
px《Plotly Express可视化指南》
精选内容

数据科学: VS Code 中 Python配置使用指南 | 财经工具 Tushare | Matplotlib 最有价值的 50 个图表

书籍阅读: 如何阅读一本书 | 巴菲特之道 | 价值 | 原则 | 投资最重要的事 | 戴维斯王朝 | 客户的游艇在哪里 | 刻意练习 | 林肯传 | 金字塔原理

投资小结: 2021Q4 | 2021Q3 | 2021Q2 | 2021Q1 | 2020Q4

精选视频

可视化: Plotly Express

财经: Plotly在投资领域的应用 | 绘制K线图表

排序算法: 汇总 | 冒泡排序 | 选择排序 | 快速排序 | 归并排序 | 堆排序 | 插入排序 | 希尔排序 | 计数排序 | 桶排序 | 基数排序

0db18cfbd98f093390ec72cf750213a0.png
### 回答1: Python自动化办公项目源码是一组通过Python编写的代码,旨在提高办公工作的效率和自动化程度。该源码可以包含一系列函数和类,用于实现各种自动化任务,如数据分析、报告生成、文件处理等。 源码的形式可以是单个Python脚本文件,或者是一个包含多个模块文件的项目。在源码中,可以使用各种Python库和框架来实现自动化功能。例如,可以使用openpyxl库来读写Excel文件,使用pandas库来处理数据,使用smtplib库来发送电子邮件等。 源码的实现通常以函数或类为单位,每个函数或类负责完成一个具体的自动化任务。源码可以实现以下功能: 1. 数据分析和处理:通过使用pandas库,可以读取和处理各种数据文件,进行数据清洗、转换和分析,生成报告和可视化图表。 2. 文件处理:可以通过使用os库和shutil库来自动化进行文件的复制、移动、重命名和删除。 3. 报告生成:可以使用jinja2库和docx库来基于模板生成各种文件格式的报告,如Word文档、PDF文件等。 4. 电子邮件发送:可以使用smtplib库和email库来实现自动发送电子邮件功能,包括发送附件和邮件内容的自动生成。 5. 网络数据获取:可以使用requests库和beautifulsoup库来获取互联网上的数据,如天气信息、新闻信息等。 6. 自动化测试:可以使用selenium库来实现自动化测试功能,模拟用户操作网页,测试网站的功能和稳定性。 总之,Python自动化办公项目源码是一组用于提高办公效率和自动化办公任务的Python代码,可以根据具体需求,实现各种功能和任务。通过编写和使用这些源码,可以显著提高办公工作的效率和质量。 ### 回答2: Python自动化办公项目源码可以涉及多种功能和应用,如数据处理、文档生成、邮件发送等。下面是一个简单的示例源码,展示了一个基于Python的自动化数据处理和报表生成项目。该项目通过读取Excel数据并将其转换为报表,以实现自动化办公功能。 ``` import pandas as pd # 读取Excel文件 data = pd.read_excel("data.xlsx") # 数据处理,例如计算总销售额 data["总销售额"] = data["单价"] * data["数量"] # 根据数据生成报表 report = data.groupby(["产品名称"]).agg({"数量": "sum", "总销售额": "sum"}) # 保存报表为Excel文件 report.to_excel("report.xlsx", index=True) ``` 该源码使用了`pandas`库进行数据处理和报表生成。首先,它通过`pd.read_excel`函数读取Excel文件中的数据。然后,根据需要进行数据处理,比如计算总销售额。最后,使用`groupby`和`agg`函数对数据进行分组和聚合,生成报表。最后,使用`to_excel`函数将报表保存为Excel文件。 该源码仅展示了一个简单的Python自动化办公项目的示例,实际项目中可以根据需求进行更复杂的数据处理和报表生成。同时,可以结合其他的Python库和框架,如OpenPyXL和PyAutoGUI,实现自动化办公的更多功能,比如自动填充表单和自动邮件发送等。 总之,Python自动化办公项目源码可以根据具体需求和功能进行编写,利用Python的各种库和工具实现各种自动化办公任务。 ### 回答3: Python自动化办公项目源码是指使用Python编写的实现自动化办公任务的程序源代码。 自动化办公是指利用计算机及相关技术,通过程序来实现办公任务的自动化,提高工作效率和准确性。Python是一种强大且易于学习和使用的编程语言,适用于各种任务的自动化开发。 Python自动化办公项目源码通常包含以下几个主要部分: 1. 数据处理:源码中通常会涉及到对办公中的数据进行处理的代码。例如,读取Excel表格、处理文本文件、解析CSV文件或处理数据库等。 2. 功能模块:源码会包含一些具体的功能模块,可以根据项目需求进行相应的拓展和修改。例如,自动发送邮件、生成报告、自动化填写表单、数据抓取等。 3. 定时任务:源码中可能包含定时执行的任务。通过设置定时任务,可以实现自动化的数据处理和报表生成等功能。例如,每天定时发送邮件、定时备份数据等。 4. 用户界面:有些自动化办公项目会添加用户界面,方便用户进行配置和操作。通过用户界面,用户可以设置参数、选择要执行的任务以及查看执行结果等。 总之,Python自动化办公项目源码能够帮助用户通过编写一些任务脚本,实现各种办公任务的自动化,提高工作效率,并减少繁琐的重复操作。用户可以根据自身需求进行修改和扩展,实现更加个性化和高效的自动化办公。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值