手机

密码

安全问题

注册 忘记密码?

详情请戳:https://www.udongman.cn/index.php?m=product&c=csp ​

有效期:2022/03/03 - 2022/08/30
修约计算、自适应列宽、填写模板
来源: | 作者:wUw | 发布时间: 1096天前 | 2893 次浏览 | 分享到:

1、使用的轮子:

import datetime  # 随便给sheet取个名
import math  # log及向上取整
import os  # 截取路径
import random  # 随机
import time  # time sleep
import tkinter.font as tkFont  # 字体设置
import tkinter.ttk  # tkinter进度条等骚操作
from decimal import Decimal  # 十进制及修约
from itertools import chain  # 交错插入
from tkinter import *  # UI需要
from tkinter import filedialog  # 选择路径需要

import numpy as np  # 数学计算包
import openpyxl  # excel无损写入sheet
import pandas as pd  # 科学计算包
from docx import Document  # word删除空行
from docx.shared import Mm  # 设置图片大小
from docxtpl import DocxTemplate, InlineImage  # 模板渲染
from openpyxl.styles import Border, Side  # 设置边框及自适应表格大小
from openpyxl.utils import get_column_letter  # 设置列宽

2、实现代码示例:

2.1修约和计算

# 标准曲线的不确定度
std_origin = [[0.253, 0.506, 1.265, 2.024, 2.530], [102436, 210017, 533276, 796984, 1019877]]  # 创建标曲原始x和y序列
test_ar = [0.889, 0.887, 0.889]
test_not = len(test_ar)  # 计算试样测试次数
std_not = len(std_origin[0])  # 计算标准点数
vol_b = (std_not * sum([i * j for i, j in zip(std_origin[0], std_origin[1])]) - (sum(std_origin[0]) * sum(std_origin[1]))) / (
        len(std_origin[1]) * sum([pow(i, 2) for i in std_origin[1]]) - pow(float(sum(std_origin[1])), 2))  # 计算斜率并转化成十进制
vol_a = average(std_origin[0]) - vol_b * average(std_origin[1])  # 计算截距
vol_ssd = pow(sum([pow((i - j), 2) for i, j in zip(std_origin[0], [vol_b * i + vol_a for i in std_origin[1]])]) / (std_not - 2), 0.5)  # 计算残差
std_oup = [(i - vol_a) / vol_b for i in std_origin[0]]  # 计算拟合理论x
c_0a = average(test_ar)  # 计算试样浓度y均值
c_sa = average(std_origin[0])  # 计算标准理论y均值
getcontext().prec = 3  # 保留三位有效数字并且修约是按照4舍6入5留双
end_u = Decimal.from_float(
        pow((pow((c_0a - c_sa), 2) / (sum([pow((i - average(std_oup)), 2) for i in std_oup]) * pow(vol_b, 2)) + (1 / test_not) + (1 / std_not)), 0.5) * vol_ssd)  # 计算标准不确定度
std_ur = end_u / Decimal.from_float(average(test_ar))  # 计算相对不确定度
print('标准曲线相对{}%'.format(std_ur * 100))

本部分主要低啊用的包为decimal,主要起到的作用并非十进制的计算而是保留数字的修约方式,并非保留小数位数,这个其实还是挺重要的,并且可以明确的是,不进行特别设置的话同样采取的是“四舍六入五留双”的机制,做一个如下的实验:

from decimal import Decimal, getcontext

a = Decimal.from_float(0.1)
print(a)
getcontext().prec = 16
print(a*Decimal.from_float(1))
getcontext().prec = 17
print(a*Decimal.from_float(1))
getcontext().prec = 18
print(a*Decimal.from_float(1))

a = Decimal.from_float(0.1534)
print(a)
getcontext().prec = 16
print(a*Decimal.from_float(1))
getcontext().prec = 17
print(a*Decimal.from_float(1))
getcontext().prec = 18
print(a*Decimal.from_float(1))

a = Decimal.from_float(0.00001534)
print(a)
getcontext().prec = 16
print(a*Decimal.from_float(1))
getcontext().prec = 17
print(a*Decimal.from_float(1))
getcontext().prec = 18
print(a*Decimal.from_float(1))
0.1000000000000000055511151231257827021181583404541015625
0.1000000000000000
0.10000000000000001
0.100000000000000006

0.1534000000000000085709217501062084920704364776611328125
0.1534000000000000
0.15340000000000001
0.153400000000000009

0.00001533999999999999881879209073787251327303238213062286376953125
0.00001534000000000000
0.000015339999999999999
0.0000153399999999999988

可以看到,有效位数为16位以内的情况下,使用Decimal.from_float还是可以基本保证精度的,getcontext().prec = 为设置有效数字位数。

其他的进位方式的调整可以看官方文档:

2.2填写模板:

l1 = locals()
l1['tpl' + str(h)] = DocxTemplate(varF_2.get())  # 打开模板

# 要插入的图片1路径
image1_path = varF_3.get()
# 要插入的图片2路径
image2_path = varF_4.get()
# 创建2张图片对象
insert_image1 = InlineImage(l1['tpl' + str(h)], image1_path, width=Mm(30))
insert_image2 = InlineImage(l1['tpl' + str(h)], image2_path, width=Mm(30))

if varF_3.get():
    countext = {
            'number': paramet0[0][0],
            'method': paramet0[0][1],
            'name': paramet0[0][2],
            'workstd_number': paramet0[0][11],
            'sample_weight1': paramet0[0][3],
            'sample_weight2': paramet0[0][4],
            'zero': paramet0[0][5],
            'temperature': paramet0[0][9],
            'humidity': paramet0[0][10],
            'yyyy': paramet0[0][6],
            'mm': paramet0[0][7],
            'dd': paramet0[0][8],
            'img1': insert_image1,
            'img2': insert_image2,
    }
    # 取出数据组成字典
else:
    countext = {
            'number': paramet0[0][0],
            'method': paramet0[0][1],
            'name': paramet0[0][2],
            'workstd_number': paramet0[0][11],
            'sample_weight1': paramet0[0][3],
            'sample_weight2': paramet0[0][4],
            'zero': paramet0[0][5],
            'temperature': paramet0[0][9],
            'humidity': paramet0[0][10],
            'yyyy': paramet0[0][6],
            'mm': paramet0[0][7],
            'dd': paramet0[0][8],
    }
for qs in range(1, len(paramet0)):
    l1['context' + str(qs)] = {
            'parameter{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][0]),
            'concentration_name{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][1]),
            'content_name{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][2]),
            'average_name{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][3]),
            'revision_name{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][4]),
            'RR_name{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][5]),
            'concentration1{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][6]),
            'concentration2{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][7]),
            'content1{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][8]),
            'content2{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][9]),
            'average{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][10]),
            'revision{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][11]),
            'RR{b}'.format(b=qs - 1): '{}'.format(paramet0[qs][12]),
    }
    countext.update(l1['context' + str(qs)])  # 合并字典
print(countext)
l1['tpl' + str(h)].render(countext)  # 执行渲染
l1['tpl' + str(h)].save(file_run + '/' + paramet0[0][0] + '.docx')  # 另存

document = Document(file_run + '/' + paramet0[0][0] + '.docx')  # 读入文件
tables = document.tables  # 获取文件中的表格集
table = tables[0]  # 获取文件中的第一个表格
num_sum = [num for num in range(18, len(table.rows) - 3) if not table.cell(num, 1).text]  # 记录空行位置
print(num_sum)
# 删除空行↓
for ed in reversed(num_sum):
    row = table.rows[ed]
    row._element.getparent().remove(row._element)
# 删除空行结束↑
document.save(file_run + '/' + paramet0[0][0] + '.docx')

使用的是docxtpl,既然是填写模板,那么就需要一个word的模板,需要渲染的部分使用双花括号括起来,例如代码中“number”这个值需要替换成给定的值,那么模板中相对应的位置应该是写作“{{number}}“。从第66行开始,渲染后的文件需要删除多余的空行,因此采取python-docx进行删除操作。

2.3openpyxl自适应列宽:

book_b = openpyxl.load_workbook(r"D:Usersxxxx.xlsx")  # 使用openpyxl读取Excel
ws = book_b['2022.11.30_11.27.31']  # 要操作的sheet名
max_rows = ws.max_row  # 获取最大行
max_columns = ws.max_column  # 获取最大列
borders = Border(left=Side(style='thin'), bottom=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'))  # 设置边框,thin为细边框

for c in range(1, max_rows + 1):  # 遍历从1开始至最大行数
    for x in range(1, max_columns + 1):  # 遍历从1开始至最大列数
        ws.cell(c, x).border = borders  # 为每一个行的所有列设置边框
# 推导,因openpyxl下标以1开始,因此[取最大值(计算字节数(转化为字符(c,x组成cell的位置的值)使用gbk编码)) x从第一行开始) c从第一列开始] = 最大列宽度
max_col = [max(len(str(ws.cell(row=x, column=c).value).encode('gbk')) for x in range(1, max_rows + 1)) for c in range(1, max_columns + 1)]

# 设置列宽
for r in range(1, ws.max_column + 1):
    letter_s = get_column_letter(r)  # 将数字转化为列名
    ws.column_dimensions[letter_s].width = max_col[r - 1] + 2  # 设置列宽,加两个字节留出一点富余量
book_b.save(r"D:Usersxxxx.xlsx")


  • 标题
  • 内容
  • 验证码
提交
标题内容提交时间
没有记录!