使用Python完成光谱数据的小批量处理
可能连CS专业的大一新生的期中作业的水准都达不到吧。
需求
将实验采集到的吸收光谱与发射光谱数据批量导入到预先制作好的Excel模板中。
背景介绍
最近在做一些荧光染料相关的课题。
在测量化合物的光谱信息时,仪器会输出格式如下的吸收光谱信息与发射光谱信息。
其中Abs
代表Absorption,即吸收光谱,Em
代表Emission,即发射光谱;第1列信息为波长,第2列为对应波长的吸光度或荧光强度。
在实验过程中,首先在比色皿内加入空白溶剂,扫描其吸收谱与发射谱;然后加入感兴趣的荧光染料,混匀后再次扫描吸收谱与发射;后者与前者相减,即可得到染料在当前溶剂环境下的光谱;进一步地,通过测量染料在不同溶剂环境下的光谱,即可了解染料的溶致变色性质,温度敏感性质,粘度敏感性质等信息。
对于每个化合物,我最终会把实验上得到的数据汇总到两个格式如下的Excel文件中,一个文件存储吸收光谱,一个文件存储发射光谱。下面以发射光谱为例。
这份总表记录了化合物在实验室所有已有溶剂中的发射光谱。BG
代表background,即溶剂的空白光谱;EM1
、EM2
、EM3
代表3次平行实验所得发射光谱数据。通过Excel的公式功能,可以实现光谱背景的扣除、光谱数据的归一化,峰值及其位置的查询等基本操作。此外,通过Excel的绘图功能,可以得到一张足以应付组会的光谱汇总图。
已有的工作流程
0.在实验过程中,为了便于后续处理,我会将背景文件命名为化合物名称-Em-BG-溶剂.csv
,例如New-2-Em-BG-DMSO.csv
;将发射光谱文件命名为化合物名称-Em-浓度-溶剂数字.csv
,例如New-2-Em-5uM-DMSO2.csv
,其中2
代表第2次平行实验;
1.将上述汇总表内的存放实验数据的列都清空,即可得到一份模板文件;
2.打开任意一份仪器输出的原始数据文件,将波长信息粘贴至模板的第一列;
3.依次将打开各个原始文件,将溶剂背景光谱和发射光谱粘贴至对应的位置;
4.对吸收光谱文件执行相同的操作。
痛点
手动将一个一个文件打开,然后复制、粘贴、关闭——这个过程机械重复且浪费时间。
假定有3个待测化合物,需要测量它们在4种溶剂中的发射光谱,考虑到每组需要测量1次背景和3次平行,则最终需要处理3*4*(1+3)=48
个光谱文件;再考虑测量吸收光谱,则还需要处理另外48个光谱文件。这是难以容忍的。
因此,考虑使用Python完成光谱数据的小批量处理。
关键需求分析
运行效率并不在考虑范围之内,因为顶多也就是几百个小文件的批量读写,对于现代计算机的性能来说绰绰有余。
关键在于,在处理过程中,需要维持模板内的公式与图表不被破坏,常用的pandas
和numpy
似乎并不支持这一点。
查询可知,openpyxl
支持对.xslx
文件的专门操作。
代码实现
from openpyxl import load_workbook
from csv import reader
from os import listdir
#读取空白模板
print("正在载入模板...")
workbook = load_workbook('./Template/EmissionSpectra_Blank.xlsx')
worksheet = workbook.active
print("载入完成")
#读取目录下的.csv格式的原始文件
print("正在检索待处理文件...")
csv_list=[]
for name in listdir(): #遍历当前目录下的文件名
if name.split('.')[-1]=='csv': #用“.”作为分隔符,用-1来指向最后一个元素,以此判断文件类型
csv_list.append(name)
print("检索完成")
#处理光谱文件
print("开始处理文件...")
loop = 1
for name in csv_list:
#首先读取波长信息
if loop == 1:
print("正在读取波长范围...")
with open(name) as raw_data:
reader_obj = reader(raw_data)
wavelength = [row[0] for row in reader_obj] #提取第一列的波长
j = 2
for value in wavelength:
worksheet[ 'A' + str(j)] = float(value)
j = j + 1
loop = loop + 1
print("读取完成,波长范围为"+str(wavelength[0])+"nm到"+str(wavelength[-1])+"nm")
#判断是否为背景光谱
if name.split('-')[-2]=='BG':
solvent = ( name.split('-')[-1] ).split('.')[0] #提取溶剂类型
print("正在读取"+solvent+"的背景光谱...")
with open(name) as raw_data:
reader_obj = reader(raw_data)
column = [row[1] for row in reader_obj] #提取第二列的荧光强度
for row in worksheet.iter_rows(min_row=1,max_row= 1): #提取第一行
for cell in row: #在第一行内遍历
if cell.value == solvent + "-BG":
cell_position = cell.coordinate #定位"solvent-BG"所在单元格位置
line_position = cell_position[0:-1] #提取列号
i=2
for value in column:
worksheet[line_position + str(i)] = float(value)
i = i + 1
print(solvent+"的背景光谱读取完成")
#如果不是背景光谱,则为发射光谱
if name.split('-')[-2]!='BG':
solvent = ( name.split('-')[-1] ).split('.')[0] #提取溶剂类型以及平行测试序号
print("正在读取"+solvent+"的发射光谱...")
number = solvent[-1]
solvent = solvent[0:-1]
with open(name) as raw_data:
reader_obj = reader(raw_data)
column = [row[1] for row in reader_obj] #提取第二列的荧光强度
for row in worksheet.iter_rows(min_row=1,max_row= 1): #提取第一行
for cell in row: #在第一行内遍历
if cell.value == solvent + "-EM" + str(number):
cell_position = cell.coordinate #定位"solvent-BG"所在单元格位置
line_position = cell_position[0:-1] #提取列号
i=2
for value in column:
worksheet[line_position + str(i)] = float(value)
i = i + 1
print(solvent+number+"的发射光谱读取完成")
print("正在导出光谱处理数据EmissionSpectra_Completed.xlsx")
workbook.save("./Template/EmissionSpectra_Completed.xlsx")
print("导出完成 :)")
使用
把待处理的原始文件放在当前目录,然后运行程序,结果符合预期。
后记
这代码丑陋得一塌糊涂。
谢邀,CS大一新生的python课程在学期中后期才讲到文件(
我进的大类招生,大一一年甚至都不会选定专业
然而实际情况可能是,在部分学校的计算机相关专业,第一、二、三学年才会接触面向对象编程,而Python很明显是属于那部分里面的(国防科大那边听说是cpp开始,我们学校c开始,大二cpp(cs,iot,信抗等)/java(软工等),也有大三java的(人工智能,但是不属于计科院))。Python一般算进阶课程,配合后面开的大数据讲的
您!医学博士,学点python小儿科啦,ORZ