原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。

Python使用folium制作地图并生成png图片

第一章 folium的方法和类的介绍(思维导图)
第二章 使用folium制作地图
第三章 folium实用功能进阶
第三章 使用Html2Image生成png图片
第四章 使用reportlab制作pdf报告


文章目录

  • Python使用folium制作地图并生成png图片
  • 前言
  • 一、reportlab是什么
  • 二、
    • 1.安装和导入库
    • 2.将画图、画表格、编辑文字抽象为类
    • 3.pdf插入图片
      • 3.1 以文件路径写入pdf
      • 3.2 以流文件写入pdf
    • 4.pdf分页
    • 5.以生成pdf流文件为例
  • 总结

前言

提示:这里可以添加本文要记录的大概内容:
本博客重点内容:reportlab生成流文件格式、reportlab分页和图片流文件写入reportlab等。
我讲一下我这个需求的来源,做的项目是一个地理空间查询和使用的系统,通过在前端调用高德地图api创建了一个查询区域,获取区域内的地理数据(数据库)。具体的需求就是,将查询区域和地理数据制作成一个覆盖率分析报告,报告中的其他内容都已完成,但报告中需要展示高德地图、查询区域、地理数据的完整图片这个功能卡了2个星期,主要原因是我对地理空间数据不熟悉,很多python相关库也不清楚,在构建图形的过程中走了很多弯路。
现在将整个实现过程梳理完成,希望对各位同道有帮助,跟其他文章和官网不同,本博客是以使用的优先级来讲解这个库。<我们靠所得来谋生,但靠给予来创造生活>


一、reportlab是什么

reportlab是Python的一个标准库,可以画图、画表格、编辑文字,最后可以输出PDF格式。它的逻辑和编辑一个word文档或者PPT很像。有两种方法:

1)建立一个空白文档,然后在上面写文字、画图等;
2)建立一个空白list,以填充表格的形式插入各种文本框、图片等,最后生成PDF文档。

因为需要产生一份给用户看的报告,里面需要插入图片、表格等,所以采用的是第二种方法。

**由于我们这个功能是django网站项目上,我们并不想生成一个文件,第二种方法还可以生成io流文件,进而传递给前端生成pdf,这样后端就不存在文件的存写读的操作了。**本篇文章在方法2的基础上,加入了reportlab生成流文件格式、reportlab分页和图片流文件写入reportlab等功能。

二、

1.安装和导入库

官网链接:https://pypi.org/project/reportlab/
官方文档:https://docs.reportlab.com/reportlab/userguide/ch1_intro/

pip install reportlab

代码如下(示例):

from reportlab.pdfbase import pdfmetrics   # 注册字体
from reportlab.pdfbase.ttfonts import TTFont # 字体类
from reportlab.platypus import Table, SimpleDocTemplate, Paragraph, Image  # 报告内容相关类
from reportlab.lib.pagesizes import letter  # 页面的标志尺寸(8.5*inch, 11*inch)
from reportlab.lib.styles import getSampleStyleSheet  # 文本样式
from reportlab.lib import colors  # 颜色模块
from reportlab.graphics.charts.barcharts import VerticalBarChart  # 图表类
from reportlab.graphics.charts.legends import Legend  # 图例类
from reportlab.graphics.shapes import Drawing  # 绘图工具
from reportlab.lib.units import cm  # 单位:cm# 注册字体(提前准备好字体文件, 如果同一个文件需要多种字体可以注册多个)
pdfmetrics.registerFont(TTFont('SimSun', 'SimSun.ttf'))

2.将画图、画表格、编辑文字抽象为类

抽象为类后,可实现多次调用,方便处理。这里我将页眉和页脚的方法也放在了抽象类中。在生成文件时,实现pdf报告的自动分页。

class Graphs(object):def __init__(self):# 获取所有样式表self.style = getSampleStyleSheet()# 绘制标题def draw_1_title(self, title1: str):# 拿到标题样式ct = self.style['Heading1']# 单独设置样式相关属性ct.fontName = 'hei'  # 字体名ct.fontSize = 20  # 字体大小ct.leading = 1.5 * ct.fontSize  # 行间距ct.textColor = colors.black  # 字体颜色ct.alignment = 1  # 居中return Paragraph(title1, ct)# 绘制小标题(黑色)def draw_2_title(self, title: str, content: str):# 拿到标题样式ct = self.style['Normal']# 单独设置样式相关属性ct.fontName = 'song'  # 字体名ct.fontSize = 15  # 字体大小ct.leading = 1.5 * ct.fontSize  # 行间距ct.textColor = colors.black  # 字体颜色return Paragraph(("<font name='Dengb'>%s</font>" % title) + content, ct)# 绘制普通段落内容def draw_text(self, text: str):# 获取普通样式ct = self.style['Normal']ct.fontName = 'song'ct.fontSize = 12ct.leading = 1.5 * ct.fontSize  # 行间距ct.wordWrap = 'CJK'  # 设置自动换行ct.alignment = 0  # 左对齐ct.firstLineIndent = 32  # 第一行开头空格ct.leading = 25return Paragraph(text, ct)# 绘制表格标题def draw_table_title(self, title: str):# 拿到标题样式ct = self.style['Heading1']# 单独设置样式相关属性ct.fontName = 'Dengb'  # 字体名ct.fontSize = 14  # 字体大小ct.leading = 15  # 行间距ct.textColor = colors.black  # 字体颜色ct.alignment = 1  # 居中ct.bold = True# 创建标题对应的段落,并且返回return Paragraph(title, ct)# 绘制表格@staticmethoddef draw_table(*args):# 列宽度col_width = [50, 300, 50, 50]style = TableStyle([('FONTNAME', (0, 0), (-1, -1), 'song'),  # 全表字体('FONTNAME', (0, 0), (-1, 0), 'Dengb'),  # 首行字体('FONTSIZE', (0, 0), (-1, 0), 12),  # 第一行的字体大小('FONTSIZE', (0, 1), (-1, -1), 10),  # 第二行到最后一行的字体大小('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 第一行水平居中('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),  # 所有表格上下居中对齐('TEXTCOLOR', (0, 0), (-1, -1), colors.black),  # 设置表格内文字颜色(不包含第一行)('GRID', (0, 0), (-1, -1), 0.5, colors.black),  # 设置表格框线为grey色,线宽为0.5# ('SPAN', (0, 1), (0, 2)),  # 合并第一列二三行# ('SPAN', (0, 3), (0, 4)),  # 合并第一列三四行# ('SPAN', (0, 5), (0, 6)),  # 合并第一列五六行# ('SPAN', (0, 7), (0, 8)),  # 合并第一列五六行])table = Table(args, colWidths=col_width, style=style)return table# 创建图表@staticmethoddef draw_bar(bar_data: list, ax: list, items: list):drawing = Drawing(500, 250)bc = VerticalBarChart()bc.x = 45  # 整个图表的x坐标bc.y = 45  # 整个图表的y坐标bc.height = 200  # 图表的高度bc.width = 350  # 图表的宽度bc.data = bar_databc.strokeColor = colors.black  # 顶部和右边轴线的颜色bc.valueAxis.valueMin = 5000  # 设置y坐标的最小值bc.valueAxis.valueMax = 26000  # 设置y坐标的最大值bc.valueAxis.valueStep = 2000  # 设置y坐标的步长bc.categoryAxis.labels.dx = 2bc.categoryAxis.labels.dy = -8bc.categoryAxis.labels.angle = 20bc.categoryAxis.categoryNames = ax# 图示leg = Legend()leg.fontName = 'song'leg.alignment = 'right'leg.boxAnchor = 'ne'leg.x = 475  # 图例的x坐标leg.y = 240leg.dxTextSpace = 10leg.columnMaximum = 3leg.colorNamePairs = itemsdrawing.add(leg)drawing.add(bc)return drawing# 绘制图片@staticmethoddef draw_img(path):img = Image(path, width=500, height=500, kind='bound')  # 读取指定路径下的图片return img# 设置页脚def footer(self, canvas, doc):"""设置页脚--页码:param canvas:Canvas类型  pdf画布:param doc:doc类型   整个pdf文件"""  # 拿到标题样式ct = self.style['Heading1']# 单独设置样式相关属性ct.fontName = 'song'  # 字体名ct.fontSize = 14  # 字体大小ct.leading = 15  # 行间距ct.textColor = colors.black  # 字体颜色ct.alignment = 1  # 居中canvas.saveState()  # 先保存当前的画布状态pageNumber = ("%s" % canvas.getPageNumber())  # 获取当前的页码p = Paragraph(pageNumber, ct)p.wrap(1 * cm, 1 * cm)  # 申请一块1cm大小的空间,返回值是实际使用的空间p.drawOn(canvas, 520, 50)  # 将页码放在指示坐标处canvas.restoreState()# 设置页眉def header(self, canvas, doc):"""设置页眉:param canvas:Canvas类型  pdf画布:param doc:doc类型     整个pdf文件https://cxybb.com/article/liyadian/81253117"""canvas.saveState()im = Image("utils/map_png/image/logo.png", height=20, width=98)im.drawOn(canvas, 430, 780)# canvas.setStrokeColorRGB(0.8, 0.8, 0.8)# canvas.setFillColorRGB(0, 0, 0)# canvas.line(15, 28, doc.width - 15, 28)# canvas.setFont('regular', 8)# str = f"XXX银行 | Page {doc.page}"# textLen = stringWidth(str, 'regular', 8)# canvas.drawCentredString(int((doc.width - textLen) / 2), 0.15 * inch, str)canvas.restoreState()

3.pdf插入图片

pdf中插入图片会有2中方式,网络上常用的方式都是文件路径,本片文章的图片是通过Html2Image生成的,无法保存成流文件格式,只能保存至本地文件。但是如果图片是通过其他途径生成的,可以直接以流文件的方式写入pdf,这样可以节省文件的创建、写入、读取和删除等操作,节省内存和磁盘空间。

3.1 以文件路径写入pdf

 # base 是当前文件所在路径的上一级路径,此种方法适用Windows和linux等多种系统,其他方法无法保证,多系统路径是否一致。base = Path(__file__).resolve().parent# out_file就是文件名字(即Html2Image生成的图片),img_path 是拼接后的文件路径content.append(graphs.draw_table_title('图1 影像覆盖情况'))img_path = os.path.join(base, 'map_png', out_file)content.append(graphs.draw_img(img_path))content.append(Spacer(0, 10))

3.2 以流文件写入pdf

from pillow import Image as pilImagewith open('test.png',mode='rb') as f:# 读取到图片content.append(graphs.draw_img(f))content.append(Spacer(0, 10))

4.pdf分页

在第二部分我们已经写入了pdf页眉和页脚的方法和参数,具体如何加载到pdf中可以参考下列方法。

doc = SimpleDocTemplate('report.pdf', pagesize=letter)# 声明一块Frame,存放页码frame_footer = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')# 设置页面模板,在加载页面时先运行herder函数,在加载完页面后运行footer函数template = PageTemplate(id='test', frames=frame_footer, onPage=graphs.header, onPageEnd=graphs.footer)doc.addPageTemplates([template])doc.build(content)

5.以生成pdf流文件为例

def pics_2_pdf(info, table, out_file):"""info:基本信息table:表格数据"""# 获取Graphs类graphs = Graphs()# 创建内容对应的空列表content = list()# 1.添加标题content.append(graphs.draw_1_title('数据中心'))# 隔行的高度content.append(Spacer(0, 10))# 2.添加小标题content.append(graphs.draw_2_title("报告形成日期: ", str(datetime.date.today().strftime("%Y/%m/%d"))))content.append(Spacer(0, 10))# 3.添加图片base = Path(__file__).resolve().parentcontent.append(graphs.draw_table_title('图1 影像覆盖情况'))img_path = os.path.join(base, 'map_png', out_file)content.append(graphs.draw_img(img_path))content.append(Spacer(0, 10))# 4.添加表格标题content.append(graphs.draw_table_title('表1 框选区域覆盖数据清单'))# 5.添加表格数据# data = [#     ['职位名称', '平均薪资', '较上年增长率'],#     ['数据分析师', '18.5K', '25%'],#     ('高级数据分析师', '25.5K', '14%'),#     ('资深数据分析师', '29.3K', '10%')# ]content.append(graphs.draw_table(*table))# 生成图表# content.append(Graphs.draw_title(''))# content.append(Graphs.draw_little_title('热门城市的就业情况'))# b_data = [(25400, 12900, 20100, 20300, 20300, 17400), (15800, 9700, 12982, 9283, 13900, 7623)]# ax_data = ['BeiJing', 'ChengDu', 'ShenZhen', 'ShangHai', 'HangZhou', 'NanJing']# leg_items = [(colors.red, '平均薪资'), (colors.green, '招聘量')]# content.append(Graphs.draw_bar(b_data, ax_data, leg_items))# 添加文字# content.append(Graphs.draw_text(#     '众所周知,大数据分析师岗位是香饽饽,近几年数据分析热席卷了整个互联网行业,与数据分析的相关的岗位招聘、培训数不胜数。很多人前赴后继,想要参与到这波红利当中。那么数据分析师就业前景到底怎么样呢?'))# 生成pdf文件# 方式一:# doc = SimpleDocTemplate('report.pdf', pagesize=letter)# 方式二-存储文件:# doc = BaseDocTemplate('report.pdf')# 方式二-流文件格式buffer = io.BytesIO()  # 重点 起一个 iodoc = BaseDocTemplate(buffer)# 声明一块Frame,存放页码frame_footer = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')# 设置页面模板,在加载页面时先运行herder函数,在加载完页面后运行footer函数template = PageTemplate(id='test', frames=frame_footer, onPage=graphs.header, onPageEnd=graphs.footer)doc.addPageTemplates([template])doc.build(content)return buffer

总结

提示:这里对文章进行总结:

本博客是以使用的优先级来讲解这个库。<我们靠所得来谋生,但靠给予来创造生活>

【Python办公自动化】使用reportlab制作pdf报告相关推荐

  1. Python办公自动化|一键生成数据分析报告

    前两天逛知乎的时候看到这样一个提问,Python自动化办公能做那些有趣或者有用的事情? 看了一下这个提问,我想这可能是很多职场人面临的困惑,想把Python用到工作中来提升效率,却不知如何下手?Pyt ...

  2. Python 办公自动化,一键给PDF文件加密,超方便

    作者 | 欣一 来源 | Python爱好者集中营 今天给大家做一个给PDF文件加密的GUI界面(图形用户界面),方便现在的一些上班族白领们使用,尤其是需要给一些比较重要的PDF文件加密的时候,下面我 ...

  3. python浪漫文艺_文艺一把!Python爬取读者制作PDF!

    2.[文件] getpdf.py ~ 3KB 下载(58) #!/usr/bin/env python #coding=utf-8 """ Author: Anemone ...

  4. Python办公自动化,合并excel+pdf转word等

    今天给大家推荐我的朋友-辰哥,公众号[Python研究者]的号主. 辰哥的公众号经常分享自己的原创干货,包括但不仅限于Python爬虫.数据分析.数据可视化.自动化办公(Excel.word等).py ...

  5. Python办公自动化之三,操作PDF

    一. 对PDF添加水印 使用reportlab库 from reportlab.pdfgen import canvas from reportlab.lib.units import cmdef c ...

  6. python课程报告模板_我用Python做了一份PDF报告!!!

    Sales Funnel Report - National {{ national_pivot_table }}

  7. pythonword编辑报告模板_使用Python制作WORD报告

    今天的另一篇文章 "使用Pandas.Jinja和WeasyPrint制作pdf报告" 中我分享了如何使用HTML模板来创建pdf报告的方法. 虽然pdf很不错,但更多的人实际上在 ...

  8. canvas导出图片python_python的reportlab库介绍、制作pdf和作图

    1 说明 1.1 reportlab模块是用python语言生成pdf文件的模块,也可以作图. 1.2 已经亲测,拿来就可以使用,适合收藏,万一自己需要就可以直接使用. 1.3 环境:python3. ...

  9. python docx 合并文档 图片_使用Python制作WORD报告

    在前面一期文章 使用Pandas.Jinja和WeasyPrint制作pdf报告 中我分享了如何使用HTML模板来创建pdf报告的方法. 虽然pdf很不错,但更多的人实际上在用微软的WORD来操作文档 ...

最新文章

  1. 怎么查电脑系统版本_电脑系统垃圾清理利器,专业、小巧且免费,有这一个就够了...
  2. MySQL CHAR、VARCHAR、TEXT、ENUM、SET(字符串类型)
  3. 常见开源项目结构划分
  4. [vue] 父子组件间传值
  5. 商城html源码_Java开源商城源码推荐,从菜鸡到大神,永远绕不开的商城系统
  6. 罗永浩与银联合作直播,但因过程太流畅被网友调侃是录播
  7. 文件存储demo,直接存储内容到本地中。
  8. axure8 事件改变样式_Axure RP 8 Beta更新介绍(三):部件样式
  9. 2021-08-25
  10. python中printf的用法_python输出语句print的用法是什么?
  11. velocity语法小结
  12. tmb100 刷linux,天猫魔盒TMB100C短接刷机教程
  13. 树莓派安装HackRF、LimeSDR、GNU Radio、Gqrx
  14. [ecshop 二次开发经验] ecshop 手机版本 购车流程 最后没有支付按钮 ,清理没有用的支付方式 68ecshop
  15. java就是我的幸福,关于幸福的句子经典
  16. linux下repo文件的配置
  17. 【英语学习工具】解说 LeHoCat 提供免费的 视频集制作工具 使用方法, 看视频学英语的制作工具, 制作英语教学课件的工具, 帮助自学英语(详细图文解说)
  18. Windows10常用快捷键+cmd常见命令码
  19. 2021年北京高新技术企业认定补贴及政策要求
  20. 【U8】登录提示缺少根元素

热门文章

  1. python快速接手别人的代码_Python 爬虫代码,网上找的别人的,但是报错,求高手指点...
  2. 董事长 CEO 总裁 总经理 区别
  3. 重复安装GI的时候报错INS-32025
  4. 人工智能在计算机领域中的应用
  5. 项目简要建设情况汇报材料报告
  6. 判断对象的某些属性是否为空
  7. html iframe显示不全,滚动的iframe解决,但在iframe页面显示不全
  8. 学it中的python怎么样_长安大专网教学历
  9. 同一局域网下,一台电脑连接另一台电脑的虚拟机(从属机(window)连接主机(window)虚拟机(Linux)的连接流程)
  10. 已知起始点坐标、目的地方位角,计算沿着测地线飞行一定距离到达的目的地坐标