ニャンポ魚

ニャンポうお

やや公共性のあるメモ。泥臭い実験生物学を、ICTの力でちょっとでも効率的にやりたい。

Open Field Tests の座標データ群から中央滞在時間と総移動距離を計算してまとめるPythonコード

このコードは DuoMouse*1 *2というトラッキングソフトが吐き出す動物の座標データから、Open Field Test におけるTime in Center と Total Travel Distance を算出し、同時にファイル名から個体の属性を読み取って、csvファイルにそれらデータをまとめて出力することを目的として書かれている。

ファイル名から個体の属性を読み取れるのは、実験を行った際にファイル命名のルールを決めておいたからなので、このあたりは筆者の環境でしかうまく動かないような要素ということになる。実際に使われる際には適宜書き換えが必要になると思われるがご了承いただきたい。あとガバがあって大事なデータがメタメタになっても筆者は責任とりません。クソコードゆるして。

import re
import csv
from pathlib import Path
import datetime
import numpy as np
import os

report = 'report' + input()+ '.csv'
#実行時に出力csvファイルの名前を手打ちする。

out = open(report, "w")
out.close()
                                        
def calcTTD(log):
    v = np.loadtxt(log, delimiter=',', usecols=(1,2))
    v = np.diff(v, axis=0) # 各点間の差を取得
    every_distance = np.linalg.norm(v, axis=1) # 各点間のユークリッド距離を計算
    TTD = '{0:.1f}'.format(np.sum(every_distance, dtype=float)) #総移動距離を計算して小数点以下一桁に丸める
    return TTD #単位はpx

def calcTiC(log, FPS, mesh_num, area_num): #mesh_numはフィールド全体を何マス×何マスに区切るか。area_numはそのうち何マス×何マスを中央と見なすか
    y = np.loadtxt(log, delimiter=',', dtype='int64', usecols=[1])
    x = np.loadtxt(log, delimiter=',', dtype='int64', usecols=[2])
    H, xedges, yedges = np.histogram2d(x, y, bins=(mesh_num, mesh_num), range=((0, HEIGHT),(0, WIDTH))) #ヒストグラム作成
    #各メッシュでの滞在時間をヒストグラムにまとめているので、そのままmatplotlibでヒートマップを出すこともできる。ここでは省略
    H = H/FPS
    Y = int((mesh_num-area_num)/2)
    centre = H[Y:mesh_num-Y,Y:mesh_num-Y]
    TiC = '{0:.1f}'.format(np.sum(centre, dtype=float)) #中央滞在時間の合計を出して小数点以下一桁に丸める
    return TiC #単位はsec

p = Path(r'hoge/hoge/hoge') #データをまとめて置いているディレクトリを指定

file_ls = list(p.glob("**/*")) #サブディレクトリに含まれているファイルの一覧を取得
file_ls = [str(i) for i in file_ls]
file_ls = [i for i in file_ls if 'xy.csv' in i] #そのうち_xy.csvを含むものだけを得る

with open(report, 'a') as f:
        writer = csv.writer(f)
        writer.writerow(['yy', 'mm', 'dd', 'sex', 'number', 'trial', 'TTD', 'TiCa', 'TiCb', 'TiCc', 'TiCd', 'TiCe', 'TiCf'])

#DuoMouseでは撮影した動画のFPSやピクセルサイズなどのデータが座標ファイルとは別に出力されている
#以下はそれを探してきて解析に使うためのコード
for i in file_ls:
    log = i
    ver_i = i.strip("xy.csv") + 'recording.log.txt'
    ld = open(ver_i)
    lines = ld.readlines()
    ld.close()
    regex = re.compile('\d+')
    for line in lines:
        if line.find("TARGET AREA WIDTH") >= 0:
            WIDTH = regex.search(line[:-1])
            print(WIDTH)
            print(WIDTH.group())
            WIDTH=int(WIDTH.group())
        elif line.find("TARGET AREA HEIGHT") >= 0:
            HEIGHT = regex.search(line[:-1])
            print(HEIGHT)
            print(HEIGHT.group())
            HEIGHT=int(HEIGHT.group())
        elif line.find("CAMERA FPS") >= 0:
            FPS= regex.search(line[:-1])
            print(FPS.group())
            FPS=int(FPS.group())
 #実際の計算。TiCは6種のサイズでとってみる
    TTD = calcTTD(log)                            
    TiCa = calcTiC(log, FPS, 10, 8)
    TiCb = calcTiC(log, FPS, 9, 7)
    TiCc = calcTiC(log, FPS, 8, 6)
    TiCd = calcTiC(log, FPS, 7, 5)
    TiCe = calcTiC(log, FPS, 5, 3)
    TiCf = calcTiC(log, FPS, 3, 1)
    #ファイル名から属性を抽出してcsvに書き込み
    #元ファイルは[yy]-[mm]-[dd]-[sex]-[individual_number]-[trial_number]というルールで命名していっていたので、それをふまえてcsvに出力
    i = os.path.basename(i)
    name = i.split('-')
    yymmdd = name[0]
    yy = yymmdd[:2]
    mm = yymmdd[2:4]
    dd = yymmdd[4:]
    ind = name[1]
    number = re.sub("\\D", "", ind)
    sex = ind.strip(number)
    try:
        tail = name[2]
    except IndexError:
        pass
    trial = tail[:1]
    with open(report, 'a') as f:
        writer = csv.writer(f)
        writer.writerow([yy, mm, dd, sex, number, trial, TTD, TiCa, TiCb, TiCc, TiCd, TiCe, TiCf])

*1:DuoMouse http://www.mgrl-lab.jp/DuoMouse.html

*2:余談だが、Duo の名のとおり、もともとは二匹のマウスのソーシャルインタラクションを検討するために書かれたソフトらしい。大は小を兼ねるということで筆者は一匹のマウスの行動解析に利用させていただいている。