openpyxl 追加 Excel 数据与 Excel 画像素画

AI悦创

共 5232字,需浏览 11分钟

 ·

2021-02-23 11:44

你好,我是悦创。

本篇文章所涉及代码文件关注公众号:AI悦创,后台回复:20210222

xlsxwriter 只能创建新的文件,不能对文件进行数据的追加和读取操作。

需要追加和读取 xlsx 文件,就需要用到 openpyxl 这个库了。安装命令:pip install openpyxl。使用 openpyxl 完成这面这个需求:

  • 读取上面创建好的 xlsxwriter 插入数据和折线图.xlsx 文件,复制一份,保存到 poenpyxl 插入数据和折线图[copy xlsxwriter].xlsx 复制的文件中
  • sheet1 保持和源文件的 sheet1 一致,折线图不画复制的文件中
  • 创建一个 sheet2,sheet2 的数据从 sheet1 中拷贝过来
  • 随机的增加 1 年的随机数据,也就是  2020年1月至12月的日期,数据1 和数据2 的 12 个数据随机生成
  • 在 sheet2 中画一个折线图,统计数据1 和数据2

需求有四个,有难有易。

拷贝文件

第一个是拷贝文件和 sheet1

其实拷贝了文件,自然就包含sheet1,最简单了,如下代码:

import openpyxl
filename = 'xlsxwriter插入数据和折线图.xlsx'
wb = openpyxl.load_workbook(filename)
wb.save('poenpyxl插入数据和折线图[copy xlsxwriter].xlsx')

这样就得到了源文件和 sheet1 的复制品。

拷贝 sheet 内容

第二个需求,拷贝sheet1,做成sheet2

也简单,如下代码:

import openpyxl
filename = 'xlsxwriter插入数据和折线图.xlsx'
wb = openpyxl.load_workbook(filename)

sheet1 = wb['sheet1']
sheet2 = wb.copy_worksheet(sheet1)
sheet2.title = "sheet2"

wb.save('poenpyxl插入数据和折线图[copy xlsxwriter].xlsx')

获取 sheet1,复制一个给 sheet2  参数,然后改下  sheet2 的标题 title,这个  title 就是文件的 sheet2 的名字。

追加数据内容

第三个需求,sheet2 中,数据1 和数据2 追加一年的数据,数据可以随意生成

貌似简单,但是年份时间不好计算,并且现在只有 2019 年的。如果之前数据是 2018 年,则追加一年,应该是 2019 年,所以要读取时间和月份追加。

这里的难点就是时间字符串的读取,以及字符串转时间,以及时间的相加。如下实现代码:

import openpyxl, random, datetime
from dateutil.relativedelta import relativedelta
filename = 'xlsxwriter插入数据和折线图.xlsx'
wb = openpyxl.load_workbook(filename)

sheet1 = wb['sheet1']
sheet2 = wb.copy_worksheet(sheet1)
sheet2.title = "sheet2"

rows = sheet2.max_row # 读取最后一行
prev_date_str = sheet2.cell(row=rows,column=1).value # 取出时间的字符串
prev_date = datetime.datetime.strptime(prev_date_str, "%Y-%m") # 时间字符串转时间对象
for i in range(1,13):
tmp_date = prev_date + relativedelta(months=i) # 月份的计算,每次增加一个月,就得到了第二年的12个月
tmp_num1 = random.randint(1,100)
tmp_num2 = random.randint(1,100)
sheet2.append([tmp_date.strftime("%Y-%m"), tmp_num1, tmp_num2])

wb.save('poenpyxl插入数据和折线图[copy xlsxwriter].xlsx')

实现思路:

  • 读取出最后一行
  • 取出时间字符串,然后转换成时间对象
  • 一年 12 个月,循环 12 次,每次增加一个月,数值可以随机的生成,用 random 即可
  • 数据的追加,是按每行,所以将【时间, 数据1, 数据2】通过 append 直接追加到数据最后即可

第三个需求搞定,下一个需求,sheet2 画折线图

使用 openpyxl 画图表

第四个需求,在 sheet2 中对全部数据画折线图

这个难度不大,只要知道 openpyxl 的画图工具即可,如下代码:

import openpyxl, random, datetime
from dateutil.relativedelta import relativedelta
filename = 'xlsxwriter插入数据和折线图.xlsx'
wb = openpyxl.load_workbook(filename)

sheet1 = wb['sheet1']
sheet2 = wb.copy_worksheet(sheet1)
sheet2.title = "sheet2"

rows = sheet2.max_row
prev_date_str = sheet2.cell(row=rows,column=1).value
prev_date = datetime.datetime.strptime(prev_date_str, "%Y-%m")
for i in range(1,13):
tmp_date = prev_date + relativedelta(months=i)
tmp_num1 = random.randint(1,100)
tmp_num2 = random.randint(1,100)
sheet2.append([tmp_date.strftime("%Y-%m"), tmp_num1, tmp_num2])

# 下面是画折线图的实现代码
from openpyxl.chart import Series,LineChart, Reference
chart = LineChart() #图表对象
rows = sheet2.max_row

data1 = Reference(sheet2, min_col=2, min_row=1, max_col=2, max_row=rows) #涉及数据
title1 = sheet2.cell(row=1,column=2).value
seriesObj1 = Series(data1, title=title1) #创建series对象

data2 = Reference(sheet2, min_col=3, min_row=1, max_col=3, max_row=rows) #涉及数据
title2 = sheet2.cell(row=1,column=3).value
seriesObj2 = Series(data2, title=title2) #创建series对象

chart.append(seriesObj1) #添加到chart中
chart.append(seriesObj2) #添加到chart中

sheet2.add_chart(chart, "E3") #将图表添加到 sheet中


wb.save('poenpyxl插入数据和折线图[copy xlsxwriter].xlsx')

导入所需的画图工具,图表初始化,然后生成数据对象:

  • data1 的生成,因为索引从1 开始,所以标题是第一行第二列,数据是第二行第二列,一直到最后一行第二列
  • data2 的生成,因为索引从1开始,所以标题是第一行第三列,数据是第二行第三列,一直到第二行最后三列
  • 将两个数据都放到图表内
  • 然后图表的开始位置,设置成 E3,数据在 ABC,E 是空的,3 距离顶部有两格的位置

最后文件保存,大功告成。

查看最后的效果图

然后就是用 Office 打开 poenpyxl 插入数据和折线图 [copy xlsxwriter].xlsx,看下  sheet2 的样子,如下图:

25 行数据,除了标题 24 行,刚好是 2019+2020 的 24 个月。折线图也一切正常。

Excel 画像素画

Excel 和图片类似

Excel 文件,单元格支持编辑内容和设置背景色。

一张图片,都是由密密麻麻的像素组成,且每个像素都是一个 rgb 的颜色值。

那是否可以读取图片每个像素的颜色,填充到 Excel 中,就可以做到 Excel 中画图。

这么想,是可以的。理论上也是可行的,那接下来就开始写代码。

打开文件和图片

第一步,导入所需库,分别是 xlsxwriter 和图片的  Image 库。使用 xlsxwriter 的理由,是 xls 内容有限,图片的像素可是很多的,所以最好是使用 xlsx 格式。

import xlsxwriter
from PIL import Image

导入之后,准备图片,并读取图片的宽高,以及像素对象:

path = '1.png'
img = Image.open(path)
imgL = img.convert("P").convert("RGB")
pix = imgL.load()
w, h = imgL.size
image.png

使用 Image 读取图片对象,获取宽和高,以及 pix 这像素对象,通过 pix[1,1 ]拿到具体的颜色 RGB 值,然后转换成 16 进制的颜色值,进行背景色的写入。

准备一个特殊函数

现在打开一个 xlsx 文件,文件名任意,如下代码:

wb = xlsxwriter.Workbook('demo2.xlsx')
ws = wb.add_worksheet('sheet1')

然后找一个 RGB 转 16 进制的函数,因为 RGB 是 10 进制的,方式就是通过 hex 函数转换成 16  进制,然后加上 x  和 0,并全部大写,就可以了。如下函数:

def RGB_to_Hex(tmp):
rgb = list(tmp)
strs = '#'
for i in rgb:
num = int(i)
strs += str(hex(num))[-2:].replace('x','0').upper()
return strs

「为什么一定要   16  进制?」 因为  sheet 中,写入背景色时,颜色必须是 16 进制才可以。

读取和写入

下面就是循环的逐个单元格设置背景色,且不需要写入内容。如下代码:

for i in range(w):
for j in range(h):
rgb = pix[i,j]
color = RGB_to_Hex(rgb)
style = wb.add_format({'bg_color': '{}'.format(color)})
ws.write(j,i,'',style)
ws.set_row(j,1)
ws.set_column(0,w-1,0.5)

wb.close()

代码思路:

  • 循环读取宽和高,读取到全部的分辨率节点
  • 然后通过 pix 读取指定 x,y 的 RGB 值,再转换成 16 进制的内容
  • 设置 style 样式,颜色值就是转换之后的  16 进制
  • 然后写入单元格,内容是空,颜色背景是 style
  • 循环内也要设置当前单元格的行高
  • 循环外,统一设置单元格的宽度

这是单元格的主要代码,写完后,关闭 workbook 即可。

查看像素画

读取图片的全部宽高,然后描绘到  Excel 中完成了。最后用图片的形式展示下文件的样子,如下图【使用  WPS 软件查看】:

image.png


长按识别下方二维码,和众多位岛民一起

把别人的顿悟,变成你的基本功


 花半秒钟就看透事物本质的人,
  和花一辈子都看不清的人,
  注定是截然不同的命运。

浏览 23
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报