目录
文章概况
本文仅作为知识点总结与教程引导,借用上篇文章的前期准备进行汇总。
中心问题
如何按照以下设定的word格式,批量生成多个word文档。
探讨问题:
1.如何生成固定范围的随机数以及在特定列表中随机选择一个元素。
2.dataframe如何按照某列数值从大到小顺序排序,以及如何选取最大值的对应行中的其他列数据。
3.如何通过python对docx进行格式设置与输出。
提示:以下是本篇文章正文内容,下面案例可供参考
一、知识点总结
1.如何生成固定范围的随机数以及在特定列表中随机选择一个元素。
(1)对于固定范围内生成一个随机数,采用的是random库的uniform函数:
random_rain = random.uniform(0,120)
(2)在特定列表中,比如26个字母中随机选择一个元素,需要用到random库中的choice函数,其中26字母的列表得到的方式有两种:1.手动创建并书输入。2.接用string模块。
a_str = string.ascii_uppercase
'''
# 获取所有ascii码中字母字符的字符串(包含大写和小写)
# 字母:string.ascii_letters
# 大写:string.ascii_uppercase
# 小写:string.ascii_lowercas
'''
了解更多关于String模块可参考
https://blog.csdn.net/qq_41300019/article/details/79069697
(3)判断随机选择的字母是否在列表内:
if (random_letter not in letters_list):
letters_list.append(random_letter)
else:
pass
2.利用随机数得到相对应的数据及站点,生成dataframe表格,并按照某列数值从大到小顺序排序
从大到小的排列设置:
首先设置一个dataframe表格,用df.sort_values(ascending=False , by)进行排序:
ascending=False 为从大到小排序,True为从小到大。
by 为指定的行或列。
了解更多数据排序可查看
https://blog.csdn.net/weixin_40286872/article/details/108234357
比如我用随机数定制这样的表格:
站点 降水量 降水等级
1 U 111.229 大暴雨
7 I 68.2513 暴雨
0 A 47.5457 大雨
5 W 30.2053 大雨
4 V 28.0151 大雨
3 Q 23.1953 中雨
2 R 21.553 中雨
8 N 15.8264 中雨
6 S 5.1173 小雨
代码编写:
#判断随机数据代表的降水量级。
def rainstrong(rain):
if rain <25 and rain > 10:
return '中雨'
elif rain >25 and rain <50:
return '大雨'
elif rain >0 and rain<10:
return '小雨'
elif rain >25 and rain<100:
return '暴雨'
elif rain >100:
return '大暴雨'
# 得到一个随机字母的列表
def random_letters(num):
#定义一个空列表保存随机字母
letters_list = []
rain_list = []
strong_list = []
#letter_list 的长度等于n时才结束循环。
while len(letters_list) < num :
a_str = string.ascii_uppercase
random_letter = random.choice(a_str)
random_rain = random.uniform(0,120)
#判断随机到的字母是否在列表里,没有则增加进去。
if (random_letter not in letters_list):
letters_list.append(random_letter)
#如果降水量为0则剔除。
while random_rain == 0:
random_rain = random.uniform(0,120)
strong_list.append(rainstrong(random_rain))
rain_list.append(random_rain)
else:
pass
df = pd.DataFrame(data=[letters_list,rain_list,strong_list],index=(['站点','降水量','降水等级'])).T.sort_values(ascending=False , by= '降水量')
return df
3.打印出dataframe最大值的那一行中的某列元素。
按照中心问题的要求,表格的内容分为:“站点名”、“降水量”、“降水强度”。
现在需要打印出下面降水量最大时所处在的站点U,怎么导出?
站点 降水量 降水等级
1 U 111.229 大暴雨
7 I 68.2513 暴雨
0 A 47.5457 大雨
5 W 30.2053 大雨
4 V 28.0151 大雨
3 Q 23.1953 中雨
2 R 21.553 中雨
8 N 15.8264 中雨
6 S 5.1173 小雨
两种办法:
一、df[条件][index][columns]
使用这种方法则需要获取cf[条件]的index与columns,cf[条件].index---->得到一个Int64Index的列表
----->对于只有最大值满足条件的只有一个,所以也需要一个索引,在index后加上[0]
故而欲得到这个dataframe最大值的站点在哪,完整的案例写法为:
df | [df['降水量']==df['降水量'].max()] | ['站点'] | [ df[df['降水量']==df['降水量'].max()].index[0] ]
--- ---------------------------------- -------- -------------------------------------------------
| | | |
| | | |
| | | |
\/ \/ \/ \/
主体 筛选条件 columns index
|
|
|
\/
df[筛选条件].index[0]
二、df[index or columns][条件].values
df[index or columns][条件]
-- ---------------- -----
| | |
| | |
| | |
\/ \/ \/
主体 选择的行或列 筛选条件
|
|
|
\/
选择的是列得到
是带有行的此列
的表格形式
例如:
df['站点'][df['降水量']==df['降水量'].max()]
>>1 U
Name: 站点, dtype: object
完整的案例写法为:
df['站点'][df['降水量']==df['降水量'].max()].values[0]
两种方法得到的最大结果都一样,建议使用第二种。
4.python-docx设置word的文段各种格式
文段设置,个人的理解add_paragraph、add_heading以及add_XXX的是对文段的段落样式的设置。 而对于字体样式的设置,是在段落的基础上进行设置,所以需要对text进行add_run设置。
而add_paragraph等没有.font等设置。
借助font能够做到一段中存在多种句子的字体颜色大小的设置。
我个人的完整写法思路为:
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt
from docx.shared import Cm
from docx.shared import RGBColor
from docx import Document
doc = Document()
paragraph = doc.add_paragraph()
text = paragraph.add_run('文段内容')
text.font.size = Pt(11)#设置字体大小为11磅
text.font.color.rgb = RGBColor(255,0,0) #设置字体颜色为红色,数值的设置与ps的颜色面板一样。
format_t = paragraph.paragraph_format #设置段落格式
format_t.alignment = WD_ALIGN_PARAGRAPH.CENTER #设置居中
format_t.space_after = Pt(5) #设置段后
format_t.space_before = Pt(10) #设置段前
更多docx的设置可参考官方文档
https://python-docx.readthedocs.org/en/latest/user/text.html
5.另外针对对python-docx对于段落首行缩进的设置
在python-docx并没有给出字符这个单位,官方文件能用的长度单位为:Cm、Pt、Mm等,这里换算成使用Cm,而要做到根据字号大小进行首行缩进,就需要对其进行计算。
根据百度所记载的字号,磅与字号间的关系为:
同时磅与毫米之间的换算 1磅 ≈ 0.35mm ,准确的说 1磅 = 0.3527mm
而假设字号为11,缩进两个字符就等于缩进
11 X 0.3527 X 2 X 0.1 cm
#首行缩进两个字符就该如下编写:
format_t.first_line_indent = Cm(0.1*11*0.35*2)
二、实现批量导出中心问题所要求的word文档格式
思路
1.先随机生成降水量数据、字母拼凑成的“站点”元素、以及对降水数据的雨量大小判别。
2.将得到的三个列表通过dataframe构建表格。
3.设置word的输出格式,包含内容为:
- 标题
- 文段
- 标题
- 表格
- 标题
- 表格
具体源代码
import random
import string
import pandas as pd
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Pt
from docx.shared import Mm
from docx.shared import RGBColor
def rainstrong(rain):
if rain <25 and rain > 10:
return '中雨'
elif rain >25 and rain <50:
return '大雨'
elif rain >0 and rain<10:
return '小雨'
elif rain >25 and rain<100:
return '暴雨'
elif rain >100:
return '大暴雨'
# 得到一个随机字母的列表
def random_letters(num):
#定义一个空列表保存随机字母
letters_list = []
rain_list = []
strong_list = []
#letter_list 的长度等于n时才结束循环。
while len(letters_list) < num :
a_str = string.ascii_uppercase
# random.choice 返回对象中的一个随机元素
random_letter = random.choice(a_str)
random_rain = random.uniform(0,120)
#判断随机到的字母是否在列表里,没有则增加进去。
if (random_letter not in letters_list):
letters_list.append(random_letter)
while random_rain == 0:
random_rain = random.uniform(0,120)
strong_list.append(rainstrong(random_rain))
rain_list.append(random_rain)
else:
pass
df = pd.DataFrame(data=[letters_list,rain_list,strong_list],index=(['站点','降水量','降水等级'])).T.sort_values(ascending=False , by= '降水量')
return df
class Main:
def __init__(self,df):
self.cf = df
self.heavy_rain = 0
self.hard_rain = 0
self.down_pour = 0
for i in df['降水量']:
if i >25 and i <50:
self.heavy_rain += 1
elif i >25 and i<100:
self.hard_rain += 1
elif i >100:
self.down_pour += 1
def mkdocument(self,ni):
from docx import Document
def re_date(ni):
if ni+1 < 10:
date = '0' +str(ni+1)
else:
date = str(ni+1)
return date
doc = Document()
h1 = doc.add_heading()
h1.add_run('雨量统计报表').font.color.rgb =RGBColor(255,0,0)
h1.alignment = WD_ALIGN_PARAGRAPH.CENTER
p1 = doc.add_paragraph()
print(self.cf['站点'][cf['降水量']==self.cf['降水量'].max()].values[0])
print(self.cf['站点'][cf['降水量']==self.cf['降水量'].max()])
#使用try区分有降水时的文段与无降水的文段。
try:
text1 = p1.add_run('2021年08月'+re_date(ni)+'日20时-'+re_date(ni+1)+'日20时,我区共有雨量站26个,其中'+
str(len(self.cf.index))+
'个站点出现降水。全区平均面雨量为'+
str( round(self.cf['降水量'].mean(axis=0)) )+
'毫米,最大降水量为'+
str(self.cf['降水量'].max())+
'毫米,出现在'+
self.cf['站点'][self.cf['降水量']==self.cf['降水量'].max()].values[0]+
'。'
)
except:
text1 = p1.add_run('2021年08月'+re_date(ni)+'日20时-'+re_date(ni+1)+'日20时,我区共有雨量站26个,其中'+
str(len(self.cf.index))+
'个站点出现降水。'
)
#设置字号大小。
s = 11
#text设置字体样式,p1设置段落样式
text1.font.size = Pt(s)
p1_format = p1.paragraph_format
p1_format.first_line_indent = Pt(s*2)
h2 = doc.add_heading()
h2.add_run('雨量分级').font.color.rgb =RGBColor(255,0,0)
h2.alignment = WD_ALIGN_PARAGRAPH.CENTER
table1 = doc.add_table(rows=2,cols=6)
t1_head = ['量级(mm)','站点数','量级(mm)','站点数','量级(mm)','站点数']
t1_data = ['25-50mm',self.heavy_rain,'50-100mm',self.hard_rain,'100mm以上',self.down_pour]
for i in range(len(t1_head)):
table1.cell(0,i).text = t1_head[i]
table1.cell(1,i).text = str(t1_data[i])
h3 = doc.add_heading()
h3.add_run('雨量明细').font.color.rgb =RGBColor(255,0,0)
h3.alignment = WD_ALIGN_PARAGRAPH.CENTER
table2 = doc.add_table(rows=len(self.cf.index)+1,cols=len(self.cf.columns))
head = ['站点','降水量','降水等级']
for i in range(len(head)):
table2.cell(0,i).text = head[i]
for i in range(len(self.cf.index)):
table2.cell(i+1,0).text = str(self.cf['站点'][self.cf.index[i]])
table2.cell(i+1,1).text = str(self.cf['降水量'][self.cf.index[i]])
if self.cf['降水量'][self.cf.index[i]] >= 50:
table2.cell(i+1,2).paragraphs[0].add_run( self.cf['降水等级'][self.cf.index[i]] ).font.color.rgb =RGBColor(255,0,0)
else:
table2.cell(i+1,2).text = self.cf['降水等级'][self.cf.index[i]]
doc.save('202108'+re_date(ni)+'.docx')
if __name__ == '__main__':
#n为输出文件数量
n = 15
for i in range(n):
num = int(random.uniform(0,27))
df = random_letters(num)
cf = Main(df).cf
mk = Main(df).mkdocument(i)
三、结语
以上仅供娱乐和学习,不考虑产生多大的实际作用,有错误的地方或者更加优质的写法请多多批评。