186 lines
8.0 KiB
Python
186 lines
8.0 KiB
Python
from numpy.lib.function_base import angle
|
|
import pandas as pd
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib import ticker
|
|
import glob
|
|
import os
|
|
from IPython import embed
|
|
import pycircstat as stats
|
|
|
|
from etrack import TrackingResult
|
|
|
|
fish_color = {'2019lepto03': {'main': 'red', 'dark': 'darkred', 'light': 'indianred'},
|
|
'2020lepto20': {'main': 'orange','dark': 'sienna', 'light': 'sandybrown'},
|
|
'2020lepto48': {'main': 'gold', 'dark': 'darkgoldenrod', 'light': 'yellow'},
|
|
'2020lepto40': {'main': 'yellowgreen', 'dark': 'seagreen', 'light': 'mediumspringgreen'},
|
|
'2020lepto42': {'main': 'turquoise', 'dark': 'darkslategrey', 'light': 'aquamarine'},
|
|
'2020lepto43': {'main': 'cornflowerblue', 'dark': 'midnightblue', 'light': 'dodgerblue'},
|
|
'2020lepto46': {'main': 'm', 'dark': 'darkmagenta', 'light': 'violet'}}
|
|
|
|
stimulus_angles = {1: 0, 2: 300 / 180 * np.pi, 3: 240/180 * np.pi, 4: np.pi, 5: 120/180 * np.pi, 6: 60/120 * np.pi}
|
|
light_conditions = ["light", "dark"]
|
|
stimulus_conditions = ["m", "f", "n"]
|
|
|
|
def plot_angles(angles, stimulus="", dark_light="", ax=None, color=None):
|
|
if color is None:
|
|
dark_color = "tab:blue"
|
|
else:
|
|
dark_color = color
|
|
|
|
if ax is None:
|
|
fig = plt.figure()
|
|
ax = fig.add_subplot(1,1,1, polar=True)
|
|
edges = np.linspace(0, 2*np.pi, 25)[:-1]
|
|
n, bins, patches = ax.hist(angles / 180 * np.pi, bins=edges, density=True, align="left", color=dark_color, alpha=1.0 if dark_light == "dark" else 0.5)
|
|
mid_angles = bins[1:] - np.diff(bins)/2
|
|
mean_angle = stats.mean(angles/ 180 * np.pi)
|
|
std_angle = stats.std(angles/ 180 * np.pi)
|
|
|
|
ax.set_title(r"stim: %s, light: %s, $\sigma$=%.2f" %(stimulus, dark_light, std_angle/np.pi*180),
|
|
fontsize=7)
|
|
ax.set_xticks(np.linspace(0.0, 2*np.pi, 7)[:-1])
|
|
#ax.set_xticklabels(map(str, np.linspace(0, 300, 6)))
|
|
ax.xaxis.set_major_formatter(ticker.FixedFormatter(list(map(lambda x:"%i$^\circ$" %x, np.linspace(0, 300, 6)))))
|
|
ax.tick_params(which="major", labelsize=8)
|
|
ax.set_yticklabels([])
|
|
ymax = ax.get_ylim()[-1]
|
|
ax.plot([mean_angle, mean_angle],[0.0, ymax], lw=1, ls="solid", color="red")
|
|
if "n" not in stimulus:
|
|
ax.scatter(0.0, ymax, marker="*", color="red", s=50, zorder=2)
|
|
if ax is None:
|
|
plt.show()
|
|
|
|
|
|
def get_trial_metadata(df, results_filename):
|
|
conditions = get_trial_conditions(df, results_filename)
|
|
stim_angle = None
|
|
if not np.isnan(conditions.signal_output.values):
|
|
stim_angle = stimulus_angles[int(conditions.signal_output)]
|
|
release_angle = stimulus_angles[int(conditions.release)]
|
|
subject = conditions.subject.values[0]
|
|
stimulus_type = conditions.stimulus.values[0]
|
|
light_condition = conditions.dark_light.values[0]
|
|
return stim_angle, release_angle, subject, stimulus_type, light_condition
|
|
|
|
|
|
def get_trial_conditions(df, results_filename):
|
|
movie_name = results_filename.split("/")[-1].split("DLC")[0] + ".mp4"
|
|
trial_condition = df[df.dateiname == movie_name]
|
|
return trial_condition
|
|
|
|
|
|
def get_angles(results_filename, min_likelihood=0.95):
|
|
tr = TrackingResult(results_filename)
|
|
angles = tr.angle_to_center("snout", min_likelihood=min_likelihood)
|
|
return angles
|
|
|
|
|
|
def get_all_angles(df, subject, stimulus_condition="n", light_condition="dark", data_folder=os.path.join("..", "data"), min_likelihood=0.95, rotate_no_stim=False):
|
|
subject_trials = df[df.subject == subject]
|
|
trials = subject_trials[(subject_trials.stimulus == stimulus_condition) & (subject_trials.dark_light == light_condition)]
|
|
all_angles = []
|
|
all_angles_joined = []
|
|
print(len(trials))
|
|
for movie in trials.dateiname.values:
|
|
results_files = glob.glob(os.path.join(data_folder, "%s%s"% (movie.split(".mp4")[0], "*.h5")))
|
|
results_file = results_files[0] if len(results_files) > 0 else None
|
|
if results_file is None:
|
|
print("Could not find tracking results for movie %s!" % movie)
|
|
continue
|
|
angles = get_angles(results_file, min_likelihood=min_likelihood)
|
|
if len(angles) == 0:
|
|
print("Skipping movie %s, no data!" % movie)
|
|
continue
|
|
stimulus_angle, release_angle, _, _, _ = get_trial_metadata(df, results_file)
|
|
if stimulus_condition != "n":
|
|
if stimulus_angle is None:
|
|
print("Stimulus angle is None for movie %s, stimulus %s" % (movie, stimulus_condition))
|
|
continue
|
|
angles += (360 - stimulus_angle)
|
|
angles[angles>360] -= 360
|
|
else:
|
|
if rotate_no_stim:
|
|
angles += (360 - release_angle)
|
|
angles[angles>360] -= 360
|
|
|
|
all_angles.append(angles)
|
|
all_angles_joined.extend(angles)
|
|
|
|
return all_angles, all_angles_joined
|
|
|
|
|
|
def characterize_behavior(phis):
|
|
"""[summary]
|
|
|
|
Zugewandt = 3/2 π < 𝞅 ≤ π/2
|
|
Zugewandt = 270 < 𝞅 ≤ 90
|
|
|
|
Abgewandt = π/2 < 𝞅 ≤ 3/2 π
|
|
Abgewandt = 90 < 𝞅 ≤ 270
|
|
|
|
Interagierend = 7/8 π < 𝞅 ≤ 1/4 π
|
|
Interagierend = 315 < 𝞅 ≤ 45
|
|
|
|
Vermeiden = 3/4 π < 𝞅 ≤ 5/4 π
|
|
Vermeiden = 135 < 𝞅 ≤ 225
|
|
"""
|
|
attracted = []
|
|
repelled = []
|
|
interacting = []
|
|
avoiding = []
|
|
|
|
for i in range(len(phis)):
|
|
phi = phis[i]
|
|
attracted.append(len(phi[(phi > 270) | (phi <= 90)]) / len(phi))
|
|
repelled.append(len(phi[(phi > 90) & (phi <= 270)]) / len(phi))
|
|
interacting.append(len(phi[(phi > 315) | (phi <= 45)]) / len(phi))
|
|
avoiding.append(len(phi[(phi > 135) & (phi <= 225)]) / len(phi))
|
|
|
|
return attracted, repelled, interacting, avoiding
|
|
|
|
|
|
def characterize_behavior_all(phis):
|
|
attracted = len(phis[(phis > 270) | (phis <= 90)]) / len(phis)
|
|
repelled = len(phis[(phis > 90) & (phis <= 270)]) / len(phis)
|
|
interacting = len(phis[(phis > 315) | (phis <= 45)]) / len(phis)
|
|
avoiding = len(phis[(phis > 135) & (phis <= 225)]) / len(phis)
|
|
|
|
return attracted, repelled, interacting, avoiding
|
|
|
|
if __name__ == "__main__":
|
|
df = pd.read_csv("../data/Tuebingen_tabelle_fertig.csv", sep=",", index_col=0)
|
|
files = glob.glob("../data/*.h5")
|
|
|
|
for f in files[:1]:
|
|
angles = get_angles(f)
|
|
stimulus_angle, release_angle, subject, stimulus_condition, light_condition = get_trial_metadata(df, f)
|
|
|
|
subjects = df.subject.unique()
|
|
subplot_labels = ["A", "B", "C"]
|
|
results = []
|
|
for subject in subjects:
|
|
fig = plt.figure(figsize=(7, 5))
|
|
for i, light in enumerate(light_conditions):
|
|
for j, stim in enumerate(stimulus_conditions):
|
|
print(subject, light, stim)
|
|
axis = fig.add_subplot(len(light_conditions), len(stimulus_conditions), i * len(stimulus_conditions) + j + 1, polar=True)
|
|
all, all_joined = get_all_angles(df, subject, stimulus_condition=stim, light_condition=light, min_likelihood=0.85, rotate_no_stim=True)
|
|
|
|
if len(all_joined) > 0:
|
|
attracted, repelled, interacting, avoiding = characterize_behavior_all(np.array(all_joined))
|
|
#attracted, repelled, interacting, avoiding = characterize_behavior(all)
|
|
|
|
results.append({"subject": subject, "light_condition": light, "stimulus": stim, "attracted": attracted,
|
|
"repelled": repelled, "interacting": interacting, "avoiding": avoiding})
|
|
plot_angles(np.array(all_joined), stim, light, ax=axis, color=fish_color[subject]["dark"])
|
|
if i == 0:
|
|
axis.text(-0.2, 1.15, subplot_labels[j], transform=axis.transAxes, fontsize=12, fontweight="bold")
|
|
fig.subplots_adjust(wspace=0.45, hspace=0.25, left=0.07, top=0.925, right=0.975, bottom=0.05)
|
|
fig.savefig("%s_preferred_angles.pdf" % subject)
|
|
plt.close()
|
|
results_df = pd.DataFrame(results)
|
|
results_df.to_csv("behavior_results_simple.csv", sep=";")
|
|
embed()
|
|
|
|
# does the fish go to the previous stimulus location? |