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?