Module bvmpc.bv_batch
This module holds functions related to running batch operations.
Expand source code
"""This module holds functions related to running batch operations."""
import os
import numpy as np
import pandas as pd
import math
import seaborn as sns
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
from bvmpc.bv_file import extract_sessions
import bvmpc.bv_analyse as bv_an
import bvmpc.bv_plot as bv_plot
import bvmpc.bv_utils
def struc_timeline(sub_list, in_dir):
"""
Structure sessions into a pandas dataframe based on trials.
Returns
-------
grp_timeline_df, time_df_sub
grp_timeline_df : array
pandas dataframes across time based on session
grp_timeline_df_sub : list
denotes the subject corresponding to each df
"""
# Initialize group variables
grp_timeline_df = []
grp_timeline_df_sub = []
for sub in sub_list:
s_grp = extract_sessions(in_dir, sub)
# Initialize column arrays
d_list, t_list, sub_list, s_idx_list, r_list, s_list = [], [], [], [], [], []
err_FR_list, err_FI_list = [], []
rw_FR_list, rw_FI_list, dr_list = [], [], []
ratio_list, interval_list = [], []
sch_list, sch_rw_list, sch_err_list, sch_dr_list = [], [], [], []
for i, s in enumerate(s_grp):
subject = s.get_metadata('subject')
date = s.get_metadata("start_date").replace("/", "-")[:5]
session_type = s.get_metadata('name')
time = s.get_metadata('start_time')
stage = session_type[:2].replace(
'_', '') # Obtain stage number w/o _
timestamps = s.get_arrays()
pell_ts = timestamps["Reward"]
dpell_bool = np.diff(pell_ts) < 0.5
dpell_idx = np.nonzero(dpell_bool)[0]
reward_times = s.get_rw_ts()
# Initialize variables used per session
ratio, interval, sch, sch_err, sch_rw, sch_dr = [], [], [], [], [], []
err_FI, err_FR, rw_FI, rw_FR = [], [], [], []
ratio = s.get_ratio()
interval = s.get_interval()
# Stage specific variables
if stage == '5a':
s_name = 'R' + str(ratio)
ratio = s_name
rw_FR = len(reward_times)
elif stage == '5b':
s_name = 'I' + str(interval)
interval = s_name
rw_FI = len(reward_times)
else:
s_name = stage.replace('_', '').replace('2', 'M').replace(
'3', 'Lh').replace('4', 'Lt').replace(
'6', 'B1').replace('7', 'B2')
if 'B' in s_name:
rw_FI, rw_FR = 0, 0
ratio = 'R' + str(ratio)
interval = 'I' + str(interval)
norm_r_ts, _, norm_err_ts, norm_dr_ts, _ = s.split_sess(
all_levers=True)
sch_type = s.get_arrays('Trial Type')
# Error related variables
if s_name == 'B2':
err_FI, err_FR = 0, 0
for i, err in enumerate(norm_err_ts):
if sch_type[i] == 1:
err_FR = + len(err)
elif sch_type[i] == 0:
err_FI += len(err)
sch_err.append(len(err))
else:
err_FR = []
err_FI = []
# Reward related variables
for i, (rw, dr) in enumerate(zip(norm_r_ts, norm_dr_ts)):
if sch_type[i] == 1:
rw_FR += len(rw)
sch.append('FR')
sch_dr.append([])
elif sch_type[i] == 0:
rw_FI += len(rw)
sch.append('FI')
sch_dr.append(len(dr))
sch_rw.append(len(rw))
# Update list arrays with new session
d_list.append(date)
t_list.append(time)
s_idx_list.append('S' + stage[0])
s_list.append(s_name)
r_list.append(len(pell_ts))
dr_list.append(len(dpell_idx))
interval_list.append(interval)
ratio_list.append(ratio)
sch_list.append(sch)
sch_rw_list.append(sch_rw)
sch_err_list.append(sch_err)
sch_dr_list.append(sch_dr)
rw_FI_list.append(rw_FI)
rw_FR_list.append(rw_FR)
err_FI_list.append(err_FI)
err_FR_list.append(err_FR)
sub_list = np.full(len(d_list), sub, dtype=int)
timeline_dict = {
'Subject': sub_list,
'Date': d_list,
'Start Time': t_list,
'Stage Idx': s_idx_list, # eg. S2, S5, S7 ...
'Stage': s_list, # eg. M, Lt, R8, I30, B1
'Total Rewards': r_list,
'Double Rewards': dr_list,
'Interval': interval_list,
'Ratio': ratio_list,
'Schedule Blocks': sch_list,
'Schedule Rw': sch_rw_list,
'Schedule Err': sch_err_list,
'Schedule DRw': sch_dr_list,
'FI Corr': rw_FI_list,
'FR Corr': rw_FR_list,
'FI Err': err_FI_list,
'FR Err': err_FR_list
}
timeline_df = pd.DataFrame(timeline_dict)
grp_timeline_df.append(timeline_df)
grp_timeline_df_sub.append(subject)
return grp_timeline_df, grp_timeline_df_sub
def plot_batch_sessions(
start_dir, sub_list, start_date, end_date, plt_flags, sub_colors_dict):
"""
Plot behavioural data across sessions.
Parameters
----------
start_dir : str
The directory to save the plots to and obtain session data from.
Saves to Plots/Current and obtains from /hdf5.
sub_list : list
The list of subjects to consider.
start_date : str
The first date to consider.
end_date : str
The last date to consider.
plt_flags : dict
Flags to denote which kind of plot to do and control the plots.
sub_colors_dict : dict
Dictionary of colours to use for each subject.
Returns
-------
None
"""
out_dir = os.path.join(start_dir, "Plots", "Current")
bvmpc.bv_utils.make_dir_if_not_exists(out_dir)
if plt_flags["raster"] == 1 or plt_flags["hist"] == 1:
# Path join only present in plot_sessions
in_dir = os.path.join(start_dir, "hdf5")
# Default conversion of date based on start_date and end_date range
d = []
for single_date in bvmpc.bv_utils.daterange(start_date, end_date):
d.append(single_date.isoformat()[-5:])
print('Extracting sessions on {} for subjects {}...'.format(d, sub_list))
s_grp = extract_sessions(in_dir, sub_list, d_list=d)
# splits s_grp into groups of 4
plot_set = bvmpc.bv_utils.chunks(s_grp, 4)
for j, plot_grp in enumerate(plot_set):
# Figure Initialization
n = len(plot_grp)
if n > 4:
print('Too many plots')
quit()
elif n > 2:
rows, cols = [4, 4 * math.ceil(n / 2)]
else:
rows, cols = [2 * n, 4 * math.ceil(n / 2)]
# Initializes GridFig Obj
gf = bv_plot.GridFig(rows, cols, wspace=0.5, hspace=0.5)
# fig = gf.get_fig()
# size_multiplier = 5
# fig = plt.figure(
# figsize=(cols * size_multiplier, rows * size_multiplier),
# tight_layout=False)
# gs = gridspec.GridSpec(rows, cols, wspace=0.5, hspace=0.5)
df_sub, df_date, df_stage = [], [], [] # Initialize plot naming parameters
plotting_sub = []
for i, s in enumerate(plot_grp): # Iterate through groups to plot rasters
# plot naming parameters
df_sub.append(s.get_metadata('subject'))
df_date.append(s.get_metadata(
'start_date').replace('/', '_')[:5])
df_stage.append(s.get_stage())
# 2x2 plotting axes
k = (i % 2) * 2
if plt_flags["raster"] == 1:
ax = gf.get_multi_ax(
k, k + 2, 4 * int(i / 2), 4 * math.ceil((i + 1) / 2))
bv_an.plot_raster_trials(
s, ax, sub_colors_dict, align=[0, 0, 1, 0])
plot_type = 'Raster_' # Plot name for saving
if plt_flags["hist"] == 1:
if not plotting_sub == s.get_metadata('subject'):
ax = gf.get_multi_ax(
k, k + 2, 4 * int(i / 2), 4 * math.ceil((i + 1) / 2))
plotting_sub = s.get_metadata('subject')
loop = 1
bv_an.trial_length_hist(s, ax, loop, sub_colors_dict)
plot_type = 'Hist_' # Plot name for saving
loop += 1
# Save Figure
# plt.subplots_adjust(top=0.85)
# fig.suptitle(('Subject ' + subject + ' Performance'),
# color=mycolors(subject), fontsize=30)
# date_p = sorted(set(df_date))
# sub_p = sorted(set(df_sub))
# stage_p = sorted(set(df_stage))
# out_name = plot_type + str(date_p) + '_' + str(sub_p) + '_' + str(stage_p) + '_' + str(j)
# out_name += ".png"
# print("Saved figure to {}".format(
# os.path.join(out_dir, out_name)))
# bv_plot.savefig(fig, os.path.join(out_dir, out_name))
# plt.close()
gf.save_fig(df_date, df_sub, df_stage, plot_type, out_dir, j)
# plot cumulative response graphs
if plt_flags["summary"] == 1:
for single_date in bvmpc.bv_utils.daterange(start_date, end_date):
d = [single_date.isoformat()[-5:]]
# plot_sessions(start_dir, d, sub, summary=True, single=True,
# corr_only=True, scd=sub_colors_dict) # Single animal breakdown
# Group with corr_only breakdown
plot_sessions(start_dir, d, sub_list, summary=True,
single=False, corr_only=True, scd=sub_colors_dict)
# plot_sessions(start_dir, d, sub, summary=True, single=False, corr_only=False, scd=sub_colors_dict) # Group with complete breakdown
# plot all 4 timeline types
if plt_flags["timeline"] == 1:
print("Plotting Timeline...")
d = [end_date.isoformat()[-5:]]
in_dir = os.path.join(start_dir, "hdf5")
single = False # plots seperate graphs for each animal if True
show_date = True # Sets x-axis as dates if True
details = False
recent = False
if not single:
plot_limit = 4
sub_list = bvmpc.bv_utils.split_list(sub_list, plot_limit)
for l in sub_list:
timeline_plot(l, in_dir, out_dir, single_plot=single, det_err=False, det_corr=False,
recent=recent, show_date=show_date, details=details, sub_colors_dict=sub_colors_dict)
else:
# Plots timeline for specified subjects
timeline_plot(sub_list, in_dir, out_dir, single_plot=single, det_err=False, det_corr=False,
recent=recent, show_date=show_date, details=details, sub_colors_dict=sub_colors_dict)
def plot_sessions(
start_dir, d_list, sub_list,
summary=False, single=False, timeline=False,
details=False, det_err=False, det_corr=False,
recent=False, show_date=False, int_only=False,
corr_only=False, scd=None):
"""
Plots session summaries.
The parameters are not currently fully documented.
Parameters
----------
summary : bool, False
Optional. Plots all sessions in a single plot, up to 6
single : bool, False
Optional. Plots single session summaries with breakdown of single blocks
int_only : bool, False
Optional. Plots only interval trials in zoomed schedule plot
corr_only : bool, False
Optional. Plots seperate summary plot with correct only trials
scd : dict, None
dict of Sub : color
Used to assign color to plot title.
TODO
----
Split timeline and plotting into separate functions.
Returns
-------
None
"""
s_list = ['4', '5a', '5b', '6', '7']
in_dir = os.path.join(start_dir, "hdf5")
out_dir = os.path.join(start_dir, "Plots", "Current")
bvmpc.bv_utils.make_dir_if_not_exists(out_dir)
if summary and not corr_only:
# extracts hdf5 session based on specification
max_plot = 4 # Set max plots per figure
s_grp = extract_sessions(in_dir, sub_list, s_list, d_list)
if s_grp == []:
return print("***No Files Extracted***")
idx = 0
if len(s_grp) > max_plot:
j = 0
s_grp_split = []
s_grp_idx = np.arange(len(s_grp))
for i in s_grp_idx[max_plot - 1::max_plot]:
s_grp_split.append(s_grp[j:i + 1])
j = i + 1
mv = len(s_grp) % max_plot
if mv != 0:
s_grp_split.append(s_grp[-mv:])
for s_grp in s_grp_split:
idx += 1
sum_plot(s_grp, idx, out_dir)
else:
sum_plot(s_grp, idx, out_dir)
if summary and corr_only:
# plots corr_only plots
max_plot = 4 # Set max plots per figure
s_grp = extract_sessions(in_dir, sub_list, s_list, d_list)
if s_grp == []:
return print("***No Files Extracted***")
idx = 0
if len(s_grp) > max_plot:
j = 0
s_grp_split = []
s_grp_idx = np.arange(len(s_grp))
for i in s_grp_idx[max_plot - 1::max_plot]:
s_grp_split.append(s_grp[j:i + 1])
j = i + 1
mv = len(s_grp) % max_plot
if mv != 0:
s_grp_split.append(s_grp[-mv:])
for s_grp in s_grp_split:
idx += 1
sum_plot(s_grp, idx, out_dir, corr_only=True)
else:
sum_plot(s_grp, idx, out_dir, corr_only=True)
if single and summary:
# Single Subject Plots
idx = 0
for sub in sub_list:
s_grp = extract_sessions(in_dir, sub, s_list, d_list)
if s_grp == []:
return print("***No Files Extracted***")
s_passed = []
d_passed = []
for s in s_grp:
stage = s.get_metadata('name')[:2].replace('_', '')
s_passed.append(stage)
date = s.get_metadata("start_date").replace("/", "-")
d_passed.append(date[:5])
subject = s.get_metadata('subject')
if '7' in s_passed:
gf = bv_plot.GridFig(len(s_grp), 4)
fig = gf.get_fig()
if len(s_grp) == 1:
fig.tight_layout(rect=[0, 0.03, 0.8, 0.95])
for i, s in enumerate(s_grp):
ax1 = gf.get_next()
bv_an.cumplot(s, out_dir, ax1, int_only,
zoom=False, zoom_sch=False)
ax2 = gf.get_next()
bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True,
plot_error=False, plot_all=True)
ax3 = gf.get_next()
bv_an.cumplot(s, out_dir, ax3, int_only, zoom=False, zoom_sch=True,
plot_error=False, plot_all=False)
ax4 = gf.get_next()
bv_an.cumplot(s, out_dir, ax4, int_only, zoom=False, zoom_sch=True,
plot_error=True, plot_all=False)
plt.subplots_adjust(top=0.85)
if scd == None:
color = "k"
else:
color = bvmpc.bv_utils.mycolors(sub, scd)
fig.suptitle(('Subject ' + subject + ' Performance'),
color=color, fontsize=30)
# # Seperate plots w line
# ax1.hlines(1.13, -0, 4.9, clip_on=False,
# transform=ax1.transAxes, linewidth=0.7)
s_print = np.array_str(np.unique(np.array(s_passed)))
d_print = np.array_str(np.unique(np.array(d_passed)))
out_name = "Sum_" + subject + "_" + d_print + "_" + s_print + ".png"
bv_plot.savefig(fig, os.path.join(out_dir, out_name))
else:
sum_plot(s_grp, idx, out_dir, single=single)
def sum_plot(s_grp, idx, out_dir, zoom=True, single=False,
int_only=False, corr_only=False):
"""
Perform summary plots of a day.
Note that if zoom is True, this function then
divides session into blocks and plots each block as individual lines.
"""
# Plots summary of day
if zoom:
print('zoomed')
if len(s_grp) > 2:
cols = 2 * math.ceil(len(s_grp) / 2)
rows = 2
else:
rows = len(s_grp)
cols = 2
else:
if len(s_grp) > 4:
rows = math.ceil(len(s_grp) / 4)
cols = 4
else:
cols = len(s_grp)
rows = 1
gf = bv_plot.GridFig(rows, cols)
fig = gf.get_fig()
s_passed = []
d_passed = []
for _, s in enumerate(s_grp):
subject = s.get_metadata('subject')
stage = s.get_metadata('name')[:2].replace('_', '')
date = s.get_metadata("start_date").replace("/", "-")
s_passed.append(stage)
d_passed.append(date[:5])
if zoom:
ax1 = gf.get_next_snake()
else:
ax1 = gf.get_next()
if corr_only and stage == '7':
bv_an.cumplot(s, out_dir, ax1, int_only, zoom=False,
zoom_sch=False, plot_all=False)
else:
bv_an.cumplot(s, out_dir, ax1, int_only, zoom=False,
zoom_sch=False)
if stage == '2' or stage == '3' or stage == '4':
IRT = True
elif stage == '5a' or stage == '5b':
IRT = True # Change to False for zoomed plot instead of IRT
else:
IRT = False
if IRT:
ax2 = gf.get_next_snake()
bv_an.IRT(s, out_dir, ax2)
elif zoom:
ax2 = gf.get_next_snake()
if corr_only and stage == '7':
bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True,
plot_error=False, plot_all=False)
else:
bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True,
plot_error=False, plot_all=True)
plt.subplots_adjust(top=0.85)
d_print = np.array_str(np.unique(np.array(d_passed)))
d_title = np.array2string(np.unique(np.array(d_passed)))
s_print = np.array_str(np.unique(np.array(s_passed)))
if single:
fig.suptitle(('Subject ' + subject + ' Performance'), fontsize=30)
out_name = "Sum_" + subject + "_" + d_print + "_" + s_print + ".png"
elif corr_only and stage == '7':
if idx == 0:
fig.suptitle(('Summary across animals ' + d_title +
'_Correct Only'), fontsize=30)
out_name = "Sum_" + d_print + "_" + s_print + "_Corr.png"
else:
fig.suptitle(('Summary across animals ' + d_title +
'_Correct Only' + " p" + str(idx)), fontsize=30)
out_name = "Sum_" + d_print + "_" + \
s_print + "_" + str(idx) + "_Corr.png"
else:
if idx == 0:
fig.suptitle(('Summary across animals ' + d_title), fontsize=30)
out_name = "Sum_" + d_print + "_" + s_print + ".png"
else:
fig.suptitle(('Summary across animals ' +
d_title + " p" + str(idx)), fontsize=30)
out_name = "Sum_" + d_print + "_" + \
s_print + "_" + str(idx) + ".png"
print("Saved figure to {}".format(
os.path.join(out_dir, out_name)))
bv_plot.savefig(fig, os.path.join(out_dir, out_name))
plt.close()
def timeline_plot(
sub_list, in_dir, out_dir, single_plot=False,
det_err=False, det_corr=False, recent=False,
show_date=True, details=False, sub_colors_dict=None):
"""
Plots total rewards from beginning of first session
Not all parameters are currently described.
Parameters
----------
det_err : bool
plots error lever presses
det_cor : bool
plots correct lever presses
recent : bool
plots recent (determined in code - static) datapoints only
show_date : bool
plots date as x axis instead of session type
Returns
-------
None
"""
# Plot size
rows, cols = [len(sub_list), 4]
size_multiplier = 5
fig = plt.figure(
figsize=(cols * size_multiplier, rows * size_multiplier),
tight_layout=False)
gs = gridspec.GridSpec(rows, cols, wspace=0.4, hspace=0.5)
for c, sub in enumerate(sub_list):
# Plot total pellets across sessions
s_grp = extract_sessions(in_dir, [sub])
s_list, r_list, type_list, d_list, box_list, time_list = [], [], [], [], [], []
err_FR_list, err_FI_list = [], []
rw_FR_list, rw_FI_list, rw_double_list = [], [], []
changes, stage_change, dpell_change = [], [], []
change_idx = []
prev_ratio, prev_interval, c_ratio, c_interval = [], [], [], []
dpell_old = []
prev_name = '2'
if recent:
number_sessions_ago = -31 # change value to set number of sessions ago
s_grp = s_grp[number_sessions_ago:]
else:
pass
for i, s in enumerate(s_grp):
ratio = s.get_ratio()
interval = s.get_interval()
s_type = s.get_metadata('name')[:2]
timestamps = s.get_arrays()
date = s.get_metadata('start_date') # Display mm/dd/yy
date = s.get_metadata('start_date')[:-3] # Display mm/dd only
# date = s.get_metadata('start_date').split("/")[1] # Display dd only
subject = s.get_metadata('subject')
pell_ts = timestamps["Reward"]
pell_double = np.nonzero(np.diff(pell_ts) < 0.5)[0]
reward_times = s.get_rw_ts()
box = s.get_metadata('box')
# time format - "%H:%M:%S"
exptime = s.get_metadata('start_time')[:2]
d_list.append(date)
box_list.append(box)
time_list.append(exptime)
if len(pell_double):
dpell_change = 1
if s_type == '5a':
s_name = 'R' + str(ratio)
c_ratio = s_name
elif s_type == '5b':
s_name = 'I' + str(interval)
c_interval = s_name
else:
s_name = s_type.replace('_', '').replace('2', 'M').replace(
'3', 'Lh').replace('4', 'Lt').replace(
'6', 'B1').replace('7', 'B2')
if 'B' in s_name:
c_ratio = 'R' + str(ratio)
c_interval = 'I' + str(interval)
if not prev_name[0] == s_type[0]:
stage_change.append(1)
changes.append(0)
change_idx.append(0)
else:
stage_change.append(0)
if not c_ratio == prev_ratio and not c_interval == prev_interval:
changes.append([c_ratio, c_interval])
change_idx.append(1)
elif not c_ratio == prev_ratio:
changes.append(c_ratio)
change_idx.append(1)
elif not c_interval == prev_interval:
changes.append(c_interval)
change_idx.append(1)
elif not dpell_change == dpell_old:
changes.append("DPell")
change_idx.append(1)
else:
changes.append(0)
change_idx.append(0)
# Calculates total reward (y axis variable)
r_list.append(len(pell_ts))
# Calculates FR & FI rewards and errors (alternative y axis variables)
err_FI = 0
err_FR = 0
rw_FR = 0
rw_FI = 0
rw_double = 0
err_plotted = 0
corr_plotted = 0
if s_type == '7_' or s_type == '6_':
norm_r_ts, _, norm_err_ts, norm_dr_ts, _ = s.split_sess(
all_levers=True)
sch_type = s.get_arrays('Trial Type')
if s_type == '7_':
for i, _ in enumerate(norm_err_ts):
if sch_type[i] == 1:
err_FR = err_FR + len(norm_err_ts[i])
elif sch_type[i] == 0:
err_FI = err_FI + len(norm_err_ts[i])
else:
err_FR = None
err_FI = None
for i, _ in enumerate(norm_r_ts):
rw_double += len(norm_dr_ts[i])
if sch_type[i] == 1:
rw_FR = rw_FR + len(norm_r_ts[i])
elif sch_type[i] == 0:
rw_FI = rw_FI + len(norm_r_ts[i])
elif s_type == '5a':
err_FI = None
err_FR = None
rw_FR = len(reward_times)
rw_FI = None
rw_double = None
elif s_type == '5b':
err_FI = None
err_FR = None
rw_FR = None
rw_FI = len(reward_times)
rw_double = len(pell_double)
else:
err_FI = None
err_FR = None
rw_FR = None
rw_FI = None
rw_double = None
# Updates list arrays with new session
rw_FR_list.append(rw_FR)
rw_FI_list.append(rw_FI)
err_FR_list.append(err_FR)
err_FI_list.append(err_FI)
rw_double_list.append(rw_double)
s_list.append(s_name)
type_list.append('S-' + s_type[0])
# Updates current iteration variables for next loop
dpell_old = dpell_change
prev_ratio = c_ratio
prev_interval = c_interval
prev_name = s_type
if single_plot:
rows, cols = [1, 4]
size_multiplier = 5
fig = plt.figure(
figsize=(cols * size_multiplier, rows * size_multiplier),
tight_layout=False)
gs = gridspec.GridSpec(rows, cols, wspace=0.2, hspace=0.3)
ax = fig.add_subplot(gs[0, :])
out_name = "Timeline_" + subject
if recent:
out_name += "_recent"
if details:
out_name += "_details"
else:
ax = fig.add_subplot(gs[int(c), :])
s_idx = np.arange(0, len(s_list))
if details: # Plots average sessions variables i.e. FR_corr, FI_corr, FR_err, FI_err, double_rw
ratio_c = plt.cm.get_cmap('Wistia')
interval_c = plt.cm.get_cmap('winter')
# Change value to increase height of annotation
# note_height = 0
# y_axis = np.zeros((1, len(s_idx)))[0] + note_height
y_axis = []
# Sets line on which annotations appear
for i, l in enumerate(rw_FR_list):
if l is None:
y_axis.append(0) # Hides non-stage 7 annotations
else:
y_axis.append(l)
plots = []
labels = []
# Dict controls lines to be plot. Set keys to 1 in plot_dict to include line in plot
if det_err:
plot_styles = {
"FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 0],
"FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 1],
"FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 0],
"FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 1],
"FI_DoubleR": [rw_double_list, '*-', 'hotpink', 0]}
err_plotted = 1
elif det_corr:
plot_styles = {
"FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 1],
"FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 0],
"FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 1],
"FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 0],
"FI_DoubleR": [rw_double_list, '*-', 'hotpink', 1]}
corr_plotted = 1
else:
plot_styles = {
"FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 1],
"FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 1],
"FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 1],
"FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 1],
"FI_DoubleR": [rw_double_list, '*-', 'hotpink', 1]}
err_plotted = 1
corr_plotted = 1
plot_dict = {"FR_Corr": 1, "FR_Err": 1,
"FI_Corr": 1, "FI_Err": 1, "FI_DoubleR": 1}
ax2 = ax.twinx()
for k, val in plot_dict.items():
if val:
s = plot_styles[k]
if k[-3:] == "Err":
ax_used = ax2
else:
ax_used = ax
h, = ax_used.plot(s_idx, s[0], s[1], label=k, linewidth='2',
markersize=10, color=s[2], alpha=s[3])
plots.append(h)
labels.append(h.get_label())
ax.set_title('\nSubject {} Timeline_Details'.format(
subject), y=1.05, fontsize=25,
color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict))
else:
# Only plots total rewards
y_axis = r_list
h1, = plt.plot(
s_idx, y_axis, label='Animal' + subject, linewidth='4',
color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict))
ax.set_title(
'\nSubject {} Timeline'.format(subject), y=1.05, fontsize=25,
color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict))
# # Plot experiment time w rewards
# ax2 = ax.twinx()
# y_axis_2 = time_list
# ax2.set_ylim([0, 24])
# ax2.plot(s_idx, y_axis_2, label='Animal'+subject, linewidth='4',
# color=mycolors(subject))
# Annotated changes in protocol
annotate_fontsize = 12
h2 = None
h3 = None
for i, c in enumerate(changes):
if stage_change[i] == 1:
h2 = ax.annotate(type_list[i], xy=(s_idx[i], y_axis[i]),
ha='center', xytext=(0, (.2 * max(y_axis))),
textcoords='offset points',
arrowprops=dict(facecolor='blue', shrink=0.05), size=annotate_fontsize)
elif change_idx[i] == 1:
h3 = ax.annotate(str(c), xy=(s_idx[i], y_axis[i]),
ha='center', xytext=(0, (.2 * max(y_axis))),
textcoords='offset points',
arrowprops=dict(facecolor='Red', shrink=0.05), size=annotate_fontsize)
ax.set_xlim(0, len(s_idx))
if show_date:
# plots x-axis tics as dates
plt.xticks(s_idx, d_list, fontsize=10)
# plt.xticks(s_idx, box_list, fontsize=10) # Plots x-tics as box
ax.set_xlabel('Sessions (Dates)', fontsize=20)
else:
# plots x-axis ticks as stages
plt.xticks(s_idx, s_list, fontsize=13)
ax.set_xlabel('Sessions (Type)', fontsize=20)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.tick_params(axis='y', labelsize=15)
if details:
if 'S-6' in type_list:
ax.axhline(45, xmax=(type_list.index('S-6') / len(type_list)), color=interval_c(2 * 45),
linestyle='-.', linewidth='.5')
ax.axhline(30, xmin=(type_list.index('S-6') / len(type_list)), color=interval_c(2 * 45),
linestyle='-.', linewidth='.5')
ax.text(type_list.index('S-6'), 31, ' Max FI', fontsize=8,
color=interval_c(2 * 45), ha='left', va='bottom')
ax.text(s_idx[0], 46, ' Max FI', fontsize=8,
color=interval_c(2 * 45), ha='left', va='bottom')
else:
ax.axhline(30, color=interval_c(2 * 45),
linestyle='-.', linewidth='.5')
ax.text(s_idx[0], 31, ' Max FI', fontsize=8,
color=interval_c(2 * 45), ha='left', va='bottom')
loc = 'top left'
ax.set_ylabel('Correct Trials', fontsize=20)
# set second y-axis labels
ax2.tick_params(axis='y', labelsize=15)
ax2.set_ylabel('Error Presses', fontsize=20)
else:
# plt.axhline(45, color='g', linestyle='-.', linewidth='.5')
plt.axhline(60, color='r', linestyle='-.',
linewidth='.5') # Marks max reward
ax.set_ylabel('Total Rewards', fontsize=20)
plots = [h1]
labels = [h1.get_label()]
loc = 'lower right'
if h2 is not None and h3 is not None:
plots.extend([h2.arrow_patch, h3.arrow_patch])
labels.extend(['Stage Changes', 'Protocol Mod.'])
elif h2 is not None:
plots.append(h2.arrow_patch)
labels.append('Stage Changes')
elif h3 is not None:
plots.append(h3.arrow_patch)
labels.append('Protocol Mod.')
plt.legend(plots, labels, loc=loc, ncol=2)
if single_plot:
out_name += ".png"
print("Saved figure to {}".format(
os.path.join(out_dir, out_name)))
bv_plot.savefig(fig, os.path.join(out_dir, out_name))
plt.close()
if not single_plot:
out_name = "Timeline_Sum_" + "-".join(sub_list)
if recent:
out_name += "_recent"
if details:
out_name += "_details"
if corr_plotted == 1 and err_plotted == 1:
pass
elif corr_plotted == 1:
out_name += "_corr"
elif err_plotted == 1:
out_name += "_err"
out_name += ".png"
print("Saved figure to {}".format(
os.path.join(out_dir, out_name)))
bv_plot.savefig(fig, os.path.join(out_dir, out_name))
plt.close()
Functions
def plot_batch_sessions(start_dir, sub_list, start_date, end_date, plt_flags, sub_colors_dict)-
Plot behavioural data across sessions.
Parameters
start_dir:str- The directory to save the plots to and obtain session data from. Saves to Plots/Current and obtains from /hdf5.
sub_list:list- The list of subjects to consider.
start_date:str- The first date to consider.
end_date:str- The last date to consider.
plt_flags:dict- Flags to denote which kind of plot to do and control the plots.
sub_colors_dict:dict- Dictionary of colours to use for each subject.
Returns
None
Expand source code
def plot_batch_sessions( start_dir, sub_list, start_date, end_date, plt_flags, sub_colors_dict): """ Plot behavioural data across sessions. Parameters ---------- start_dir : str The directory to save the plots to and obtain session data from. Saves to Plots/Current and obtains from /hdf5. sub_list : list The list of subjects to consider. start_date : str The first date to consider. end_date : str The last date to consider. plt_flags : dict Flags to denote which kind of plot to do and control the plots. sub_colors_dict : dict Dictionary of colours to use for each subject. Returns ------- None """ out_dir = os.path.join(start_dir, "Plots", "Current") bvmpc.bv_utils.make_dir_if_not_exists(out_dir) if plt_flags["raster"] == 1 or plt_flags["hist"] == 1: # Path join only present in plot_sessions in_dir = os.path.join(start_dir, "hdf5") # Default conversion of date based on start_date and end_date range d = [] for single_date in bvmpc.bv_utils.daterange(start_date, end_date): d.append(single_date.isoformat()[-5:]) print('Extracting sessions on {} for subjects {}...'.format(d, sub_list)) s_grp = extract_sessions(in_dir, sub_list, d_list=d) # splits s_grp into groups of 4 plot_set = bvmpc.bv_utils.chunks(s_grp, 4) for j, plot_grp in enumerate(plot_set): # Figure Initialization n = len(plot_grp) if n > 4: print('Too many plots') quit() elif n > 2: rows, cols = [4, 4 * math.ceil(n / 2)] else: rows, cols = [2 * n, 4 * math.ceil(n / 2)] # Initializes GridFig Obj gf = bv_plot.GridFig(rows, cols, wspace=0.5, hspace=0.5) # fig = gf.get_fig() # size_multiplier = 5 # fig = plt.figure( # figsize=(cols * size_multiplier, rows * size_multiplier), # tight_layout=False) # gs = gridspec.GridSpec(rows, cols, wspace=0.5, hspace=0.5) df_sub, df_date, df_stage = [], [], [] # Initialize plot naming parameters plotting_sub = [] for i, s in enumerate(plot_grp): # Iterate through groups to plot rasters # plot naming parameters df_sub.append(s.get_metadata('subject')) df_date.append(s.get_metadata( 'start_date').replace('/', '_')[:5]) df_stage.append(s.get_stage()) # 2x2 plotting axes k = (i % 2) * 2 if plt_flags["raster"] == 1: ax = gf.get_multi_ax( k, k + 2, 4 * int(i / 2), 4 * math.ceil((i + 1) / 2)) bv_an.plot_raster_trials( s, ax, sub_colors_dict, align=[0, 0, 1, 0]) plot_type = 'Raster_' # Plot name for saving if plt_flags["hist"] == 1: if not plotting_sub == s.get_metadata('subject'): ax = gf.get_multi_ax( k, k + 2, 4 * int(i / 2), 4 * math.ceil((i + 1) / 2)) plotting_sub = s.get_metadata('subject') loop = 1 bv_an.trial_length_hist(s, ax, loop, sub_colors_dict) plot_type = 'Hist_' # Plot name for saving loop += 1 # Save Figure # plt.subplots_adjust(top=0.85) # fig.suptitle(('Subject ' + subject + ' Performance'), # color=mycolors(subject), fontsize=30) # date_p = sorted(set(df_date)) # sub_p = sorted(set(df_sub)) # stage_p = sorted(set(df_stage)) # out_name = plot_type + str(date_p) + '_' + str(sub_p) + '_' + str(stage_p) + '_' + str(j) # out_name += ".png" # print("Saved figure to {}".format( # os.path.join(out_dir, out_name))) # bv_plot.savefig(fig, os.path.join(out_dir, out_name)) # plt.close() gf.save_fig(df_date, df_sub, df_stage, plot_type, out_dir, j) # plot cumulative response graphs if plt_flags["summary"] == 1: for single_date in bvmpc.bv_utils.daterange(start_date, end_date): d = [single_date.isoformat()[-5:]] # plot_sessions(start_dir, d, sub, summary=True, single=True, # corr_only=True, scd=sub_colors_dict) # Single animal breakdown # Group with corr_only breakdown plot_sessions(start_dir, d, sub_list, summary=True, single=False, corr_only=True, scd=sub_colors_dict) # plot_sessions(start_dir, d, sub, summary=True, single=False, corr_only=False, scd=sub_colors_dict) # Group with complete breakdown # plot all 4 timeline types if plt_flags["timeline"] == 1: print("Plotting Timeline...") d = [end_date.isoformat()[-5:]] in_dir = os.path.join(start_dir, "hdf5") single = False # plots seperate graphs for each animal if True show_date = True # Sets x-axis as dates if True details = False recent = False if not single: plot_limit = 4 sub_list = bvmpc.bv_utils.split_list(sub_list, plot_limit) for l in sub_list: timeline_plot(l, in_dir, out_dir, single_plot=single, det_err=False, det_corr=False, recent=recent, show_date=show_date, details=details, sub_colors_dict=sub_colors_dict) else: # Plots timeline for specified subjects timeline_plot(sub_list, in_dir, out_dir, single_plot=single, det_err=False, det_corr=False, recent=recent, show_date=show_date, details=details, sub_colors_dict=sub_colors_dict) def plot_sessions(start_dir, d_list, sub_list, summary=False, single=False, timeline=False, details=False, det_err=False, det_corr=False, recent=False, show_date=False, int_only=False, corr_only=False, scd=None)-
Plots session summaries.
The parameters are not currently fully documented.
Parameters
summary:bool, False- Optional. Plots all sessions in a single plot, up to 6
single:bool, False- Optional. Plots single session summaries with breakdown of single blocks
int_only:bool, False- Optional. Plots only interval trials in zoomed schedule plot
corr_only:bool, False- Optional. Plots seperate summary plot with correct only trials
scd:dict, None- dict of Sub : color Used to assign color to plot title.
Todo
Split timeline and plotting into separate functions.
Returns
None
Expand source code
def plot_sessions( start_dir, d_list, sub_list, summary=False, single=False, timeline=False, details=False, det_err=False, det_corr=False, recent=False, show_date=False, int_only=False, corr_only=False, scd=None): """ Plots session summaries. The parameters are not currently fully documented. Parameters ---------- summary : bool, False Optional. Plots all sessions in a single plot, up to 6 single : bool, False Optional. Plots single session summaries with breakdown of single blocks int_only : bool, False Optional. Plots only interval trials in zoomed schedule plot corr_only : bool, False Optional. Plots seperate summary plot with correct only trials scd : dict, None dict of Sub : color Used to assign color to plot title. TODO ---- Split timeline and plotting into separate functions. Returns ------- None """ s_list = ['4', '5a', '5b', '6', '7'] in_dir = os.path.join(start_dir, "hdf5") out_dir = os.path.join(start_dir, "Plots", "Current") bvmpc.bv_utils.make_dir_if_not_exists(out_dir) if summary and not corr_only: # extracts hdf5 session based on specification max_plot = 4 # Set max plots per figure s_grp = extract_sessions(in_dir, sub_list, s_list, d_list) if s_grp == []: return print("***No Files Extracted***") idx = 0 if len(s_grp) > max_plot: j = 0 s_grp_split = [] s_grp_idx = np.arange(len(s_grp)) for i in s_grp_idx[max_plot - 1::max_plot]: s_grp_split.append(s_grp[j:i + 1]) j = i + 1 mv = len(s_grp) % max_plot if mv != 0: s_grp_split.append(s_grp[-mv:]) for s_grp in s_grp_split: idx += 1 sum_plot(s_grp, idx, out_dir) else: sum_plot(s_grp, idx, out_dir) if summary and corr_only: # plots corr_only plots max_plot = 4 # Set max plots per figure s_grp = extract_sessions(in_dir, sub_list, s_list, d_list) if s_grp == []: return print("***No Files Extracted***") idx = 0 if len(s_grp) > max_plot: j = 0 s_grp_split = [] s_grp_idx = np.arange(len(s_grp)) for i in s_grp_idx[max_plot - 1::max_plot]: s_grp_split.append(s_grp[j:i + 1]) j = i + 1 mv = len(s_grp) % max_plot if mv != 0: s_grp_split.append(s_grp[-mv:]) for s_grp in s_grp_split: idx += 1 sum_plot(s_grp, idx, out_dir, corr_only=True) else: sum_plot(s_grp, idx, out_dir, corr_only=True) if single and summary: # Single Subject Plots idx = 0 for sub in sub_list: s_grp = extract_sessions(in_dir, sub, s_list, d_list) if s_grp == []: return print("***No Files Extracted***") s_passed = [] d_passed = [] for s in s_grp: stage = s.get_metadata('name')[:2].replace('_', '') s_passed.append(stage) date = s.get_metadata("start_date").replace("/", "-") d_passed.append(date[:5]) subject = s.get_metadata('subject') if '7' in s_passed: gf = bv_plot.GridFig(len(s_grp), 4) fig = gf.get_fig() if len(s_grp) == 1: fig.tight_layout(rect=[0, 0.03, 0.8, 0.95]) for i, s in enumerate(s_grp): ax1 = gf.get_next() bv_an.cumplot(s, out_dir, ax1, int_only, zoom=False, zoom_sch=False) ax2 = gf.get_next() bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True, plot_error=False, plot_all=True) ax3 = gf.get_next() bv_an.cumplot(s, out_dir, ax3, int_only, zoom=False, zoom_sch=True, plot_error=False, plot_all=False) ax4 = gf.get_next() bv_an.cumplot(s, out_dir, ax4, int_only, zoom=False, zoom_sch=True, plot_error=True, plot_all=False) plt.subplots_adjust(top=0.85) if scd == None: color = "k" else: color = bvmpc.bv_utils.mycolors(sub, scd) fig.suptitle(('Subject ' + subject + ' Performance'), color=color, fontsize=30) # # Seperate plots w line # ax1.hlines(1.13, -0, 4.9, clip_on=False, # transform=ax1.transAxes, linewidth=0.7) s_print = np.array_str(np.unique(np.array(s_passed))) d_print = np.array_str(np.unique(np.array(d_passed))) out_name = "Sum_" + subject + "_" + d_print + "_" + s_print + ".png" bv_plot.savefig(fig, os.path.join(out_dir, out_name)) else: sum_plot(s_grp, idx, out_dir, single=single) def struc_timeline(sub_list, in_dir)-
Structure sessions into a pandas dataframe based on trials.
Returns
grp_timeline_df, time_df_sub- grp_timeline_df : array pandas dataframes across time based on session grp_timeline_df_sub : list denotes the subject corresponding to each df
Expand source code
def struc_timeline(sub_list, in_dir): """ Structure sessions into a pandas dataframe based on trials. Returns ------- grp_timeline_df, time_df_sub grp_timeline_df : array pandas dataframes across time based on session grp_timeline_df_sub : list denotes the subject corresponding to each df """ # Initialize group variables grp_timeline_df = [] grp_timeline_df_sub = [] for sub in sub_list: s_grp = extract_sessions(in_dir, sub) # Initialize column arrays d_list, t_list, sub_list, s_idx_list, r_list, s_list = [], [], [], [], [], [] err_FR_list, err_FI_list = [], [] rw_FR_list, rw_FI_list, dr_list = [], [], [] ratio_list, interval_list = [], [] sch_list, sch_rw_list, sch_err_list, sch_dr_list = [], [], [], [] for i, s in enumerate(s_grp): subject = s.get_metadata('subject') date = s.get_metadata("start_date").replace("/", "-")[:5] session_type = s.get_metadata('name') time = s.get_metadata('start_time') stage = session_type[:2].replace( '_', '') # Obtain stage number w/o _ timestamps = s.get_arrays() pell_ts = timestamps["Reward"] dpell_bool = np.diff(pell_ts) < 0.5 dpell_idx = np.nonzero(dpell_bool)[0] reward_times = s.get_rw_ts() # Initialize variables used per session ratio, interval, sch, sch_err, sch_rw, sch_dr = [], [], [], [], [], [] err_FI, err_FR, rw_FI, rw_FR = [], [], [], [] ratio = s.get_ratio() interval = s.get_interval() # Stage specific variables if stage == '5a': s_name = 'R' + str(ratio) ratio = s_name rw_FR = len(reward_times) elif stage == '5b': s_name = 'I' + str(interval) interval = s_name rw_FI = len(reward_times) else: s_name = stage.replace('_', '').replace('2', 'M').replace( '3', 'Lh').replace('4', 'Lt').replace( '6', 'B1').replace('7', 'B2') if 'B' in s_name: rw_FI, rw_FR = 0, 0 ratio = 'R' + str(ratio) interval = 'I' + str(interval) norm_r_ts, _, norm_err_ts, norm_dr_ts, _ = s.split_sess( all_levers=True) sch_type = s.get_arrays('Trial Type') # Error related variables if s_name == 'B2': err_FI, err_FR = 0, 0 for i, err in enumerate(norm_err_ts): if sch_type[i] == 1: err_FR = + len(err) elif sch_type[i] == 0: err_FI += len(err) sch_err.append(len(err)) else: err_FR = [] err_FI = [] # Reward related variables for i, (rw, dr) in enumerate(zip(norm_r_ts, norm_dr_ts)): if sch_type[i] == 1: rw_FR += len(rw) sch.append('FR') sch_dr.append([]) elif sch_type[i] == 0: rw_FI += len(rw) sch.append('FI') sch_dr.append(len(dr)) sch_rw.append(len(rw)) # Update list arrays with new session d_list.append(date) t_list.append(time) s_idx_list.append('S' + stage[0]) s_list.append(s_name) r_list.append(len(pell_ts)) dr_list.append(len(dpell_idx)) interval_list.append(interval) ratio_list.append(ratio) sch_list.append(sch) sch_rw_list.append(sch_rw) sch_err_list.append(sch_err) sch_dr_list.append(sch_dr) rw_FI_list.append(rw_FI) rw_FR_list.append(rw_FR) err_FI_list.append(err_FI) err_FR_list.append(err_FR) sub_list = np.full(len(d_list), sub, dtype=int) timeline_dict = { 'Subject': sub_list, 'Date': d_list, 'Start Time': t_list, 'Stage Idx': s_idx_list, # eg. S2, S5, S7 ... 'Stage': s_list, # eg. M, Lt, R8, I30, B1 'Total Rewards': r_list, 'Double Rewards': dr_list, 'Interval': interval_list, 'Ratio': ratio_list, 'Schedule Blocks': sch_list, 'Schedule Rw': sch_rw_list, 'Schedule Err': sch_err_list, 'Schedule DRw': sch_dr_list, 'FI Corr': rw_FI_list, 'FR Corr': rw_FR_list, 'FI Err': err_FI_list, 'FR Err': err_FR_list } timeline_df = pd.DataFrame(timeline_dict) grp_timeline_df.append(timeline_df) grp_timeline_df_sub.append(subject) return grp_timeline_df, grp_timeline_df_sub def sum_plot(s_grp, idx, out_dir, zoom=True, single=False, int_only=False, corr_only=False)-
Perform summary plots of a day.
Note that if zoom is True, this function then divides session into blocks and plots each block as individual lines.
Expand source code
def sum_plot(s_grp, idx, out_dir, zoom=True, single=False, int_only=False, corr_only=False): """ Perform summary plots of a day. Note that if zoom is True, this function then divides session into blocks and plots each block as individual lines. """ # Plots summary of day if zoom: print('zoomed') if len(s_grp) > 2: cols = 2 * math.ceil(len(s_grp) / 2) rows = 2 else: rows = len(s_grp) cols = 2 else: if len(s_grp) > 4: rows = math.ceil(len(s_grp) / 4) cols = 4 else: cols = len(s_grp) rows = 1 gf = bv_plot.GridFig(rows, cols) fig = gf.get_fig() s_passed = [] d_passed = [] for _, s in enumerate(s_grp): subject = s.get_metadata('subject') stage = s.get_metadata('name')[:2].replace('_', '') date = s.get_metadata("start_date").replace("/", "-") s_passed.append(stage) d_passed.append(date[:5]) if zoom: ax1 = gf.get_next_snake() else: ax1 = gf.get_next() if corr_only and stage == '7': bv_an.cumplot(s, out_dir, ax1, int_only, zoom=False, zoom_sch=False, plot_all=False) else: bv_an.cumplot(s, out_dir, ax1, int_only, zoom=False, zoom_sch=False) if stage == '2' or stage == '3' or stage == '4': IRT = True elif stage == '5a' or stage == '5b': IRT = True # Change to False for zoomed plot instead of IRT else: IRT = False if IRT: ax2 = gf.get_next_snake() bv_an.IRT(s, out_dir, ax2) elif zoom: ax2 = gf.get_next_snake() if corr_only and stage == '7': bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True, plot_error=False, plot_all=False) else: bv_an.cumplot(s, out_dir, ax2, int_only, zoom=False, zoom_sch=True, plot_error=False, plot_all=True) plt.subplots_adjust(top=0.85) d_print = np.array_str(np.unique(np.array(d_passed))) d_title = np.array2string(np.unique(np.array(d_passed))) s_print = np.array_str(np.unique(np.array(s_passed))) if single: fig.suptitle(('Subject ' + subject + ' Performance'), fontsize=30) out_name = "Sum_" + subject + "_" + d_print + "_" + s_print + ".png" elif corr_only and stage == '7': if idx == 0: fig.suptitle(('Summary across animals ' + d_title + '_Correct Only'), fontsize=30) out_name = "Sum_" + d_print + "_" + s_print + "_Corr.png" else: fig.suptitle(('Summary across animals ' + d_title + '_Correct Only' + " p" + str(idx)), fontsize=30) out_name = "Sum_" + d_print + "_" + \ s_print + "_" + str(idx) + "_Corr.png" else: if idx == 0: fig.suptitle(('Summary across animals ' + d_title), fontsize=30) out_name = "Sum_" + d_print + "_" + s_print + ".png" else: fig.suptitle(('Summary across animals ' + d_title + " p" + str(idx)), fontsize=30) out_name = "Sum_" + d_print + "_" + \ s_print + "_" + str(idx) + ".png" print("Saved figure to {}".format( os.path.join(out_dir, out_name))) bv_plot.savefig(fig, os.path.join(out_dir, out_name)) plt.close() def timeline_plot(sub_list, in_dir, out_dir, single_plot=False, det_err=False, det_corr=False, recent=False, show_date=True, details=False, sub_colors_dict=None)-
Plots total rewards from beginning of first session
Not all parameters are currently described.
Parameters
det_err:bool- plots error lever presses
det_cor:bool- plots correct lever presses
recent:bool- plots recent (determined in code - static) datapoints only
show_date:bool- plots date as x axis instead of session type
Returns
None
Expand source code
def timeline_plot( sub_list, in_dir, out_dir, single_plot=False, det_err=False, det_corr=False, recent=False, show_date=True, details=False, sub_colors_dict=None): """ Plots total rewards from beginning of first session Not all parameters are currently described. Parameters ---------- det_err : bool plots error lever presses det_cor : bool plots correct lever presses recent : bool plots recent (determined in code - static) datapoints only show_date : bool plots date as x axis instead of session type Returns ------- None """ # Plot size rows, cols = [len(sub_list), 4] size_multiplier = 5 fig = plt.figure( figsize=(cols * size_multiplier, rows * size_multiplier), tight_layout=False) gs = gridspec.GridSpec(rows, cols, wspace=0.4, hspace=0.5) for c, sub in enumerate(sub_list): # Plot total pellets across sessions s_grp = extract_sessions(in_dir, [sub]) s_list, r_list, type_list, d_list, box_list, time_list = [], [], [], [], [], [] err_FR_list, err_FI_list = [], [] rw_FR_list, rw_FI_list, rw_double_list = [], [], [] changes, stage_change, dpell_change = [], [], [] change_idx = [] prev_ratio, prev_interval, c_ratio, c_interval = [], [], [], [] dpell_old = [] prev_name = '2' if recent: number_sessions_ago = -31 # change value to set number of sessions ago s_grp = s_grp[number_sessions_ago:] else: pass for i, s in enumerate(s_grp): ratio = s.get_ratio() interval = s.get_interval() s_type = s.get_metadata('name')[:2] timestamps = s.get_arrays() date = s.get_metadata('start_date') # Display mm/dd/yy date = s.get_metadata('start_date')[:-3] # Display mm/dd only # date = s.get_metadata('start_date').split("/")[1] # Display dd only subject = s.get_metadata('subject') pell_ts = timestamps["Reward"] pell_double = np.nonzero(np.diff(pell_ts) < 0.5)[0] reward_times = s.get_rw_ts() box = s.get_metadata('box') # time format - "%H:%M:%S" exptime = s.get_metadata('start_time')[:2] d_list.append(date) box_list.append(box) time_list.append(exptime) if len(pell_double): dpell_change = 1 if s_type == '5a': s_name = 'R' + str(ratio) c_ratio = s_name elif s_type == '5b': s_name = 'I' + str(interval) c_interval = s_name else: s_name = s_type.replace('_', '').replace('2', 'M').replace( '3', 'Lh').replace('4', 'Lt').replace( '6', 'B1').replace('7', 'B2') if 'B' in s_name: c_ratio = 'R' + str(ratio) c_interval = 'I' + str(interval) if not prev_name[0] == s_type[0]: stage_change.append(1) changes.append(0) change_idx.append(0) else: stage_change.append(0) if not c_ratio == prev_ratio and not c_interval == prev_interval: changes.append([c_ratio, c_interval]) change_idx.append(1) elif not c_ratio == prev_ratio: changes.append(c_ratio) change_idx.append(1) elif not c_interval == prev_interval: changes.append(c_interval) change_idx.append(1) elif not dpell_change == dpell_old: changes.append("DPell") change_idx.append(1) else: changes.append(0) change_idx.append(0) # Calculates total reward (y axis variable) r_list.append(len(pell_ts)) # Calculates FR & FI rewards and errors (alternative y axis variables) err_FI = 0 err_FR = 0 rw_FR = 0 rw_FI = 0 rw_double = 0 err_plotted = 0 corr_plotted = 0 if s_type == '7_' or s_type == '6_': norm_r_ts, _, norm_err_ts, norm_dr_ts, _ = s.split_sess( all_levers=True) sch_type = s.get_arrays('Trial Type') if s_type == '7_': for i, _ in enumerate(norm_err_ts): if sch_type[i] == 1: err_FR = err_FR + len(norm_err_ts[i]) elif sch_type[i] == 0: err_FI = err_FI + len(norm_err_ts[i]) else: err_FR = None err_FI = None for i, _ in enumerate(norm_r_ts): rw_double += len(norm_dr_ts[i]) if sch_type[i] == 1: rw_FR = rw_FR + len(norm_r_ts[i]) elif sch_type[i] == 0: rw_FI = rw_FI + len(norm_r_ts[i]) elif s_type == '5a': err_FI = None err_FR = None rw_FR = len(reward_times) rw_FI = None rw_double = None elif s_type == '5b': err_FI = None err_FR = None rw_FR = None rw_FI = len(reward_times) rw_double = len(pell_double) else: err_FI = None err_FR = None rw_FR = None rw_FI = None rw_double = None # Updates list arrays with new session rw_FR_list.append(rw_FR) rw_FI_list.append(rw_FI) err_FR_list.append(err_FR) err_FI_list.append(err_FI) rw_double_list.append(rw_double) s_list.append(s_name) type_list.append('S-' + s_type[0]) # Updates current iteration variables for next loop dpell_old = dpell_change prev_ratio = c_ratio prev_interval = c_interval prev_name = s_type if single_plot: rows, cols = [1, 4] size_multiplier = 5 fig = plt.figure( figsize=(cols * size_multiplier, rows * size_multiplier), tight_layout=False) gs = gridspec.GridSpec(rows, cols, wspace=0.2, hspace=0.3) ax = fig.add_subplot(gs[0, :]) out_name = "Timeline_" + subject if recent: out_name += "_recent" if details: out_name += "_details" else: ax = fig.add_subplot(gs[int(c), :]) s_idx = np.arange(0, len(s_list)) if details: # Plots average sessions variables i.e. FR_corr, FI_corr, FR_err, FI_err, double_rw ratio_c = plt.cm.get_cmap('Wistia') interval_c = plt.cm.get_cmap('winter') # Change value to increase height of annotation # note_height = 0 # y_axis = np.zeros((1, len(s_idx)))[0] + note_height y_axis = [] # Sets line on which annotations appear for i, l in enumerate(rw_FR_list): if l is None: y_axis.append(0) # Hides non-stage 7 annotations else: y_axis.append(l) plots = [] labels = [] # Dict controls lines to be plot. Set keys to 1 in plot_dict to include line in plot if det_err: plot_styles = { "FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 0], "FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 1], "FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 0], "FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 1], "FI_DoubleR": [rw_double_list, '*-', 'hotpink', 0]} err_plotted = 1 elif det_corr: plot_styles = { "FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 1], "FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 0], "FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 1], "FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 0], "FI_DoubleR": [rw_double_list, '*-', 'hotpink', 1]} corr_plotted = 1 else: plot_styles = { "FR_Corr": [rw_FR_list, '*-', ratio_c(3 * 45), 1], "FR_Err": [err_FR_list, 'x-', ratio_c(10 * 45), 1], "FI_Corr": [rw_FI_list, '*-', interval_c(2 * 45), 1], "FI_Err": [err_FI_list, 'x-', interval_c(4 * 45), 1], "FI_DoubleR": [rw_double_list, '*-', 'hotpink', 1]} err_plotted = 1 corr_plotted = 1 plot_dict = {"FR_Corr": 1, "FR_Err": 1, "FI_Corr": 1, "FI_Err": 1, "FI_DoubleR": 1} ax2 = ax.twinx() for k, val in plot_dict.items(): if val: s = plot_styles[k] if k[-3:] == "Err": ax_used = ax2 else: ax_used = ax h, = ax_used.plot(s_idx, s[0], s[1], label=k, linewidth='2', markersize=10, color=s[2], alpha=s[3]) plots.append(h) labels.append(h.get_label()) ax.set_title('\nSubject {} Timeline_Details'.format( subject), y=1.05, fontsize=25, color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict)) else: # Only plots total rewards y_axis = r_list h1, = plt.plot( s_idx, y_axis, label='Animal' + subject, linewidth='4', color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict)) ax.set_title( '\nSubject {} Timeline'.format(subject), y=1.05, fontsize=25, color=bvmpc.bv_utils.mycolors(subject, sub_colors_dict)) # # Plot experiment time w rewards # ax2 = ax.twinx() # y_axis_2 = time_list # ax2.set_ylim([0, 24]) # ax2.plot(s_idx, y_axis_2, label='Animal'+subject, linewidth='4', # color=mycolors(subject)) # Annotated changes in protocol annotate_fontsize = 12 h2 = None h3 = None for i, c in enumerate(changes): if stage_change[i] == 1: h2 = ax.annotate(type_list[i], xy=(s_idx[i], y_axis[i]), ha='center', xytext=(0, (.2 * max(y_axis))), textcoords='offset points', arrowprops=dict(facecolor='blue', shrink=0.05), size=annotate_fontsize) elif change_idx[i] == 1: h3 = ax.annotate(str(c), xy=(s_idx[i], y_axis[i]), ha='center', xytext=(0, (.2 * max(y_axis))), textcoords='offset points', arrowprops=dict(facecolor='Red', shrink=0.05), size=annotate_fontsize) ax.set_xlim(0, len(s_idx)) if show_date: # plots x-axis tics as dates plt.xticks(s_idx, d_list, fontsize=10) # plt.xticks(s_idx, box_list, fontsize=10) # Plots x-tics as box ax.set_xlabel('Sessions (Dates)', fontsize=20) else: # plots x-axis ticks as stages plt.xticks(s_idx, s_list, fontsize=13) ax.set_xlabel('Sessions (Type)', fontsize=20) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.tick_params(axis='y', labelsize=15) if details: if 'S-6' in type_list: ax.axhline(45, xmax=(type_list.index('S-6') / len(type_list)), color=interval_c(2 * 45), linestyle='-.', linewidth='.5') ax.axhline(30, xmin=(type_list.index('S-6') / len(type_list)), color=interval_c(2 * 45), linestyle='-.', linewidth='.5') ax.text(type_list.index('S-6'), 31, ' Max FI', fontsize=8, color=interval_c(2 * 45), ha='left', va='bottom') ax.text(s_idx[0], 46, ' Max FI', fontsize=8, color=interval_c(2 * 45), ha='left', va='bottom') else: ax.axhline(30, color=interval_c(2 * 45), linestyle='-.', linewidth='.5') ax.text(s_idx[0], 31, ' Max FI', fontsize=8, color=interval_c(2 * 45), ha='left', va='bottom') loc = 'top left' ax.set_ylabel('Correct Trials', fontsize=20) # set second y-axis labels ax2.tick_params(axis='y', labelsize=15) ax2.set_ylabel('Error Presses', fontsize=20) else: # plt.axhline(45, color='g', linestyle='-.', linewidth='.5') plt.axhline(60, color='r', linestyle='-.', linewidth='.5') # Marks max reward ax.set_ylabel('Total Rewards', fontsize=20) plots = [h1] labels = [h1.get_label()] loc = 'lower right' if h2 is not None and h3 is not None: plots.extend([h2.arrow_patch, h3.arrow_patch]) labels.extend(['Stage Changes', 'Protocol Mod.']) elif h2 is not None: plots.append(h2.arrow_patch) labels.append('Stage Changes') elif h3 is not None: plots.append(h3.arrow_patch) labels.append('Protocol Mod.') plt.legend(plots, labels, loc=loc, ncol=2) if single_plot: out_name += ".png" print("Saved figure to {}".format( os.path.join(out_dir, out_name))) bv_plot.savefig(fig, os.path.join(out_dir, out_name)) plt.close() if not single_plot: out_name = "Timeline_Sum_" + "-".join(sub_list) if recent: out_name += "_recent" if details: out_name += "_details" if corr_plotted == 1 and err_plotted == 1: pass elif corr_plotted == 1: out_name += "_corr" elif err_plotted == 1: out_name += "_err" out_name += ".png" print("Saved figure to {}".format( os.path.join(out_dir, out_name))) bv_plot.savefig(fig, os.path.join(out_dir, out_name)) plt.close()