You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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")

错误原因分析

  1. 输入参数未正确传入:原代码未强制要求-i参数,若运行时未传入该参数,args.input会是None,执行name[:-4]时就会触发下标访问错误。
  2. 文件内容不符合预期:代码依赖输入文件中存在CELL_START、SPOTS_START、SPOTS_END标记,如果文件中没有这些内容,spotStarts会是空列表,执行detHeader = FISH[spotStarts[0]+1]时会引发索引错误;此外原代码中直接访问FISH[i+10]未做边界检查,若列表长度不足会导致索引越界。
  3. 文件读取未做异常处理:若输入文件路径错误或文件不存在,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)

使用说明

  1. 运行代码时必须通过命令行传入输入文件路径:
    python your_script_name.py -i path/to/your/matlab_output.txt
    
  2. 确保输入的.txt文件包含代码依赖的CELL_START、SPOTS_START、SPOTS_END标记,格式与往届学生处理的文件一致。

内容的提问来源于stack exchange,提问作者m.eastham93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 20:24:55