使用argparse转换显微镜数据MatLab输出文本为CSV文件遇阻求助
解决Python处理显微镜数据时的TypeError: 'NoneType' object is not subscriptable错误
问题描述
我尝试用往届学生留下的Python代码处理显微镜数据,代码通过argparse读取MatLab输出的文本文件,将其转换为适合R进一步分析的长格式。但由于缺乏工作流示例且经验不足,代码始终无法正常运行。我尝试手动替换代码中的文件名,但反复出现TypeError: 'NoneType' object is not subscriptable错误,求解决方法。
原代码如下:
import csv import argparse parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", help = "Input File") args=parser.parse_args() print("Input {}".format(args.input)) name = args.input out = name[:-4] +"_SCRAPED.csv" outDet = name[:-4] +"_SCRAPED_DETAILED.csv" cellStarts = [] spotStarts =[] spotEnds = [] print("Scraping data from" + " "+name) #FISHQuants = with open(name) as tsv: reader = csv.reader(tsv, delimiter = "\t") FISH = list(reader) #Get cell starts, spot starts and spot ends. These can be used to # 1) Attribute spots to specific cells # 2) Determine the number of spots for each cell # 3) Determine the total number of spots in the image and therefore the average spots per cell i=0 while i <len(FISH): if "CELL_START" in FISH[i]: if "SPOTS_START" in FISH[i+10]: cellStarts.append(i) elif "SPOTS_START" in FISH[i]: spotStarts.append(i) elif "SPOTS_END" in FISH[i]: spotEnds.append(i) i += 1 i=0 if len(cellStarts) != len(spotStarts): print("Number of Cells does not equal number of spots cell identifiers, check the original .txt for cells without any spots") exit(code = 1) else: print("Number of Cells =" + " " + str(len(cellStarts))) cellHeader = "Cell" countHeader = "Spots" detHeader = FISH[spotStarts[0]+1] countRows = [[cellHeader] + [countHeader]] detRows = [[cellHeader] + detHeader[0:]] while i < len(cellStarts): cellNum = i+1 spotCount = (spotEnds[i]-1)-(spotStarts[i]+2) detStart = spotStarts[i]+2 detEnd = spotEnds[i]-1 x = detStart while x < detEnd: detailed = FISH[x] spotsDetailed = [str(cellNum)] + detailed detRows.append(spotsDetailed) x = x+1 countRows.append([str(cellNum)] + [str(spotCount)]) i = i+1 with open(out, "w") as f: writer = csv.writer(f) writer.writerows(countRows) f.close() with open(outDet, "w") as d: writer = csv.writer(d) writer.writerows(detRows) d.close() print("Scraping Completed")
错误原因分析
- 输入参数未正确传入:原代码未强制要求
-i参数,若运行时未传入该参数,args.input会是None,执行name[:-4]时就会触发下标访问错误。 - 文件内容不符合预期:代码依赖输入文件中存在
CELL_START、SPOTS_START、SPOTS_END标记,如果文件中没有这些内容,spotStarts会是空列表,执行detHeader = FISH[spotStarts[0]+1]时会引发索引错误;此外原代码中直接访问FISH[i+10]未做边界检查,若列表长度不足会导致索引越界。 - 文件读取未做异常处理:若输入文件路径错误或文件不存在,
open(name)会直接抛出异常,没有友好提示。
修复方案与代码
以下是修复后的代码,针对上述问题添加了参数校验、异常处理和边界检查:
import csv import argparse parser = argparse.ArgumentParser(description='Convert MatLab microscope data to R-compatible long format') # 强制要求输入参数,避免args.input为None parser.add_argument("-i", "--input", help="Input File", required=True) args = parser.parse_args() print(f"Input: {args.input}") name = args.input # 先校验文件名格式(确保后缀是4位,比如.txt) if len(name) < 4 or not name.endswith('.txt'): print("Error: Input file must be a .txt file") exit(1) out = name[:-4] + "_SCRAPED.csv" outDet = name[:-4] + "_SCRAPED_DETAILED.csv" cellStarts = [] spotStarts = [] spotEnds = [] try: print(f"Scraping data from {name}") with open(name, 'r') as tsv: reader = csv.reader(tsv, delimiter="\t") FISH = list(reader) # 检查文件是否为空 if not FISH: print("Error: Input file is empty") exit(1) i = 0 while i < len(FISH): # 检查当前行是否非空,避免索引空列表 if not FISH[i]: i += 1 continue if "CELL_START" in FISH[i]: # 检查i+10是否超出列表长度,避免索引越界 if i + 10 < len(FISH) and "SPOTS_START" in FISH[i+10]: cellStarts.append(i) elif "SPOTS_START" in FISH[i]: spotStarts.append(i) elif "SPOTS_END" in FISH[i]: spotEnds.append(i) i += 1 # 检查spotStarts是否非空 if not spotStarts: print("Error: No SPOTS_START markers found in input file") exit(1) if len(cellStarts) != len(spotStarts): print("Warning: Number of Cells does not equal number of spots cell identifiers. Check original .txt for cells without spots.") # 这里不直接退出,而是继续处理已有的数据(可选,根据需求调整) print(f"Number of Cells = {len(cellStarts)}") cellHeader = "Cell" countHeader = "Spots" # 校验spotStarts[0]+1是否在FISH范围内 if spotStarts[0] + 1 >= len(FISH): print("Error: Invalid SPOTS_START position, no header row found") exit(1) detHeader = FISH[spotStarts[0]+1] countRows = [[cellHeader, countHeader]] detRows = [[cellHeader] + detHeader] i = 0 # 确保循环只处理存在对应spotStarts的cell max_iter = min(len(cellStarts), len(spotStarts), len(spotEnds)) while i < max_iter: cellNum = i + 1 # 计算spotCount时检查边界 if spotEnds[i] - 1 < spotStarts[i] + 2: spotCount = 0 else: spotCount = (spotEnds[i]-1) - (spotStarts[i]+2) detStart = spotStarts[i] + 2 detEnd = spotEnds[i] - 1 # 确保detStart <= detEnd,避免无效循环 if detStart <= detEnd and detEnd < len(FISH): x = detStart while x <= detEnd: detailed = FISH[x] spotsDetailed = [str(cellNum)] + detailed detRows.append(spotsDetailed) x += 1 countRows.append([str(cellNum), str(spotCount)]) i += 1 # 写入输出文件 with open(out, "w", newline='') as f: writer = csv.writer(f) writer.writerows(countRows) with open(outDet, "w", newline='') as d: writer = csv.writer(d) writer.writerows(detRows) print("Scraping Completed") except FileNotFoundError: print(f"Error: Input file '{name}' not found") exit(1) except Exception as e: print(f"Unexpected error: {str(e)}") exit(1)
使用说明
- 运行代码时必须通过命令行传入输入文件路径:
python your_script_name.py -i path/to/your/matlab_output.txt - 确保输入的
.txt文件包含代码依赖的CELL_START、SPOTS_START、SPOTS_END标记,格式与往届学生处理的文件一致。
内容的提问来源于stack exchange,提问作者m.eastham93
相关产品推荐
相关产品推荐

