From de15dd9e92ae417c6c5dce4f297c686277616670 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Mon, 12 Dec 2022 13:12:18 -0500 Subject: [PATCH 01/19] updates --- .../LFP_Analysis_Workflow.docx | Bin 31736 -> 31474 bytes .../~$P_Analysis_Workflow.docx | Bin 162 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx diff --git a/LFPs/Analysis_code_JM/LFP_Analysis_Workflow.docx b/LFPs/Analysis_code_JM/LFP_Analysis_Workflow.docx index 6906db72437222e69ca2e2489bccdbdcf2d0768a..dfc35df67c1ba376f0315215a52116280b5aa62c 100644 GIT binary patch delta 22063 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 delta 22315 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 diff --git a/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx b/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx deleted file mode 100644 index fbbe2f8f35c349168c7012f7c69f7190a67ef4c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmWgkO-#=#EiTT_(^2qB&CAP7OD$p`2!t7Y84?-N8S)rP8H#~0AIQ>SP+;(4NCmR; z7%~~sfGmVT>vAAQUOS%ub?e_7jP9#u?nzK$VDOrGJB^3uCL_$kWyPPgf7HWxK$@|E F0RTk`A4vcJ From 9274634f272f80357e9699873e39595f396aa0ca Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Thu, 15 Dec 2022 14:07:59 -0500 Subject: [PATCH 02/19] testing alternative bad channel information --- .../script_generate_trials_structure_bad_data.m | 5 +---- .../script_generate_trials_structure_bad_data_plots.m | 2 +- LFPs/Analysis_code_JM/utils/identify_bad_data.m | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m index 72e1f049..9e455a00 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m @@ -72,10 +72,7 @@ continue; end -% if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - + % if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... % || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes % continue; diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m index 14a378ba..7940ff8d 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m @@ -298,7 +298,7 @@ LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) for i_row = 1 : num_rows - y_lim = [-1500, 1500]; + y_lim = [-2500, 2500]; plot_col = ceil(i_row / LFPs_per_shank); plot_row = i_row - LFPs_per_shank * (plot_col-1); plot_num = (plot_row-1) * 8 + plot_col; diff --git a/LFPs/Analysis_code_JM/utils/identify_bad_data.m b/LFPs/Analysis_code_JM/utils/identify_bad_data.m index 6fd48a61..a5bc88f1 100644 --- a/LFPs/Analysis_code_JM/utils/identify_bad_data.m +++ b/LFPs/Analysis_code_JM/utils/identify_bad_data.m @@ -27,7 +27,7 @@ lfp = lfp_data.lfp; -outlier_thresh = 1500; % in mV +outlier_thresh = 2000; % in mV t_win = [-2.5 5]; % eventFieldnames = {'cueOn'}; From 4cdd6b6f0c58ef1f7f238dd7888fc6c2f39ffffe Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Mon, 19 Dec 2022 08:42:24 -0500 Subject: [PATCH 03/19] create original trials structure with folder --- ...ipt_generate_trials_structure_bad_data.asv | 282 ++++++++++++++++++ ...cript_generate_trials_structure_bad_data.m | 7 +- ...generate_trials_structure_bad_data_plots.m | 19 +- .../create_trials_structure_original_folder.m | 10 + .../utils/generate_trials_structure.asv | 132 ++++++++ .../utils/generate_trials_structure.m | 132 ++++++++ .../utils/load_trials_structure.m | 45 ++- .../script_extract_power_spectra.m | 4 +- 8 files changed, 596 insertions(+), 35 deletions(-) create mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv create mode 100644 LFPs/Analysis_code_JM/utils/create_trials_structure_original_folder.m create mode 100644 LFPs/Analysis_code_JM/utils/generate_trials_structure.asv create mode 100644 LFPs/Analysis_code_JM/utils/generate_trials_structure.m diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv new file mode 100644 index 00000000..6ac8b316 --- /dev/null +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv @@ -0,0 +1,282 @@ +% script to write field potentials around each trial + +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +%% +fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc +num_trials_to_plot = 5; + +% start with an LFP file +% get the trial structure for that session +% run this analysis + +trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) + +switch lower(trialType) + case 'allgo' + eventFieldnames = {'centerIn'}; + case 'correctgo' + eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; +end + + % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', + % 'foodretrievel'}; This is the full eventlist for a correctGo trial. + % Choose one for generating event_triggered_lfps. +num_events = length(eventFieldnames); +t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct + + +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +naming_convention; % for labeling graphs + +% choiceTask difficulty levels +choiceRTdifficulty = cell(1, 10); +choiceRTdifficulty{1} = 'poke any'; +choiceRTdifficulty{2} = 'very easy'; +choiceRTdifficulty{3} = 'easy'; +choiceRTdifficulty{4} = 'standard'; +choiceRTdifficulty{5} = 'advanced'; +choiceRTdifficulty{6} = 'choice VE'; +choiceRTdifficulty{7} = 'choice easy'; +choiceRTdifficulty{8} = 'choice standard'; +choiceRTdifficulty{9} = 'choice advanced'; +choiceRTdifficulty{10} = 'testing'; + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end + + probe_channel_info = load_channel_information(fname, sheetname); + [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; + if ~exist(trials_structure_plots, 'dir') + mkdir(trials_structure_plots); + end + + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') + mkdir(processed_graphFolder_LFP_eventFieldname); + end + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); + + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + +% if exist(trials_full_name, 'file') +% continue +% end + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + +% % at this point, event_triggered_lfps_ordered is an m x n x p array where +% % m is the number of events (i.e., all the cueon OR nosein OR other... +% % events) in a single session; n is the number of channels in that session +% % (generally 64), and p is the number of time samples extracted around each +% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change + + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + +% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. +% % num_channels = size(event_triggered_lfps,2); +% num_trials = size(event_triggered_lfps, 1); +% + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + + end + end +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m index 9e455a00..6ac8b316 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m @@ -34,7 +34,7 @@ ASSY156 = ["R0411", "R0419"]; ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; % Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? @@ -224,7 +224,7 @@ % Order the lfps here [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) %find the column header that matches session_name (session_name and %the column headers should match for each session to pull in the @@ -237,11 +237,10 @@ % write code here to get event_triggered_lfps_ordered % for each separate event -% % create a filename to save the trials_structure + % create a filename to save the trials_structure trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - % if exist(trials_full_name, 'file') % continue % end diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m index 7940ff8d..462bb323 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m @@ -4,6 +4,8 @@ intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); +valid_trials_folder = find_trials_struct_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data + %% fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc @@ -144,12 +146,14 @@ % mkdir(trials_structure); % end + % Graphs in this folder are WITH calculating an outlier threshold. trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; if ~exist(trials_structure_plots, 'dir') mkdir(trials_structure_plots); end - processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + % Graphs in this folder are grandfathered in BEFORE I calculated a specific outlier threshold and just using by eye on Neuroscope. + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') mkdir(processed_graphFolder_LFP_eventFieldname); end @@ -161,7 +165,9 @@ sprintf('no log file found for %s', session_folder) end - logData = readLogData(session_log); %gathersing logData information + + % Start of generation of trials structure + logData = readLogData(session_log); %gathering logData information % calculate nexData, need digital input and analog input files digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); @@ -203,7 +209,9 @@ sprintf('could not generate trials structure for %s', session_folder) continue end - + % End of calculating trials structure (original without threshold info) + + % extract Trial Type (e.g. correctGo) % Set trialType at beginning of file [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here @@ -245,10 +253,6 @@ trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); -% if exist(trials_full_name, 'file') -% continue -% end - % Cath for troubleshooting the data to NOT run through all of the folders and % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. % It will simply generate one trial per session. @@ -386,4 +390,5 @@ end end end + end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/create_trials_structure_original_folder.m b/LFPs/Analysis_code_JM/utils/create_trials_structure_original_folder.m new file mode 100644 index 00000000..fe8b9aae --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/create_trials_structure_original_folder.m @@ -0,0 +1,10 @@ +function session_trials_folder_original = create_trials_structure_original_folder(rd_metadata, parent_directory) + +trials_folder= strcat(rd_metadata.ratID, '-LFP-trials-structures-original'); +session_trials_folder_original = fullfile(parent_directory, rd_metadata.ratID, trials_folder, rd_metadata.session_name); + +if ~isfolder(session_trials_folder_original) + + mkdir(session_trials_folder_original) + +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv b/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv new file mode 100644 index 00000000..fe8a8ec6 --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv @@ -0,0 +1,132 @@ +% script to generate trials structures +% This file needs to be tested 12/18/2022 + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +%% +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder_original = create_trials_structure_original_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + +% if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly +% probe_type = 'NN8x8'; +% elseif contains(ratID, ASSY156) +% probe_type = 'ASSY156'; +% elseif contains(ratID, ASSY236) +% probe_type = 'ASSY236'; +% end + + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + trials_structure_original = [parentFolder(1:end-9) 'LFP-trials-structures-original']; + if ~exist(trials_structure_original, 'dir') + mkdir(trials_structure_original); + end + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + trials_fname_to_save = char(strcat(session_name, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_original_full_name = fullfile(session_trials_folder_original, trials_fname_to_save); + save(trials_original_full_name, 'trials'); + end +end diff --git a/LFPs/Analysis_code_JM/utils/generate_trials_structure.m b/LFPs/Analysis_code_JM/utils/generate_trials_structure.m new file mode 100644 index 00000000..7ab96da5 --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/generate_trials_structure.m @@ -0,0 +1,132 @@ +% script to generate trials structures +% This file needs to be tested 12/18/2022 + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +%% +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder_original = create_trials_structure_original_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + +% if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly +% probe_type = 'NN8x8'; +% elseif contains(ratID, ASSY156) +% probe_type = 'ASSY156'; +% elseif contains(ratID, ASSY236) +% probe_type = 'ASSY236'; +% end + + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + trials_structure_original = [parentFolder(1:end-9) 'LFP-trials-structures-original']; + if ~exist(trials_structure_original, 'dir') + mkdir(trials_structure_original); + end + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + trials_fname_to_save = char(strcat(session_name, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_original_full_name = fullfile(session_trials_folder_original, trials_fname_to_save); + save(trials_original_full_name, 'trials'); + end +end diff --git a/LFPs/Analysis_code_JM/utils/load_trials_structure.m b/LFPs/Analysis_code_JM/utils/load_trials_structure.m index 97e6d1d9..059ecb7b 100644 --- a/LFPs/Analysis_code_JM/utils/load_trials_structure.m +++ b/LFPs/Analysis_code_JM/utils/load_trials_structure.m @@ -1,31 +1,30 @@ % script to load in trials structure -intan_choicetask_parent = 'X:\Neuro-Leventhal\data\ChoiceTask'; +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -valid_trials_folder = find_trials_struct_folders(intan_choicetask_parent); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data +valid_trials_folder = find_trials_struct_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc %% -for i_ratfolder = 1 : length(valid_trials_folder) + for i_ratfolder = 1 : length(valid_trials_folder) + + session_trials_struct_folders = valid_trials_folder(i_ratfolder).trials_folders; + + for i_trials_folder = 1 : length(session_trials_struct_folders) + % extract the ratID and session name from the LFP file + session_path = session_trials_struct_folders{i_trials_folder}; + pd_trials_data = parse_trials_struct_folder(session_path); + ratID = pd_trials_data.ratID; + session_name = pd_trials_data.session_name; - session_trials_struct_folders = valid_trials_folder(i_ratfolder).trials_folders; - - for i_sessionfolder = 1 : length(session_trials_struct_folders) - % extract the ratID and session name from the LFP file - session_path = session_trials_struct_folders{i_sessionfolder}; - pd_trials_data = parse_trials_struct_folder(session_path); - ratID = pd_trials_data.ratID; - session_name = pd_trials_data.session_name; - - % Load trials structure - for i_trialsfolder = 1:length(session_trials_struct_folders) - session_trials_structure = fullfile(intan_choicetask_parent, ratID, [ratID '-LFP-trials-structures'], session_name); - session_trials = find_trials_mat(session_trials_structure); - trials_structure_file = dir(fullfile(session_trials)); - trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); - trials_structure = load(trials_structure_fname); - trials_validchannels_marked = trials_structure.trials_validchannels_marked; + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures'], session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials_validchannels_marked = trials_structure.trials_validchannels_marked; + end + end end - - end -end diff --git a/silicon_probe_LFP_analysis/script_extract_power_spectra.m b/silicon_probe_LFP_analysis/script_extract_power_spectra.m index 81af1faa..8b91f3b1 100644 --- a/silicon_probe_LFP_analysis/script_extract_power_spectra.m +++ b/silicon_probe_LFP_analysis/script_extract_power_spectra.m @@ -16,7 +16,9 @@ ASSY156 = ["R0411", "R0419"]; ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; -sessions_to_ignore = {'R0378_20210507a', 'R0425_20220728a', 'R0427_20220920a'}; % R0425_20220728a debugging because the intan side was left on for 15 hours; +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; % R0427_20220920a does not have an 'info.rhd' file %% From 15da264848c58aafd95c198aff4bf6e7ddc56e6e Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Tue, 20 Dec 2022 09:58:28 -0500 Subject: [PATCH 04/19] generating trials structure utils --- ...ipt_generate_trials_structure_bad_data.asv | 282 ------------------ .../utils/find_trials_struct_folders.m | 6 +- .../find_trials_struct_original_folders.m | 79 +++++ .../utils/generate_trials_structure.asv | 132 -------- .../utils/generate_trials_structure.m | 10 +- .../utils/gude-2022-12-20.log | 6 + .../utils/load_trials_structure.m | 8 +- .../load_trials_structure_identify_bad_data.m | 30 ++ 8 files changed, 130 insertions(+), 423 deletions(-) delete mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv create mode 100644 LFPs/Analysis_code_JM/utils/find_trials_struct_original_folders.m delete mode 100644 LFPs/Analysis_code_JM/utils/generate_trials_structure.asv create mode 100644 LFPs/Analysis_code_JM/utils/gude-2022-12-20.log create mode 100644 LFPs/Analysis_code_JM/utils/load_trials_structure_identify_bad_data.m diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv deleted file mode 100644 index 6ac8b316..00000000 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv +++ /dev/null @@ -1,282 +0,0 @@ -% script to write field potentials around each trial - -% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; - -intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); - -%% -fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc -num_trials_to_plot = 5; - -% start with an LFP file -% get the trial structure for that session -% run this analysis - -trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) - -switch lower(trialType) - case 'allgo' - eventFieldnames = {'centerIn'}; - case 'correctgo' - eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; -end - - % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', - % 'foodretrievel'}; This is the full eventlist for a correctGo trial. - % Choose one for generating event_triggered_lfps. -num_events = length(eventFieldnames); -t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct - - -% lists for ratID probe_type -NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type -ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; - -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; -sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; -sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; -% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? - -naming_convention; % for labeling graphs - -% choiceTask difficulty levels -choiceRTdifficulty = cell(1, 10); -choiceRTdifficulty{1} = 'poke any'; -choiceRTdifficulty{2} = 'very easy'; -choiceRTdifficulty{3} = 'easy'; -choiceRTdifficulty{4} = 'standard'; -choiceRTdifficulty{5} = 'advanced'; -choiceRTdifficulty{6} = 'choice VE'; -choiceRTdifficulty{7} = 'choice easy'; -choiceRTdifficulty{8} = 'choice standard'; -choiceRTdifficulty{9} = 'choice advanced'; -choiceRTdifficulty{10} = 'testing'; - -%% -for i_rat = 1 : length(rats_with_intan_sessions) - - intan_folders = rats_with_intan_sessions(i_rat).intan_folders; - - for i_sessionfolder = 1 : length(intan_folders) - % extract the ratID and session name from the LFP file - session_path = intan_folders{i_sessionfolder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); - session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); - ratID = rd_metadata.ratID; - intan_session_name = rd_metadata.session_name; - session_name = rd_metadata.session_name; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end - - -% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... -% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - - -% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') -% continue; -% end - - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); - end - - probe_channel_info = load_channel_information(fname, sheetname); - [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); - -% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; -% if ~exist(trials_structure, 'dir') -% mkdir(trials_structure); -% end - - trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; - if ~exist(trials_structure_plots, 'dir') - mkdir(trials_structure_plots); - end - - processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; - if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') - mkdir(processed_graphFolder_LFP_eventFieldname); - end - - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathersing logData information - - % calculate nexData, need digital input and analog input files - digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); - analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); - rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); - - if ~exist(digin_fname, 'file') - sprintf('no digital input file for %s', session_folder); - continue - end - - if ~exist(analogin_fname, 'file') - sprintf('no analog input file for %s', session_folder); - continue - end - - if ~exist(rhd_fname, 'file') - sprintf('no rhd info file for %s', session_folder); - continue - end - - % read in rhd info; requires 'info.rhd' file. - rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); - - % read digital input file - dig_data = readIntanDigitalFile(digin_fname); - if ~isfield(rhd_info, 'board_adc_channels') - sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) - continue - end - - analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); - nexData = intan2nex(dig_data, analog_data, rhd_info); - - try - sprintf('attempting to create trials structure for %s', session_folder) - trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); - catch - sprintf('could not generate trials structure for %s', session_folder) - continue - end - - % extract Trial Type (e.g. correctGo) - % Set trialType at beginning of file - [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here - trIdx = extractTrials(trials, trialEventParams); - num_trials = length(trIdx); - - %Getting the LFP-fname - pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - - lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); - lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) - Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop - - % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. - % sessions_to_ignore doesn't seem to be working here so using this - % catch instead - lfp_data_num_rows = size(lfp_data.lfp,1); - if lfp_data_num_rows < 64 - continue; - end - - % Order the lfps here - [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) - - %find the column header that matches session_name (session_name and - %the column headers should match for each session to pull in the - %info for probe site health - valid_sites_reordered = channel_information.(session_name); - %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - - % Generate event triggered LFPs - for i_event = 1 : num_events - % write code here to get event_triggered_lfps_ordered - % for each separate event - - % create a filename to save the trials_structure - trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - -% if exist(trials_full_name, 'file') -% continue -% end - - % Cath for troubleshooting the data to NOT run through all of the folders and - % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. - % It will simply generate one trial per session. - - % this function adds 2 fields to the trials structure to identify bad sites - trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? - - event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data - tpoints_per_event = size(event_triggered_lfps, 3); - t = linspace(t_win(1), t_win(2), tpoints_per_event); - - trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); - save(trials_full_name, 'trials_validchannels_marked'); - -% % at this point, event_triggered_lfps_ordered is an m x n x p array where -% % m is the number of events (i.e., all the cueon OR nosein OR other... -% % events) in a single session; n is the number of channels in that session -% % (generally 64), and p is the number of time samples extracted around each -% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). - - % above here, the lfp file, trial structure never change - - % create a filename to save the plots - trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); - -% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. -% % num_channels = size(event_triggered_lfps,2); -% num_trials = size(event_triggered_lfps, 1); -% - % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). - - end - end -end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/find_trials_struct_folders.m b/LFPs/Analysis_code_JM/utils/find_trials_struct_folders.m index f0bf3110..313228ad 100644 --- a/LFPs/Analysis_code_JM/utils/find_trials_struct_folders.m +++ b/LFPs/Analysis_code_JM/utils/find_trials_struct_folders.m @@ -1,12 +1,12 @@ -function valid_trials_folder = find_trials_struct_folders(intan_choicetask_parent) +function valid_trials_folder = find_trials_struct_folders(intan_parent_directory) -potential_rat_folders = dir(intan_choicetask_parent); +potential_rat_folders = dir(intan_parent_directory); valid_trials_folder = struct('name',[], 'trials_structure_folders', []); num_valid_rat_folders = 0; for i_folder = 1 : length(potential_rat_folders) - full_path = fullfile(intan_choicetask_parent, potential_rat_folders(i_folder).name); + full_path = fullfile(intan_parent_directory, potential_rat_folders(i_folder).name); if ~isfolder(full_path) continue end diff --git a/LFPs/Analysis_code_JM/utils/find_trials_struct_original_folders.m b/LFPs/Analysis_code_JM/utils/find_trials_struct_original_folders.m new file mode 100644 index 00000000..037e8c8c --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/find_trials_struct_original_folders.m @@ -0,0 +1,79 @@ +function valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory) + +potential_rat_folders = dir(intan_parent_directory); +valid_trials_original_folder = struct('name',[], 'trials_structure_folders', []); + +num_valid_rat_folders = 0; +for i_folder = 1 : length(potential_rat_folders) + + full_path = fullfile(intan_parent_directory, potential_rat_folders(i_folder).name); + if ~isfolder(full_path) + continue + end + % look for folders of format RXXXX + if isvalidratfolder(potential_rat_folders(i_folder).name) + num_valid_rat_folders = num_valid_rat_folders + 1; + rat_folders{num_valid_rat_folders} = full_path; + end + +end + +num_rat_folders_with_trials_data = 0; +for i_ratfolder = 1 : num_valid_rat_folders + + [root_path, cur_ratID, ext] = fileparts(rat_folders{i_ratfolder}); + + cur_trials_folder = fullfile(rat_folders{i_ratfolder}, strcat(cur_ratID, '-LFP-trials-structures-original')); + + if ~isfolder(cur_trials_folder) + continue + end + + potential_session_folders = dir(cur_trials_folder); + + % rewrite this section to find session folders with processed data + num_valid_sessionfolders = 0; + found_trials_data = false; + num_trials_sessionfolders = 0; + for i_sessionfolder = 1 : length(potential_session_folders) + if isvalidchoicesessionfolder(potential_session_folders(i_sessionfolder).name) + num_valid_sessionfolders = num_valid_sessionfolders + 1; + + % test if session folder contains lfp data + full_pd_path = fullfile(cur_trials_folder, potential_session_folders(i_sessionfolder).name); +% test_folders = dir(full_pd_path); +% for i_tf = 1 : length(test_folders) +% fp = fullfile(full_pd_path, test_folders(i_tf).name); +% +% if ~isfolder(fp) || length(test_folders(i_tf).name) < 5 +% continue +% end +% +% if ~isvalidratfolder(test_folders(i_tf).name(1:5)) +% continue +% end +% +% % if isbehavior_vi_folder(test_folders(i_tf).name) +% % continue +% % end + + trials_datafolder = is_intan_trials_structure_datafolder(full_pd_path); + if ~isempty(trials_datafolder) + num_trials_sessionfolders = num_trials_sessionfolders + 1; + trials_datafolders{num_trials_sessionfolders} = trials_datafolder; + found_trials_data = true; + end + +% end + end + end + + if found_trials_data + num_rat_folders_with_trials_data = num_rat_folders_with_trials_data + 1; + valid_trials_original_folder(num_rat_folders_with_trials_data).name = rat_folders{i_ratfolder}; + valid_trials_original_folder(num_rat_folders_with_trials_data).trials_folders = trials_datafolders; + end + +end + +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv b/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv deleted file mode 100644 index fe8a8ec6..00000000 --- a/LFPs/Analysis_code_JM/utils/generate_trials_structure.asv +++ /dev/null @@ -1,132 +0,0 @@ -% script to generate trials structures -% This file needs to be tested 12/18/2022 - -intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); - -%% -% lists for ratID probe_type -NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type -ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; - -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; -sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; -sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; -% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? - -%% -for i_rat = 1 : length(rats_with_intan_sessions) - - intan_folders = rats_with_intan_sessions(i_rat).intan_folders; - - for i_sessionfolder = 1 : length(intan_folders) - % extract the ratID and session name from the LFP file - session_path = intan_folders{i_sessionfolder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); - session_trials_folder_original = create_trials_structure_original_folder(rd_metadata, intan_parent_directory); - ratID = rd_metadata.ratID; - intan_session_name = rd_metadata.session_name; - session_name = rd_metadata.session_name; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end - - -% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... -% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - - -% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') -% continue; -% end - - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - -% if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly -% probe_type = 'NN8x8'; -% elseif contains(ratID, ASSY156) -% probe_type = 'ASSY156'; -% elseif contains(ratID, ASSY236) -% probe_type = 'ASSY236'; -% end - - -% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; -% if ~exist(trials_structure, 'dir') -% mkdir(trials_structure); -% end - - trials_structure_original = [parentFolder(1:end-9) 'LFP-trials-structures-original']; - if ~exist(trials_structure_original, 'dir') - mkdir(trials_structure_original); - end - - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathersing logData information - - % calculate nexData, need digital input and analog input files - digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); - analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); - rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); - - if ~exist(digin_fname, 'file') - sprintf('no digital input file for %s', session_folder); - continue - end - - if ~exist(analogin_fname, 'file') - sprintf('no analog input file for %s', session_folder); - continue - end - - if ~exist(rhd_fname, 'file') - sprintf('no rhd info file for %s', session_folder); - continue - end - - % read in rhd info; requires 'info.rhd' file. - rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); - - % read digital input file - dig_data = readIntanDigitalFile(digin_fname); - if ~isfield(rhd_info, 'board_adc_channels') - sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) - continue - end - - analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); - nexData = intan2nex(dig_data, analog_data, rhd_info); - - try - sprintf('attempting to create trials structure for %s', session_folder) - trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); - catch - sprintf('could not generate trials structure for %s', session_folder) - continue - end - - trials_fname_to_save = char(strcat(session_name, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_original_full_name = fullfile(session_trials_folder_original, trials_fname_to_save); - save(trials_original_full_name, 'trials'); - end -end diff --git a/LFPs/Analysis_code_JM/utils/generate_trials_structure.m b/LFPs/Analysis_code_JM/utils/generate_trials_structure.m index 7ab96da5..707b8c3e 100644 --- a/LFPs/Analysis_code_JM/utils/generate_trials_structure.m +++ b/LFPs/Analysis_code_JM/utils/generate_trials_structure.m @@ -78,6 +78,13 @@ [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); session_log = find_session_log(session_folder); + trials_fname_to_save = char(strcat(session_name, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_original_full_name = fullfile(session_trials_folder_original, trials_fname_to_save); + + if exist(trials_original_full_name, 'file') + continue; + end + if isempty(session_log) sprintf('no log file found for %s', session_folder) end @@ -125,8 +132,7 @@ continue end - trials_fname_to_save = char(strcat(session_name, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_original_full_name = fullfile(session_trials_folder_original, trials_fname_to_save); + save(trials_original_full_name, 'trials'); end end diff --git a/LFPs/Analysis_code_JM/utils/gude-2022-12-20.log b/LFPs/Analysis_code_JM/utils/gude-2022-12-20.log new file mode 100644 index 00000000..39f1c1ca --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/gude-2022-12-20.log @@ -0,0 +1,6 @@ +09:22:23:119 [ALWAYS] GUDE Logging Started +09:22:23:124 [INFO] SqliteResumeCache::SqliteResumeCache basedirectory is null/empty +09:22:23:125 [ERROR] SqliteResumeCache::CreateSqliteResumeCache creating resume cache pointer failure +09:22:23:126 [ERROR] Initialize resume cache pointer failure +09:22:23:127 [INFO] gude policy POLICY_USER limit (4,4,1) chunk 2097152, chunking (UL 0 DL 1), resXfer 1, adapt 0, NSURL 1, timeout 86400 +09:22:23:130 [INFO] Initialized -- gude-lib version: v0.12.1 app: gude diff --git a/LFPs/Analysis_code_JM/utils/load_trials_structure.m b/LFPs/Analysis_code_JM/utils/load_trials_structure.m index 059ecb7b..b506736a 100644 --- a/LFPs/Analysis_code_JM/utils/load_trials_structure.m +++ b/LFPs/Analysis_code_JM/utils/load_trials_structure.m @@ -1,14 +1,14 @@ % script to load in trials structure intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -valid_trials_folder = find_trials_struct_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data +valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc %% - for i_ratfolder = 1 : length(valid_trials_folder) + for i_ratfolder = 1 : length(valid_trials_original_folder) - session_trials_struct_folders = valid_trials_folder(i_ratfolder).trials_folders; + session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; for i_trials_folder = 1 : length(session_trials_struct_folders) % extract the ratID and session name from the LFP file @@ -19,7 +19,7 @@ % Load trials structure for i_trialsfolder = 1:length(session_trials_struct_folders) - session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures'], session_name); + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); session_trials = find_trials_mat(session_trials_structure); trials_structure_file = dir(fullfile(session_trials)); trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); diff --git a/LFPs/Analysis_code_JM/utils/load_trials_structure_identify_bad_data.m b/LFPs/Analysis_code_JM/utils/load_trials_structure_identify_bad_data.m new file mode 100644 index 00000000..059ecb7b --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/load_trials_structure_identify_bad_data.m @@ -0,0 +1,30 @@ +% script to load in trials structure +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; + +valid_trials_folder = find_trials_struct_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data + +fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc + +%% + for i_ratfolder = 1 : length(valid_trials_folder) + + session_trials_struct_folders = valid_trials_folder(i_ratfolder).trials_folders; + + for i_trials_folder = 1 : length(session_trials_struct_folders) + % extract the ratID and session name from the LFP file + session_path = session_trials_struct_folders{i_trials_folder}; + pd_trials_data = parse_trials_struct_folder(session_path); + ratID = pd_trials_data.ratID; + session_name = pd_trials_data.session_name; + + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures'], session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials_validchannels_marked = trials_structure.trials_validchannels_marked; + end + end + end From bcce11b00c43e11df5aef6e1ae40096c03feda7d Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Tue, 20 Dec 2022 15:57:45 -0500 Subject: [PATCH 05/19] troubleshooting --- .../extract_LFP_around_timestamps.m | 4 - ...nerate_trials_structure_bad_data_plots.asv | 404 ++++++++++++ ...generate_trials_structure_bad_data_plots.m | 597 +++++++++--------- .../utils/load_trials_structure.m | 4 +- 4 files changed, 710 insertions(+), 299 deletions(-) create mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv diff --git a/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m b/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m index bf3b0003..26f1a38f 100644 --- a/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m +++ b/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m @@ -38,11 +38,7 @@ start_sample = floor(trial_ts(i_ts) * Fs); end_sample = start_sample + samples_per_event - 1; - try current_lfp = ordered_lfp(:, start_sample:end_sample); % changed LFP to ordered_lfp for the calculate_cwt_3D_matrix script - catch - keyboard; - end end event_triggered_lfps(i_ts, :, :) = current_lfp; diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv new file mode 100644 index 00000000..61128a32 --- /dev/null +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv @@ -0,0 +1,404 @@ +% script to write field potentials around each trial + +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); +valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); + +%% +fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc +num_trials_to_plot = 5; + +% start with an LFP file +% get the trial structure for that session +% run this analysis + +trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) + +switch lower(trialType) + case 'allgo' + eventFieldnames = {'centerIn'}; + case 'correctgo' + eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; +end + + % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', + % 'foodretrievel'}; This is the full eventlist for a correctGo trial. + % Choose one for generating event_triggered_lfps. +num_events = length(eventFieldnames); +t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct + + +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +naming_convention; % for labeling graphs + +% choiceTask difficulty levels +choiceRTdifficulty = cell(1, 10); +choiceRTdifficulty{1} = 'poke any'; +choiceRTdifficulty{2} = 'very easy'; +choiceRTdifficulty{3} = 'easy'; +choiceRTdifficulty{4} = 'standard'; +choiceRTdifficulty{5} = 'advanced'; +choiceRTdifficulty{6} = 'choice VE'; +choiceRTdifficulty{7} = 'choice easy'; +choiceRTdifficulty{8} = 'choice standard'; +choiceRTdifficulty{9} = 'choice advanced'; +choiceRTdifficulty{10} = 'testing'; + +%% + %Testing just loading in the trials structure here + +for i_ratfolder = 1 : length(valid_trials_original_folder) + + session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; + + for i_trials_folder = 1 : length(session_trials_struct_folders) + % extract the ratID and session name from the LFP file + session_path = session_trials_struct_folders{i_trials_folder}; + pd_trials_data = parse_trials_struct_folder(session_path); + ratID = pd_trials_data.ratID; + session_name = pd_trials_data.session_name; + + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials = trials_structure.trials; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + +% if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end + + probe_channel_info = load_channel_information(fname, sheetname); + [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + % Graphs in this folder are WITH calculating an outlier threshold. + trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; + if ~exist(trials_structure_plots, 'dir') + mkdir(trials_structure_plots); + end + + % Graphs in this folder are grandfathered in BEFORE I calculated a specific outlier threshold and just using by eye on Neuroscope. + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') + mkdir(processed_graphFolder_LFP_eventFieldname); + end + +% % Start of generation of trials structure + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); % even with loading in trials structure, still need logData but it is quick to load. + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathering logData information +% +% % calculate nexData, need digital input and analog input files +% digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); +% analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); +% rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); +% +% if ~exist(digin_fname, 'file') +% sprintf('no digital input file for %s', session_folder); +% continue +% end +% +% if ~exist(analogin_fname, 'file') +% sprintf('no analog input file for %s', session_folder); +% continue +% end +% +% if ~exist(rhd_fname, 'file') +% sprintf('no rhd info file for %s', session_folder); +% continue +% end +% +% % read in rhd info; requires 'info.rhd' file. +% rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); +% +% % read digital input file +% dig_data = readIntanDigitalFile(digin_fname); +% if ~isfield(rhd_info, 'board_adc_channels') +% sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) +% continue +% end +% +% analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); +% nexData = intan2nex(dig_data, analog_data, rhd_info); +% +% try +% sprintf('attempting to create trials structure for %s', session_folder) +% trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); +% catch +% sprintf('could not generate trials structure for %s', session_folder) +% continue +% end +% % End of calculating trials structure (original without threshold info) + + + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); + + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + + % % at this point, event_triggered_lfps_ordered is an m x n x p array where + % % m is the number of events (i.e., all the cueon OR nosein OR other... + % % events) in a single session; n is the number of channels in that session + % % (generally 64), and p is the number of time samples extracted around each + % % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change + + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + + % % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. + % % num_channels = size(event_triggered_lfps,2); + % num_trials = size(event_triggered_lfps, 1); + % + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + if num_trials < num_trials_to_plot + continue; + end + + % select trials for plotting at random + trial_idx_to_plot = randperm(num_trials, num_trials_to_plot); % create a catch if num_trials_to_plot < num_trials, continue. + + for i_trial = 1:num_trials_to_plot + trial_idx = trial_idx_to_plot(i_trial); + channel_lfps = squeeze(event_triggered_lfps(trial_idx,:, :)); + % trials, create a 64channel graph for each trial? + + % Plot the data + figure; + num_rows = size(event_triggered_lfps,2); + LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) + for i_row = 1 : num_rows + + y_lim = [-2500, 2500]; + plot_col = ceil(i_row / LFPs_per_shank); + plot_row = i_row - LFPs_per_shank * (plot_col-1); + plot_num = (plot_row-1) * 8 + plot_col; + + subplot(LFPs_per_shank,8,plot_num); + + % sue the trials structure data + % (trials_validchannels_marked.is_channel_valid_ordered) + % to color the actual plots based on good or + % bad sites above the specified threshold (1500mV, check the script to verify) + % switch trials_validchannels_marked(i_trial).is_channel_valid_ordered(i_row) + switch trials_validchannels_marked(trial_idx).is_channel_valid_ordered(i_row) + % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + plot_color = 'r'; % marks bad channels within specified trial + case 1 + plot_color = 'k'; % marks good channels within specified trial + otherwise + plot_color = 'b'; % catch in case the data was not input into the structure + end + + plot_channel_lfps = plot(t, channel_lfps(i_row, :), plot_color); % change to log10 -- plot(f, 10*log10(power_lfps(:,1))) + set(gca, 'ylim',y_lim); + grid on + + % give titles to each subplot + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + caption = sprintf('NN8x8 #%d', site_order(i_row)); + elseif contains(ratID, ASSY156) + caption = sprintf('ASSY156 #%d', site_order(i_row)); + elseif contains(ratID, ASSY236) + caption = sprintf('ASSY236 #%d', site_order(i_row)); + end + title(caption, 'FontSize', 8); + + if plot_row < LFPs_per_shank + set(gca,'xticklabels',[]) + end + + if plot_col > 1 + set(gca,'yticklabels',[]) + end + + ax = gca; + % This section is coded to color the axes of + % the plots when checking the amplifier.dat + % files 'by eye' using Neuroscope + switch valid_sites_reordered(i_row) % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + ax.XColor = 'r'; % Red % marks bad channels within specified trial + ax.YColor = 'r'; % Red + % ax.ylabel = 'k'; + case 1 + ax.XColor = 'k'; % black % marks good channels within specified trial + ax.YColor = 'k'; % black + % ax.ylabel = 'k'; + case 2 + ax.XColor = 'b'; % blue % marks channels as 'variable' and could be good for portions of the whole amplifier.dat file but bad for others. Thus some channels may be good for only some trials, not all. + ax.YColor = 'b'; + % ax.ylabel = 'k'; + otherwise + ax.XColor = 'b'; % blue % catch in case the data was not input into the structure + ax.YColor = 'b'; + % ax.ylabel = 'k'; + end + end + set(gcf, 'WindowState', 'maximize'); % maximizes the window so that it exports the graphics with appropriate font size + + % Gives the whole plot page a name + A=cell(1,5); + A{1} = ['Subject: ' ratID]; + A{2} = ['Session: ' session_name]; + A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; + A{4} = ['Trial Number: ' num2str(trial_idx)]; + A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; + + sgtitle(A, 'Interpreter','none'); + + if i_trial == 1 + exportgraphics(gcf, trials_plot_full_name); + else + exportgraphics(gcf, trials_plot_full_name, 'append', true); %ADD APPEND FLAG HERE + end + close; + end + end + + end + end + +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m index 462bb323..2958e2e2 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m @@ -4,8 +4,7 @@ intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); -valid_trials_folder = find_trials_struct_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data - +valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); %% fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc @@ -57,22 +56,36 @@ choiceRTdifficulty{10} = 'testing'; %% -for i_rat = 1 : length(rats_with_intan_sessions) - - intan_folders = rats_with_intan_sessions(i_rat).intan_folders; - - for i_sessionfolder = 1 : length(intan_folders) + %Testing just loading in the trials structure here + +for i_ratfolder = 1 : length(valid_trials_original_folder) + + session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; + intan_folders = rats_with_intan_sessions(i_ratfolder).intan_folders; + + for i_session_folder = 1 : length(intan_folders) % extract the ratID and session name from the LFP file - session_path = intan_folders{i_sessionfolder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); - session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); - ratID = rd_metadata.ratID; - intan_session_name = rd_metadata.session_name; - session_name = rd_metadata.session_name; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end + session_path = session_trials_struct_folders{i_session_folder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_session_folder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + pd_trials_data = parse_trials_struct_folder(session_path); + ratID = pd_trials_data.ratID; + intan_session_name = rd_metadata.session_name; + trial_session_name = pd_trials_data.session_name; + session_name = rd_metadata.session_name; + + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], trial_session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials = trials_structure.trials; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end % if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes % continue; @@ -88,55 +101,55 @@ % continue; % end - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); - end + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1) || contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end probe_channel_info = load_channel_information(fname, sheetname); [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); @@ -158,237 +171,237 @@ mkdir(processed_graphFolder_LFP_eventFieldname); end - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - - % Start of generation of trials structure - logData = readLogData(session_log); %gathering logData information - - % calculate nexData, need digital input and analog input files - digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); - analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); - rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); - - if ~exist(digin_fname, 'file') - sprintf('no digital input file for %s', session_folder); - continue - end - - if ~exist(analogin_fname, 'file') - sprintf('no analog input file for %s', session_folder); - continue - end - - if ~exist(rhd_fname, 'file') - sprintf('no rhd info file for %s', session_folder); - continue - end - - % read in rhd info; requires 'info.rhd' file. - rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); - - % read digital input file - dig_data = readIntanDigitalFile(digin_fname); - if ~isfield(rhd_info, 'board_adc_channels') - sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) - continue - end - - analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); - nexData = intan2nex(dig_data, analog_data, rhd_info); - - try - sprintf('attempting to create trials structure for %s', session_folder) - trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); - catch - sprintf('could not generate trials structure for %s', session_folder) - continue - end - % End of calculating trials structure (original without threshold info) +% % Start of generation of trials structure + [session_folder, ~, ~] = fileparts(intan_folders{i_session_folder}); % even with loading in trials structure, still need logData but it is quick to load. + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathering logData information +% +% % calculate nexData, need digital input and analog input files +% digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); +% analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); +% rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); +% +% if ~exist(digin_fname, 'file') +% sprintf('no digital input file for %s', session_folder); +% continue +% end +% +% if ~exist(analogin_fname, 'file') +% sprintf('no analog input file for %s', session_folder); +% continue +% end +% +% if ~exist(rhd_fname, 'file') +% sprintf('no rhd info file for %s', session_folder); +% continue +% end +% +% % read in rhd info; requires 'info.rhd' file. +% rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); +% +% % read digital input file +% dig_data = readIntanDigitalFile(digin_fname); +% if ~isfield(rhd_info, 'board_adc_channels') +% sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) +% continue +% end +% +% analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); +% nexData = intan2nex(dig_data, analog_data, rhd_info); +% +% try +% sprintf('attempting to create trials structure for %s', session_folder) +% trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); +% catch +% sprintf('could not generate trials structure for %s', session_folder) +% continue +% end +% % End of calculating trials structure (original without threshold info) - % extract Trial Type (e.g. correctGo) - % Set trialType at beginning of file - [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here - trIdx = extractTrials(trials, trialEventParams); - num_trials = length(trIdx); - - %Getting the LFP-fname - pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - - lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); - lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) - Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop - - % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. - % sessions_to_ignore doesn't seem to be working here so using this - % catch instead - lfp_data_num_rows = size(lfp_data.lfp,1); - if lfp_data_num_rows < 64 - continue; - end - % Order the lfps here - [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) - - %find the column header that matches session_name (session_name and - %the column headers should match for each session to pull in the - %info for probe site health - valid_sites_reordered = channel_information.(session_name); - %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - - % Generate event triggered LFPs - for i_event = 1 : num_events - % write code here to get event_triggered_lfps_ordered - % for each separate event - -% % create a filename to save the trials_structure - trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - - - % Cath for troubleshooting the data to NOT run through all of the folders and - % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. - % It will simply generate one trial per session. - - % this function adds 2 fields to the trials structure to identify bad sites - trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? - - event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data - tpoints_per_event = size(event_triggered_lfps, 3); - t = linspace(t_win(1), t_win(2), tpoints_per_event); - - trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); - save(trials_full_name, 'trials_validchannels_marked'); - -% % at this point, event_triggered_lfps_ordered is an m x n x p array where -% % m is the number of events (i.e., all the cueon OR nosein OR other... -% % events) in a single session; n is the number of channels in that session -% % (generally 64), and p is the number of time samples extracted around each -% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). - - % above here, the lfp file, trial structure never change - - % create a filename to save the plots - trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); - -% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. -% % num_channels = size(event_triggered_lfps,2); -% num_trials = size(event_triggered_lfps, 1); -% - % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). - if num_trials < num_trials_to_plot - continue; - end + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); - % select trials for plotting at random - trial_idx_to_plot = randperm(num_trials, num_trials_to_plot); % create a catch if num_trials_to_plot < num_trials, continue. - - for i_trial = 1:num_trials_to_plot - trial_idx = trial_idx_to_plot(i_trial); - channel_lfps = squeeze(event_triggered_lfps(trial_idx,:, :)); - % trials, create a 64channel graph for each trial? - - % Plot the data - figure; - num_rows = size(event_triggered_lfps,2); - LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) - for i_row = 1 : num_rows - - y_lim = [-2500, 2500]; - plot_col = ceil(i_row / LFPs_per_shank); - plot_row = i_row - LFPs_per_shank * (plot_col-1); - plot_num = (plot_row-1) * 8 + plot_col; - - subplot(LFPs_per_shank,8,plot_num); - - % sue the trials structure data - % (trials_validchannels_marked.is_channel_valid_ordered) - % to color the actual plots based on good or - % bad sites above the specified threshold (1500mV, check the script to verify) -% switch trials_validchannels_marked(i_trial).is_channel_valid_ordered(i_row) - switch trials_validchannels_marked(trial_idx).is_channel_valid_ordered(i_row) - % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps - case 0 - plot_color = 'r'; % marks bad channels within specified trial - case 1 - plot_color = 'k'; % marks good channels within specified trial - otherwise - plot_color = 'b'; % catch in case the data was not input into the structure - end + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - plot_channel_lfps = plot(t, channel_lfps(i_row, :), plot_color); % change to log10 -- plot(f, 10*log10(power_lfps(:,1))) - set(gca, 'ylim',y_lim); - grid on - - % give titles to each subplot - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - caption = sprintf('NN8x8 #%d', site_order(i_row)); - elseif contains(ratID, ASSY156) - caption = sprintf('ASSY156 #%d', site_order(i_row)); - elseif contains(ratID, ASSY236) - caption = sprintf('ASSY236 #%d', site_order(i_row)); - end - title(caption, 'FontSize', 8); + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(trial_session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); + + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(trial_session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + + % % at this point, event_triggered_lfps_ordered is an m x n x p array where + % % m is the number of events (i.e., all the cueon OR nosein OR other... + % % events) in a single session; n is the number of channels in that session + % % (generally 64), and p is the number of time samples extracted around each + % % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change + + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(trial_session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); - if plot_row < LFPs_per_shank - set(gca,'xticklabels',[]) - end - - if plot_col > 1 - set(gca,'yticklabels',[]) - end - - ax = gca; - % This section is coded to color the axes of - % the plots when checking the amplifier.dat - % files 'by eye' using Neuroscope - switch valid_sites_reordered(i_row) % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps - case 0 - ax.XColor = 'r'; % Red % marks bad channels within specified trial - ax.YColor = 'r'; % Red - % ax.ylabel = 'k'; - case 1 - ax.XColor = 'k'; % black % marks good channels within specified trial - ax.YColor = 'k'; % black - % ax.ylabel = 'k'; - case 2 - ax.XColor = 'b'; % blue % marks channels as 'variable' and could be good for portions of the whole amplifier.dat file but bad for others. Thus some channels may be good for only some trials, not all. - ax.YColor = 'b'; - % ax.ylabel = 'k'; - otherwise - ax.XColor = 'b'; % blue % catch in case the data was not input into the structure - ax.YColor = 'b'; - % ax.ylabel = 'k'; - end - end - set(gcf, 'WindowState', 'maximize'); % maximizes the window so that it exports the graphics with appropriate font size - - % Gives the whole plot page a name - A=cell(1,5); - A{1} = ['Subject: ' ratID]; - A{2} = ['Session: ' session_name]; - A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; - A{4} = ['Trial Number: ' num2str(trial_idx)]; - A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; - - sgtitle(A, 'Interpreter','none'); - - if i_trial == 1 - exportgraphics(gcf, trials_plot_full_name); - else - exportgraphics(gcf, trials_plot_full_name, 'append', true); %ADD APPEND FLAG HERE - end - close; + % % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. + % % num_channels = size(event_triggered_lfps,2); + % num_trials = size(event_triggered_lfps, 1); + % + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + if num_trials < num_trials_to_plot + continue; + end + + % select trials for plotting at random + trial_idx_to_plot = randperm(num_trials, num_trials_to_plot); % create a catch if num_trials_to_plot < num_trials, continue. + + for i_trial = 1:num_trials_to_plot + trial_idx = trial_idx_to_plot(i_trial); + channel_lfps = squeeze(event_triggered_lfps(trial_idx,:, :)); + % trials, create a 64channel graph for each trial? + + % Plot the data + figure; + num_rows = size(event_triggered_lfps,2); + LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) + for i_row = 1 : num_rows + + y_lim = [-2500, 2500]; + plot_col = ceil(i_row / LFPs_per_shank); + plot_row = i_row - LFPs_per_shank * (plot_col-1); + plot_num = (plot_row-1) * 8 + plot_col; + + subplot(LFPs_per_shank,8,plot_num); + + % sue the trials structure data + % (trials_validchannels_marked.is_channel_valid_ordered) + % to color the actual plots based on good or + % bad sites above the specified threshold (1500mV, check the script to verify) + % switch trials_validchannels_marked(i_trial).is_channel_valid_ordered(i_row) + switch trials_validchannels_marked(trial_idx).is_channel_valid_ordered(i_row) + % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + plot_color = 'r'; % marks bad channels within specified trial + case 1 + plot_color = 'k'; % marks good channels within specified trial + otherwise + plot_color = 'b'; % catch in case the data was not input into the structure + end + + plot_channel_lfps = plot(t, channel_lfps(i_row, :), plot_color); % change to log10 -- plot(f, 10*log10(power_lfps(:,1))) + set(gca, 'ylim',y_lim); + grid on + + % give titles to each subplot + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + caption = sprintf('NN8x8 #%d', site_order(i_row)); + elseif contains(ratID, ASSY156) + caption = sprintf('ASSY156 #%d', site_order(i_row)); + elseif contains(ratID, ASSY236) + caption = sprintf('ASSY236 #%d', site_order(i_row)); + end + title(caption, 'FontSize', 8); + + if plot_row < LFPs_per_shank + set(gca,'xticklabels',[]) + end + + if plot_col > 1 + set(gca,'yticklabels',[]) + end + + ax = gca; + % This section is coded to color the axes of + % the plots when checking the amplifier.dat + % files 'by eye' using Neuroscope + switch valid_sites_reordered(i_row) % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + ax.XColor = 'r'; % Red % marks bad channels within specified trial + ax.YColor = 'r'; % Red + % ax.ylabel = 'k'; + case 1 + ax.XColor = 'k'; % black % marks good channels within specified trial + ax.YColor = 'k'; % black + % ax.ylabel = 'k'; + case 2 + ax.XColor = 'b'; % blue % marks channels as 'variable' and could be good for portions of the whole amplifier.dat file but bad for others. Thus some channels may be good for only some trials, not all. + ax.YColor = 'b'; + % ax.ylabel = 'k'; + otherwise + ax.XColor = 'b'; % blue % catch in case the data was not input into the structure + ax.YColor = 'b'; + % ax.ylabel = 'k'; + end + end + set(gcf, 'WindowState', 'maximize'); % maximizes the window so that it exports the graphics with appropriate font size + + % Gives the whole plot page a name + A=cell(1,5); + A{1} = ['Subject: ' ratID]; + A{2} = ['Session: ' trial_session_name]; + A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; + A{4} = ['Trial Number: ' num2str(trial_idx)]; + A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; + + sgtitle(A, 'Interpreter','none'); + + if i_trial == 1 + exportgraphics(gcf, trials_plot_full_name); + else + exportgraphics(gcf, trials_plot_full_name, 'append', true); %ADD APPEND FLAG HERE + end + close; + end end end - end - -end \ No newline at end of file + end +end diff --git a/LFPs/Analysis_code_JM/utils/load_trials_structure.m b/LFPs/Analysis_code_JM/utils/load_trials_structure.m index b506736a..05016875 100644 --- a/LFPs/Analysis_code_JM/utils/load_trials_structure.m +++ b/LFPs/Analysis_code_JM/utils/load_trials_structure.m @@ -3,8 +3,6 @@ valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); % find the folders with the trials structures to lab each lfp with data calculated as 'bad'; % need to match this with the loaded in lfp data -fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc - %% for i_ratfolder = 1 : length(valid_trials_original_folder) @@ -24,7 +22,7 @@ trials_structure_file = dir(fullfile(session_trials)); trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); trials_structure = load(trials_structure_fname); - trials_validchannels_marked = trials_structure.trials_validchannels_marked; + trials = trials_structure.trials; end end end From 9a4e1b1fe8a1826db6f6ec6f85a045ee1d89eca9 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Fri, 23 Dec 2022 14:17:15 -0500 Subject: [PATCH 06/19] updates --- .../extract_LFP_around_timestamps.m | 5 +- ...ipt_generate_trials_structure_bad_data.asv | 282 ++++++++++++ ...nerate_trials_structure_bad_data_plots.asv | 163 +++---- ...generate_trials_structure_bad_data_plots.m | 399 ++++++++--------- ..._trials_structure_bad_data_plots_TESTING.m | 405 ++++++++++++++++++ 5 files changed, 962 insertions(+), 292 deletions(-) create mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv create mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots_TESTING.m diff --git a/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m b/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m index 26f1a38f..c9975764 100644 --- a/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m +++ b/LFPs/Analysis_code_JM/extract_LFP_around_timestamps.m @@ -37,8 +37,11 @@ else start_sample = floor(trial_ts(i_ts) * Fs); end_sample = start_sample + samples_per_event - 1; - + try current_lfp = ordered_lfp(:, start_sample:end_sample); % changed LFP to ordered_lfp for the calculate_cwt_3D_matrix script + catch + keyboard + end end event_triggered_lfps(i_ts, :, :) = current_lfp; diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv new file mode 100644 index 00000000..6ac8b316 --- /dev/null +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv @@ -0,0 +1,282 @@ +% script to write field potentials around each trial + +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +%% +fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc +num_trials_to_plot = 5; + +% start with an LFP file +% get the trial structure for that session +% run this analysis + +trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) + +switch lower(trialType) + case 'allgo' + eventFieldnames = {'centerIn'}; + case 'correctgo' + eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; +end + + % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', + % 'foodretrievel'}; This is the full eventlist for a correctGo trial. + % Choose one for generating event_triggered_lfps. +num_events = length(eventFieldnames); +t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct + + +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +naming_convention; % for labeling graphs + +% choiceTask difficulty levels +choiceRTdifficulty = cell(1, 10); +choiceRTdifficulty{1} = 'poke any'; +choiceRTdifficulty{2} = 'very easy'; +choiceRTdifficulty{3} = 'easy'; +choiceRTdifficulty{4} = 'standard'; +choiceRTdifficulty{5} = 'advanced'; +choiceRTdifficulty{6} = 'choice VE'; +choiceRTdifficulty{7} = 'choice easy'; +choiceRTdifficulty{8} = 'choice standard'; +choiceRTdifficulty{9} = 'choice advanced'; +choiceRTdifficulty{10} = 'testing'; + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end + + probe_channel_info = load_channel_information(fname, sheetname); + [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; + if ~exist(trials_structure_plots, 'dir') + mkdir(trials_structure_plots); + end + + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') + mkdir(processed_graphFolder_LFP_eventFieldname); + end + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); + + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + +% if exist(trials_full_name, 'file') +% continue +% end + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + +% % at this point, event_triggered_lfps_ordered is an m x n x p array where +% % m is the number of events (i.e., all the cueon OR nosein OR other... +% % events) in a single session; n is the number of channels in that session +% % (generally 64), and p is the number of time samples extracted around each +% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change + + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + +% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. +% % num_channels = size(event_triggered_lfps,2); +% num_trials = size(event_triggered_lfps, 1); +% + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + + end + end +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv index 61128a32..c774079b 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv @@ -58,29 +58,24 @@ choiceRTdifficulty{10} = 'testing'; %% %Testing just loading in the trials structure here -for i_ratfolder = 1 : length(valid_trials_original_folder) +for i_ratfolder = 1 : length(rats_with_intan_sessions) - session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; - - for i_trials_folder = 1 : length(session_trials_struct_folders) + session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; + intan_folders = rats_with_intan_sessions(i_ratfolder).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) % extract the ratID and session name from the LFP file - session_path = session_trials_struct_folders{i_trials_folder}; + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; pd_trials_data = parse_trials_struct_folder(session_path); - ratID = pd_trials_data.ratID; - session_name = pd_trials_data.session_name; - - % Load trials structure - for i_trialsfolder = 1:length(session_trials_struct_folders) - session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); - session_trials = find_trials_mat(session_trials_structure); - trials_structure_file = dir(fullfile(session_trials)); - trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); - trials_structure = load(trials_structure_fname); - trials = trials_structure.trials; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end % if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes % continue; @@ -96,55 +91,64 @@ for i_ratfolder = 1 : length(valid_trials_original_folder) % continue; % end - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1) || contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials = trials_structure.trials; end + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end probe_channel_info = load_channel_information(fname, sheetname); [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); @@ -167,14 +171,14 @@ for i_ratfolder = 1 : length(valid_trials_original_folder) end % % Start of generation of trials structure - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); % even with loading in trials structure, still need logData but it is quick to load. - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathering logData information + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); % even with loading in trials structure, still need logData but it is quick to load. + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathering logData information % % % calculate nexData, need digital input and analog input files % digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); @@ -396,9 +400,6 @@ for i_ratfolder = 1 : length(valid_trials_original_folder) end close; end - end - - end - end - -end \ No newline at end of file + end + end +end diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m index 2958e2e2..cab47252 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.m @@ -56,41 +56,24 @@ choiceRTdifficulty{10} = 'testing'; %% - %Testing just loading in the trials structure here - -for i_ratfolder = 1 : length(valid_trials_original_folder) - - session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; - intan_folders = rats_with_intan_sessions(i_ratfolder).intan_folders; - - for i_session_folder = 1 : length(intan_folders) +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) % extract the ratID and session name from the LFP file - session_path = session_trials_struct_folders{i_session_folder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_session_folder}); - session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); - pd_trials_data = parse_trials_struct_folder(session_path); - ratID = pd_trials_data.ratID; - intan_session_name = rd_metadata.session_name; - trial_session_name = pd_trials_data.session_name; - session_name = rd_metadata.session_name; - - % Load trials structure - for i_trialsfolder = 1:length(session_trials_struct_folders) - session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], trial_session_name); - session_trials = find_trials_mat(session_trials_structure); - trials_structure_file = dir(fullfile(session_trials)); - trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); - trials_structure = load(trials_structure_fname); - trials = trials_structure.trials; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; -% if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + + % if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... % || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes % continue; @@ -101,55 +84,55 @@ % continue; % end - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1) || contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); - end + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end probe_channel_info = load_channel_information(fname, sheetname); [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); @@ -159,144 +142,141 @@ % mkdir(trials_structure); % end - % Graphs in this folder are WITH calculating an outlier threshold. trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; if ~exist(trials_structure_plots, 'dir') mkdir(trials_structure_plots); end - % Graphs in this folder are grandfathered in BEFORE I calculated a specific outlier threshold and just using by eye on Neuroscope. - processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') mkdir(processed_graphFolder_LFP_eventFieldname); end -% % Start of generation of trials structure - [session_folder, ~, ~] = fileparts(intan_folders{i_session_folder}); % even with loading in trials structure, still need logData but it is quick to load. - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathering logData information -% -% % calculate nexData, need digital input and analog input files -% digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); -% analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); -% rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); -% -% if ~exist(digin_fname, 'file') -% sprintf('no digital input file for %s', session_folder); -% continue -% end -% -% if ~exist(analogin_fname, 'file') -% sprintf('no analog input file for %s', session_folder); -% continue -% end -% -% if ~exist(rhd_fname, 'file') -% sprintf('no rhd info file for %s', session_folder); -% continue -% end -% -% % read in rhd info; requires 'info.rhd' file. -% rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); -% -% % read digital input file -% dig_data = readIntanDigitalFile(digin_fname); -% if ~isfield(rhd_info, 'board_adc_channels') -% sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) -% continue -% end -% -% analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); -% nexData = intan2nex(dig_data, analog_data, rhd_info); -% -% try -% sprintf('attempting to create trials structure for %s', session_folder) -% trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); -% catch -% sprintf('could not generate trials structure for %s', session_folder) -% continue -% end -% % End of calculating trials structure (original without threshold info) - + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - % extract Trial Type (e.g. correctGo) - % Set trialType at beginning of file - [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here - trIdx = extractTrials(trials, trialEventParams); - num_trials = length(trIdx); - - %Getting the LFP-fname - pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - - lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); - lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) - Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop - - % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. - % sessions_to_ignore doesn't seem to be working here so using this - % catch instead - lfp_data_num_rows = size(lfp_data.lfp,1); - if lfp_data_num_rows < 64 - continue; - end - - % Order the lfps here - [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) - - %find the column header that matches session_name (session_name and - %the column headers should match for each session to pull in the - %info for probe site health - valid_sites_reordered = channel_information.(trial_session_name); - %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - - % Generate event triggered LFPs - for i_event = 1 : num_events - % write code here to get event_triggered_lfps_ordered - % for each separate event - - % % create a filename to save the trials_structure - trials_fname_to_save = char(strcat(trial_session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - - - % Cath for troubleshooting the data to NOT run through all of the folders and - % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. - % It will simply generate one trial per session. - - % this function adds 2 fields to the trials structure to identify bad sites - trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? - - event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data - tpoints_per_event = size(event_triggered_lfps, 3); - t = linspace(t_win(1), t_win(2), tpoints_per_event); - - trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); - save(trials_full_name, 'trials_validchannels_marked'); - - % % at this point, event_triggered_lfps_ordered is an m x n x p array where - % % m is the number of events (i.e., all the cueon OR nosein OR other... - % % events) in a single session; n is the number of channels in that session - % % (generally 64), and p is the number of time samples extracted around each - % % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). - - % above here, the lfp file, trial structure never change - - % create a filename to save the plots - trials_plot_fname_to_save = char(strcat(trial_session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + +% if exist(trials_full_name, 'file') +% continue +% end + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + +% % at this point, event_triggered_lfps_ordered is an m x n x p array where +% % m is the number of events (i.e., all the cueon OR nosein OR other... +% % events) in a single session; n is the number of channels in that session +% % (generally 64), and p is the number of time samples extracted around each +% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change - % % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. - % % num_channels = size(event_triggered_lfps,2); - % num_trials = size(event_triggered_lfps, 1); - % - % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + +% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. +% % num_channels = size(event_triggered_lfps,2); +% num_trials = size(event_triggered_lfps, 1); +% + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). if num_trials < num_trials_to_plot continue; end @@ -387,7 +367,7 @@ % Gives the whole plot page a name A=cell(1,5); A{1} = ['Subject: ' ratID]; - A{2} = ['Session: ' trial_session_name]; + A{2} = ['Session: ' session_name]; A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; A{4} = ['Trial Number: ' num2str(trial_idx)]; A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; @@ -402,6 +382,5 @@ close; end end - end end end diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots_TESTING.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots_TESTING.m new file mode 100644 index 00000000..c774079b --- /dev/null +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots_TESTING.m @@ -0,0 +1,405 @@ +% script to write field potentials around each trial + +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); +valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); + +%% +fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc +num_trials_to_plot = 5; + +% start with an LFP file +% get the trial structure for that session +% run this analysis + +trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) + +switch lower(trialType) + case 'allgo' + eventFieldnames = {'centerIn'}; + case 'correctgo' + eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; +end + + % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', + % 'foodretrievel'}; This is the full eventlist for a correctGo trial. + % Choose one for generating event_triggered_lfps. +num_events = length(eventFieldnames); +t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct + + +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +naming_convention; % for labeling graphs + +% choiceTask difficulty levels +choiceRTdifficulty = cell(1, 10); +choiceRTdifficulty{1} = 'poke any'; +choiceRTdifficulty{2} = 'very easy'; +choiceRTdifficulty{3} = 'easy'; +choiceRTdifficulty{4} = 'standard'; +choiceRTdifficulty{5} = 'advanced'; +choiceRTdifficulty{6} = 'choice VE'; +choiceRTdifficulty{7} = 'choice easy'; +choiceRTdifficulty{8} = 'choice standard'; +choiceRTdifficulty{9} = 'choice advanced'; +choiceRTdifficulty{10} = 'testing'; + +%% + %Testing just loading in the trials structure here + +for i_ratfolder = 1 : length(rats_with_intan_sessions) + + session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; + intan_folders = rats_with_intan_sessions(i_ratfolder).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + pd_trials_data = parse_trials_struct_folder(session_path); + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) + continue; + end + +% if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + +% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... +% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes +% continue; +% end + + +% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') +% continue; +% end + + if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. + continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for + end + + if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1) || contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + % Load trials structure + for i_trialsfolder = 1:length(session_trials_struct_folders) + session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); + session_trials = find_trials_mat(session_trials_structure); + trials_structure_file = dir(fullfile(session_trials)); + trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); + trials_structure = load(trials_structure_fname); + trials = trials_structure.trials; + end + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % load_channel_information - this file is coded 0 = bad, 1 = good, + % 2 = variable for data in each channel for each session_name for + % each rat_ID. Use the opts.VariableNamesRange for eat ratID to + % detectImportOptions otherwise there's an error due to different + % session number for each rat + sheetname = ratID; + if contains(ratID, 'R0326') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); + elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); + elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); + elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); + elseif contains(ratID, 'R0376') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); + elseif contains(ratID, 'R0394') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); + elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); + elseif contains(ratID, 'R0412') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); + elseif contains(ratID, 'R0419') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); + elseif contains(ratID, 'R0420') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); + elseif contains(ratID, 'R0425') + opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); + end + + probe_channel_info = load_channel_information(fname, sheetname); + [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); + +% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; +% if ~exist(trials_structure, 'dir') +% mkdir(trials_structure); +% end + + % Graphs in this folder are WITH calculating an outlier threshold. + trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; + if ~exist(trials_structure_plots, 'dir') + mkdir(trials_structure_plots); + end + + % Graphs in this folder are grandfathered in BEFORE I calculated a specific outlier threshold and just using by eye on Neuroscope. + processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; + if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') + mkdir(processed_graphFolder_LFP_eventFieldname); + end + +% % Start of generation of trials structure + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); % even with loading in trials structure, still need logData but it is quick to load. + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathering logData information +% +% % calculate nexData, need digital input and analog input files +% digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); +% analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); +% rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); +% +% if ~exist(digin_fname, 'file') +% sprintf('no digital input file for %s', session_folder); +% continue +% end +% +% if ~exist(analogin_fname, 'file') +% sprintf('no analog input file for %s', session_folder); +% continue +% end +% +% if ~exist(rhd_fname, 'file') +% sprintf('no rhd info file for %s', session_folder); +% continue +% end +% +% % read in rhd info; requires 'info.rhd' file. +% rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); +% +% % read digital input file +% dig_data = readIntanDigitalFile(digin_fname); +% if ~isfield(rhd_info, 'board_adc_channels') +% sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) +% continue +% end +% +% analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); +% nexData = intan2nex(dig_data, analog_data, rhd_info); +% +% try +% sprintf('attempting to create trials structure for %s', session_folder) +% trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); +% catch +% sprintf('could not generate trials structure for %s', session_folder) +% continue +% end +% % End of calculating trials structure (original without threshold info) + + + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + %Getting the LFP-fname + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) + Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop + + % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. + % sessions_to_ignore doesn't seem to be working here so using this + % catch instead + lfp_data_num_rows = size(lfp_data.lfp,1); + if lfp_data_num_rows < 64 + continue; + end + + % Order the lfps here + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) + + %find the column header that matches session_name (session_name and + %the column headers should match for each session to pull in the + %info for probe site health + valid_sites_reordered = channel_information.(session_name); + %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); + + % Generate event triggered LFPs + for i_event = 1 : num_events + % write code here to get event_triggered_lfps_ordered + % for each separate event + + % % create a filename to save the trials_structure + trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); + + + % Cath for troubleshooting the data to NOT run through all of the folders and + % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. + % It will simply generate one trial per session. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data + tpoints_per_event = size(event_triggered_lfps, 3); + t = linspace(t_win(1), t_win(2), tpoints_per_event); + + trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); + save(trials_full_name, 'trials_validchannels_marked'); + + % % at this point, event_triggered_lfps_ordered is an m x n x p array where + % % m is the number of events (i.e., all the cueon OR nosein OR other... + % % events) in a single session; n is the number of channels in that session + % % (generally 64), and p is the number of time samples extracted around each + % % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). + + % above here, the lfp file, trial structure never change + + % create a filename to save the plots + trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); + + % % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. + % % num_channels = size(event_triggered_lfps,2); + % num_trials = size(event_triggered_lfps, 1); + % + % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). + if num_trials < num_trials_to_plot + continue; + end + + % select trials for plotting at random + trial_idx_to_plot = randperm(num_trials, num_trials_to_plot); % create a catch if num_trials_to_plot < num_trials, continue. + + for i_trial = 1:num_trials_to_plot + trial_idx = trial_idx_to_plot(i_trial); + channel_lfps = squeeze(event_triggered_lfps(trial_idx,:, :)); + % trials, create a 64channel graph for each trial? + + % Plot the data + figure; + num_rows = size(event_triggered_lfps,2); + LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) + for i_row = 1 : num_rows + + y_lim = [-2500, 2500]; + plot_col = ceil(i_row / LFPs_per_shank); + plot_row = i_row - LFPs_per_shank * (plot_col-1); + plot_num = (plot_row-1) * 8 + plot_col; + + subplot(LFPs_per_shank,8,plot_num); + + % sue the trials structure data + % (trials_validchannels_marked.is_channel_valid_ordered) + % to color the actual plots based on good or + % bad sites above the specified threshold (1500mV, check the script to verify) + % switch trials_validchannels_marked(i_trial).is_channel_valid_ordered(i_row) + switch trials_validchannels_marked(trial_idx).is_channel_valid_ordered(i_row) + % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + plot_color = 'r'; % marks bad channels within specified trial + case 1 + plot_color = 'k'; % marks good channels within specified trial + otherwise + plot_color = 'b'; % catch in case the data was not input into the structure + end + + plot_channel_lfps = plot(t, channel_lfps(i_row, :), plot_color); % change to log10 -- plot(f, 10*log10(power_lfps(:,1))) + set(gca, 'ylim',y_lim); + grid on + + % give titles to each subplot + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + caption = sprintf('NN8x8 #%d', site_order(i_row)); + elseif contains(ratID, ASSY156) + caption = sprintf('ASSY156 #%d', site_order(i_row)); + elseif contains(ratID, ASSY236) + caption = sprintf('ASSY236 #%d', site_order(i_row)); + end + title(caption, 'FontSize', 8); + + if plot_row < LFPs_per_shank + set(gca,'xticklabels',[]) + end + + if plot_col > 1 + set(gca,'yticklabels',[]) + end + + ax = gca; + % This section is coded to color the axes of + % the plots when checking the amplifier.dat + % files 'by eye' using Neuroscope + switch valid_sites_reordered(i_row) % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps + case 0 + ax.XColor = 'r'; % Red % marks bad channels within specified trial + ax.YColor = 'r'; % Red + % ax.ylabel = 'k'; + case 1 + ax.XColor = 'k'; % black % marks good channels within specified trial + ax.YColor = 'k'; % black + % ax.ylabel = 'k'; + case 2 + ax.XColor = 'b'; % blue % marks channels as 'variable' and could be good for portions of the whole amplifier.dat file but bad for others. Thus some channels may be good for only some trials, not all. + ax.YColor = 'b'; + % ax.ylabel = 'k'; + otherwise + ax.XColor = 'b'; % blue % catch in case the data was not input into the structure + ax.YColor = 'b'; + % ax.ylabel = 'k'; + end + end + set(gcf, 'WindowState', 'maximize'); % maximizes the window so that it exports the graphics with appropriate font size + + % Gives the whole plot page a name + A=cell(1,5); + A{1} = ['Subject: ' ratID]; + A{2} = ['Session: ' session_name]; + A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; + A{4} = ['Trial Number: ' num2str(trial_idx)]; + A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; + + sgtitle(A, 'Interpreter','none'); + + if i_trial == 1 + exportgraphics(gcf, trials_plot_full_name); + else + exportgraphics(gcf, trials_plot_full_name, 'append', true); %ADD APPEND FLAG HERE + end + close; + end + end + end +end From fd9e08afec7fadfab078738f38b8a74364f7e824 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Thu, 5 Jan 2023 08:48:42 -0500 Subject: [PATCH 07/19] updates --- ...ipt_generate_trials_structure_bad_data.asv | 282 ------------ ...nerate_trials_structure_bad_data_plots.asv | 405 ------------------ 2 files changed, 687 deletions(-) delete mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv delete mode 100644 LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv deleted file mode 100644 index 6ac8b316..00000000 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.asv +++ /dev/null @@ -1,282 +0,0 @@ -% script to write field potentials around each trial - -% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; - -intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); - -%% -fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc -num_trials_to_plot = 5; - -% start with an LFP file -% get the trial structure for that session -% run this analysis - -trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) - -switch lower(trialType) - case 'allgo' - eventFieldnames = {'centerIn'}; - case 'correctgo' - eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; -end - - % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', - % 'foodretrievel'}; This is the full eventlist for a correctGo trial. - % Choose one for generating event_triggered_lfps. -num_events = length(eventFieldnames); -t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct - - -% lists for ratID probe_type -NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type -ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; - -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; -sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; -sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; -% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? - -naming_convention; % for labeling graphs - -% choiceTask difficulty levels -choiceRTdifficulty = cell(1, 10); -choiceRTdifficulty{1} = 'poke any'; -choiceRTdifficulty{2} = 'very easy'; -choiceRTdifficulty{3} = 'easy'; -choiceRTdifficulty{4} = 'standard'; -choiceRTdifficulty{5} = 'advanced'; -choiceRTdifficulty{6} = 'choice VE'; -choiceRTdifficulty{7} = 'choice easy'; -choiceRTdifficulty{8} = 'choice standard'; -choiceRTdifficulty{9} = 'choice advanced'; -choiceRTdifficulty{10} = 'testing'; - -%% -for i_rat = 1 : length(rats_with_intan_sessions) - - intan_folders = rats_with_intan_sessions(i_rat).intan_folders; - - for i_sessionfolder = 1 : length(intan_folders) - % extract the ratID and session name from the LFP file - session_path = intan_folders{i_sessionfolder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); - session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); - ratID = rd_metadata.ratID; - intan_session_name = rd_metadata.session_name; - session_name = rd_metadata.session_name; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end - - -% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... -% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - - -% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') -% continue; -% end - - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); - end - - probe_channel_info = load_channel_information(fname, sheetname); - [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); - -% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; -% if ~exist(trials_structure, 'dir') -% mkdir(trials_structure); -% end - - trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; - if ~exist(trials_structure_plots, 'dir') - mkdir(trials_structure_plots); - end - - processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; - if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') - mkdir(processed_graphFolder_LFP_eventFieldname); - end - - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathersing logData information - - % calculate nexData, need digital input and analog input files - digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); - analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); - rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); - - if ~exist(digin_fname, 'file') - sprintf('no digital input file for %s', session_folder); - continue - end - - if ~exist(analogin_fname, 'file') - sprintf('no analog input file for %s', session_folder); - continue - end - - if ~exist(rhd_fname, 'file') - sprintf('no rhd info file for %s', session_folder); - continue - end - - % read in rhd info; requires 'info.rhd' file. - rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); - - % read digital input file - dig_data = readIntanDigitalFile(digin_fname); - if ~isfield(rhd_info, 'board_adc_channels') - sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) - continue - end - - analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); - nexData = intan2nex(dig_data, analog_data, rhd_info); - - try - sprintf('attempting to create trials structure for %s', session_folder) - trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); - catch - sprintf('could not generate trials structure for %s', session_folder) - continue - end - - % extract Trial Type (e.g. correctGo) - % Set trialType at beginning of file - [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here - trIdx = extractTrials(trials, trialEventParams); - num_trials = length(trIdx); - - %Getting the LFP-fname - pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - - lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); - lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) - Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop - - % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. - % sessions_to_ignore doesn't seem to be working here so using this - % catch instead - lfp_data_num_rows = size(lfp_data.lfp,1); - if lfp_data_num_rows < 64 - continue; - end - - % Order the lfps here - [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) - - %find the column header that matches session_name (session_name and - %the column headers should match for each session to pull in the - %info for probe site health - valid_sites_reordered = channel_information.(session_name); - %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - - % Generate event triggered LFPs - for i_event = 1 : num_events - % write code here to get event_triggered_lfps_ordered - % for each separate event - - % create a filename to save the trials_structure - trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - -% if exist(trials_full_name, 'file') -% continue -% end - - % Cath for troubleshooting the data to NOT run through all of the folders and - % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. - % It will simply generate one trial per session. - - % this function adds 2 fields to the trials structure to identify bad sites - trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? - - event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data - tpoints_per_event = size(event_triggered_lfps, 3); - t = linspace(t_win(1), t_win(2), tpoints_per_event); - - trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); - save(trials_full_name, 'trials_validchannels_marked'); - -% % at this point, event_triggered_lfps_ordered is an m x n x p array where -% % m is the number of events (i.e., all the cueon OR nosein OR other... -% % events) in a single session; n is the number of channels in that session -% % (generally 64), and p is the number of time samples extracted around each -% % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). - - % above here, the lfp file, trial structure never change - - % create a filename to save the plots - trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); - -% % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. -% % num_channels = size(event_triggered_lfps,2); -% num_trials = size(event_triggered_lfps, 1); -% - % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). - - end - end -end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv deleted file mode 100644 index c774079b..00000000 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data_plots.asv +++ /dev/null @@ -1,405 +0,0 @@ -% script to write field potentials around each trial - -% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; - -intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; -rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); -valid_trials_original_folder = find_trials_struct_original_folders(intan_parent_directory); - -%% -fname = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary\Rat_Information_channels_to_discard.xlsx'; % for channels to ignore based on visualizing in Neuroscope etc -num_trials_to_plot = 5; - -% start with an LFP file -% get the trial structure for that session -% run this analysis - -trialType = ('allgo'); % to pull out trIdx of the trials structure (all trials) - -switch lower(trialType) - case 'allgo' - eventFieldnames = {'centerIn'}; - case 'correctgo' - eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; -end - - % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', - % 'foodretrievel'}; This is the full eventlist for a correctGo trial. - % Choose one for generating event_triggered_lfps. -num_events = length(eventFieldnames); -t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct - - -% lists for ratID probe_type -NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type -ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; - -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; -sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; -sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; -% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? - -naming_convention; % for labeling graphs - -% choiceTask difficulty levels -choiceRTdifficulty = cell(1, 10); -choiceRTdifficulty{1} = 'poke any'; -choiceRTdifficulty{2} = 'very easy'; -choiceRTdifficulty{3} = 'easy'; -choiceRTdifficulty{4} = 'standard'; -choiceRTdifficulty{5} = 'advanced'; -choiceRTdifficulty{6} = 'choice VE'; -choiceRTdifficulty{7} = 'choice easy'; -choiceRTdifficulty{8} = 'choice standard'; -choiceRTdifficulty{9} = 'choice advanced'; -choiceRTdifficulty{10} = 'testing'; - -%% - %Testing just loading in the trials structure here - -for i_ratfolder = 1 : length(rats_with_intan_sessions) - - session_trials_struct_folders = valid_trials_original_folder(i_ratfolder).trials_folders; - intan_folders = rats_with_intan_sessions(i_ratfolder).intan_folders; - - for i_sessionfolder = 1 : length(intan_folders) - % extract the ratID and session name from the LFP file - session_path = intan_folders{i_sessionfolder}; - rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); - session_trials_folder = create_trials_structure_data_folder(rd_metadata, intan_parent_directory); - ratID = rd_metadata.ratID; - pd_trials_data = parse_trials_struct_folder(session_path); - intan_session_name = rd_metadata.session_name; - session_name = rd_metadata.session_name; - - if any(strcmp(session_path, sessions_to_ignore)) % can't quite get this to debug but seems ok - it keeps running these sessions and catching errors (hence the need to skip them!) - continue; - end - -% if contains(ratID, NN8x8) || contains(ratID, ASSY156) % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - -% if contains(ratID, 'R0326') || contains(ratID, 'R0372') || contains(ratID, 'R0376')... -% || contains(ratID, 'R0374') || contains(ratID, 'R0378') || contains(ratID, 'R0379') % just trying to skip some lines of data to get to the last set to debug. Uncomment out to run more trialTypes -% continue; -% end - - -% if contains(ratID, NN8x8)|| contains(ratID, ASSY156)|| contains(ratID, 'R0420')|| contains(ratID, 'R0425') -% continue; -% end - - if contains(ratID, 'R0328') || contains(ratID, 'R0327') || contains(ratID, 'R0411') || contains(ratID, 'R0456') % the first style it wouldn't skip these sessions so trying it as the 'intan' name instead of just the rawdata folder name. - continue; % R0328 has no actual ephys; using these lines to skip unneeded data. R0327 Can't create trials struct; R0420 I haven't added lines for - end - - if contains(session_name, sessions_to_ignore) || contains(session_name, sessions_to_ignore1) || contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files - continue; - end - - % Load trials structure - for i_trialsfolder = 1:length(session_trials_struct_folders) - session_trials_structure = fullfile(intan_parent_directory, ratID, [ratID '-LFP-trials-structures-original'], session_name); - session_trials = find_trials_mat(session_trials_structure); - trials_structure_file = dir(fullfile(session_trials)); - trials_structure_fname = fullfile(trials_structure_file.folder, trials_structure_file.name); - trials_structure = load(trials_structure_fname); - trials = trials_structure.trials; - end - parentFolder = fullfile(intan_parent_directory, ... - ratID, ... - [ratID '-processed']); - - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % load_channel_information - this file is coded 0 = bad, 1 = good, - % 2 = variable for data in each channel for each session_name for - % each rat_ID. Use the opts.VariableNamesRange for eat ratID to - % detectImportOptions otherwise there's an error due to different - % session number for each rat - sheetname = ratID; - if contains(ratID, 'R0326') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:H1', 'datarange', 'A2:H65', 'sheet', sheetname); - elseif contains(ratID, 'R0327') || contains(ratID, 'R0374') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:E1', 'datarange', 'A2:E65', 'sheet', sheetname); - elseif contains(ratID, 'R0372') || contains(ratID, 'R0378')|| contains(ratID, 'R0396') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:J1', 'datarange', 'A2:J65', 'sheet', sheetname); - elseif contains(ratID, 'R0379') || contains(ratID, 'R0413') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:L1', 'datarange', 'A2:L65', 'sheet', sheetname); - elseif contains(ratID, 'R0376') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:O1', 'datarange', 'A2:O65', 'sheet', sheetname); - elseif contains(ratID, 'R0394') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:G1', 'datarange', 'A2:G65', 'sheet', sheetname); - elseif contains(ratID, 'R0395') || contains(ratID, 'R0427') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:K1', 'datarange', 'A2:K65', 'sheet', sheetname); - elseif contains(ratID, 'R0412') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:M1', 'datarange', 'A2:M65', 'sheet', sheetname); - elseif contains(ratID, 'R0419') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:P1', 'datarange', 'A2:P65', 'sheet', sheetname); - elseif contains(ratID, 'R0420') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:N1', 'datarange', 'A2:N65', 'sheet', sheetname); - elseif contains(ratID, 'R0425') - opts = detectImportOptions(fname, 'filetype', 'spreadsheet', 'VariableNamesRange', 'A1:V1', 'datarange', 'A2:V65', 'sheet', sheetname); - end - - probe_channel_info = load_channel_information(fname, sheetname); - [channel_information, intan_site_order, site_order] = channel_by_probe_site_ALL(probe_channel_info, probe_type); - -% trials_structure = [parentFolder(1:end-9) 'LFP-trials-structures']; -% if ~exist(trials_structure, 'dir') -% mkdir(trials_structure); -% end - - % Graphs in this folder are WITH calculating an outlier threshold. - trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; - if ~exist(trials_structure_plots, 'dir') - mkdir(trials_structure_plots); - end - - % Graphs in this folder are grandfathered in BEFORE I calculated a specific outlier threshold and just using by eye on Neuroscope. - processed_graphFolder_LFP_eventFieldname = [parentFolder(1:end-9) 'LFP-eventFieldname-graphs']; - if ~exist(processed_graphFolder_LFP_eventFieldname, 'dir') - mkdir(processed_graphFolder_LFP_eventFieldname); - end - -% % Start of generation of trials structure - [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); % even with loading in trials structure, still need logData but it is quick to load. - session_log = find_session_log(session_folder); - - if isempty(session_log) - sprintf('no log file found for %s', session_folder) - end - - logData = readLogData(session_log); %gathering logData information -% -% % calculate nexData, need digital input and analog input files -% digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); -% analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); -% rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); -% -% if ~exist(digin_fname, 'file') -% sprintf('no digital input file for %s', session_folder); -% continue -% end -% -% if ~exist(analogin_fname, 'file') -% sprintf('no analog input file for %s', session_folder); -% continue -% end -% -% if ~exist(rhd_fname, 'file') -% sprintf('no rhd info file for %s', session_folder); -% continue -% end -% -% % read in rhd info; requires 'info.rhd' file. -% rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); -% -% % read digital input file -% dig_data = readIntanDigitalFile(digin_fname); -% if ~isfield(rhd_info, 'board_adc_channels') -% sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) -% continue -% end -% -% analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); -% nexData = intan2nex(dig_data, analog_data, rhd_info); -% -% try -% sprintf('attempting to create trials structure for %s', session_folder) -% trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); -% catch -% sprintf('could not generate trials structure for %s', session_folder) -% continue -% end -% % End of calculating trials structure (original without threshold info) - - - - % extract Trial Type (e.g. correctGo) - % Set trialType at beginning of file - [ trialEventParams ] = getTrialEventParams(trialType); % Need to verify this section. Working Here - trIdx = extractTrials(trials, trialEventParams); - num_trials = length(trIdx); - - %Getting the LFP-fname - pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); - - lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); - lfp_data = load(lfp_fname); % Load in the LFP data for rearranging LFP data (ordering it by probe_type) - Fs = lfp_data.actual_Fs; % need the Fs loaded in for gathering event_triggered_lfps in the next 'for' loop - - % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. - % sessions_to_ignore doesn't seem to be working here so using this - % catch instead - lfp_data_num_rows = size(lfp_data.lfp,1); - if lfp_data_num_rows < 64 - continue; - end - - % Order the lfps here - [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); - % Orders the lfps by probe site mapping (double check the single file to remove catches for loading in single data) - - %find the column header that matches session_name (session_name and - %the column headers should match for each session to pull in the - %info for probe site health - valid_sites_reordered = channel_information.(session_name); - %channel_descriptions = find(probe_channel_info.Properties.VariableNames, session_name); - - % Generate event triggered LFPs - for i_event = 1 : num_events - % write code here to get event_triggered_lfps_ordered - % for each separate event - - % % create a filename to save the trials_structure - trials_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_full_name = fullfile(session_trials_folder, trials_fname_to_save); - - - % Cath for troubleshooting the data to NOT run through all of the folders and - % create the data if the plots are already made. This will not create 5 pages of 5 different random trials. - % It will simply generate one trial per session. - - % this function adds 2 fields to the trials structure to identify bad sites - trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames{i_event}); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? - - event_triggered_lfps = extract_event_related_LFPs(ordered_lfp, trials(trIdx), eventFieldnames{i_event}, 'fs', Fs, 'twin', t_win); % made this using ordered_lfp data - tpoints_per_event = size(event_triggered_lfps, 3); - t = linspace(t_win(1), t_win(2), tpoints_per_event); - - trials_validchannels_marked = identify_bad_data(lfp_data, trials(trIdx), intan_site_order_for_trials_struct, probe_type, trialEventParams, eventFieldnames); - save(trials_full_name, 'trials_validchannels_marked'); - - % % at this point, event_triggered_lfps_ordered is an m x n x p array where - % % m is the number of events (i.e., all the cueon OR nosein OR other... - % % events) in a single session; n is the number of channels in that session - % % (generally 64), and p is the number of time samples extracted around each - % % event (i.e., p = 2001 if we extract +/- 2 seconds around each event). - - % above here, the lfp file, trial structure never change - - % create a filename to save the plots - trials_plot_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'trials', '.pdf')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually - trials_plot_full_name = fullfile(trials_structure_plots, trials_plot_fname_to_save); - - % % pts_per_event = size(event_triggered_lfps,3); % I think these lines need to go into the for loop for whenever a set of data is loaded into the workspace. - % % num_channels = size(event_triggered_lfps,2); - % num_trials = size(event_triggered_lfps, 1); - % - % catch for num_trials_to_plot < num_trials (this is specifically for R0420_20220714 since it did only 3 trials so can't graph 5 random trials). - if num_trials < num_trials_to_plot - continue; - end - - % select trials for plotting at random - trial_idx_to_plot = randperm(num_trials, num_trials_to_plot); % create a catch if num_trials_to_plot < num_trials, continue. - - for i_trial = 1:num_trials_to_plot - trial_idx = trial_idx_to_plot(i_trial); - channel_lfps = squeeze(event_triggered_lfps(trial_idx,:, :)); - % trials, create a 64channel graph for each trial? - - % Plot the data - figure; - num_rows = size(event_triggered_lfps,2); - LFPs_per_shank = num_rows/ 8; % will be 8 for 64 channels, 7 for 56 channels (diff) - for i_row = 1 : num_rows - - y_lim = [-2500, 2500]; - plot_col = ceil(i_row / LFPs_per_shank); - plot_row = i_row - LFPs_per_shank * (plot_col-1); - plot_num = (plot_row-1) * 8 + plot_col; - - subplot(LFPs_per_shank,8,plot_num); - - % sue the trials structure data - % (trials_validchannels_marked.is_channel_valid_ordered) - % to color the actual plots based on good or - % bad sites above the specified threshold (1500mV, check the script to verify) - % switch trials_validchannels_marked(i_trial).is_channel_valid_ordered(i_row) - switch trials_validchannels_marked(trial_idx).is_channel_valid_ordered(i_row) - % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps - case 0 - plot_color = 'r'; % marks bad channels within specified trial - case 1 - plot_color = 'k'; % marks good channels within specified trial - otherwise - plot_color = 'b'; % catch in case the data was not input into the structure - end - - plot_channel_lfps = plot(t, channel_lfps(i_row, :), plot_color); % change to log10 -- plot(f, 10*log10(power_lfps(:,1))) - set(gca, 'ylim',y_lim); - grid on - - % give titles to each subplot - if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly - caption = sprintf('NN8x8 #%d', site_order(i_row)); - elseif contains(ratID, ASSY156) - caption = sprintf('ASSY156 #%d', site_order(i_row)); - elseif contains(ratID, ASSY236) - caption = sprintf('ASSY236 #%d', site_order(i_row)); - end - title(caption, 'FontSize', 8); - - if plot_row < LFPs_per_shank - set(gca,'xticklabels',[]) - end - - if plot_col > 1 - set(gca,'yticklabels',[]) - end - - ax = gca; - % This section is coded to color the axes of - % the plots when checking the amplifier.dat - % files 'by eye' using Neuroscope - switch valid_sites_reordered(i_row) % make sure is_valid_lfp is a boolean with true if it's a good channel; make sure this is in the same order as channel_lfps - case 0 - ax.XColor = 'r'; % Red % marks bad channels within specified trial - ax.YColor = 'r'; % Red - % ax.ylabel = 'k'; - case 1 - ax.XColor = 'k'; % black % marks good channels within specified trial - ax.YColor = 'k'; % black - % ax.ylabel = 'k'; - case 2 - ax.XColor = 'b'; % blue % marks channels as 'variable' and could be good for portions of the whole amplifier.dat file but bad for others. Thus some channels may be good for only some trials, not all. - ax.YColor = 'b'; - % ax.ylabel = 'k'; - otherwise - ax.XColor = 'b'; % blue % catch in case the data was not input into the structure - ax.YColor = 'b'; - % ax.ylabel = 'k'; - end - end - set(gcf, 'WindowState', 'maximize'); % maximizes the window so that it exports the graphics with appropriate font size - - % Gives the whole plot page a name - A=cell(1,5); - A{1} = ['Subject: ' ratID]; - A{2} = ['Session: ' session_name]; - A{3} = ['Task Level: ' choiceRTdifficulty{logData.taskLevel+1}]; - A{4} = ['Trial Number: ' num2str(trial_idx)]; - A{5} = ['EventFieldname and Trial Type: ' eventFieldnames{i_event} '_' trialType]; - - sgtitle(A, 'Interpreter','none'); - - if i_trial == 1 - exportgraphics(gcf, trials_plot_full_name); - else - exportgraphics(gcf, trials_plot_full_name, 'append', true); %ADD APPEND FLAG HERE - end - close; - end - end - end -end From 3025acbb756cb0bde2a1f31a452d73af8cb6ccbe Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Fri, 5 May 2023 16:47:39 -0400 Subject: [PATCH 08/19] updating --- Analysis/sum_session_correct_trials.m | 7 + .../utils/probe_site_mapping_all_probes_DL.m | 159 ++++++++++++++++++ .../utils/ratID_by_probe_type.xlsx | Bin 9385 -> 9495 bytes .../~$P_Analysis_Workflow.docx | Bin 0 -> 162 bytes .../script_extract_power_spectra.asv | 128 ++++++++++++++ .../script_extract_power_spectra.m | 41 ++++- 6 files changed, 328 insertions(+), 7 deletions(-) create mode 100644 Analysis/sum_session_correct_trials.m create mode 100644 LFPs/Analysis_code_JM/utils/probe_site_mapping_all_probes_DL.m create mode 100644 LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx create mode 100644 silicon_probe_LFP_analysis/script_extract_power_spectra.asv diff --git a/Analysis/sum_session_correct_trials.m b/Analysis/sum_session_correct_trials.m new file mode 100644 index 00000000..d30b3c95 --- /dev/null +++ b/Analysis/sum_session_correct_trials.m @@ -0,0 +1,7 @@ +AllTrials = vertcat(trials.correct); +tone = vertcat(trials.tone); +C = [AllTrials tone]; +indices = find(C(:,1)==0); +C(indices,:) = []; +tone2 = sum( C(:,2)==2 ); +tone1 = sum( C(:,2)==1 ); \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/probe_site_mapping_all_probes_DL.m b/LFPs/Analysis_code_JM/utils/probe_site_mapping_all_probes_DL.m new file mode 100644 index 00000000..8a520562 --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/probe_site_mapping_all_probes_DL.m @@ -0,0 +1,159 @@ +function intan_to_site_map_DL = probe_site_mapping_all_probes_DL(probe_type) + +% INPUTS: + % probe_type - this current mapping is for the NeuroNexus H64LP A8x8 probe. +% OUTPUTS: + % intan_to_site_map - structure containing reorganization of the lfp_amplifier + % variable ordering each shank from ventral to dorsal + +if strcmpi(probe_type, 'nn8x8') + %this is how the lfp.mat file is organized + % lfp_organization = [1:64]; + + %shank number - organized based on lfp.mat files generated in -processed + %folders to match the intan_ampflier number; remember Intan_amplifer + %numbers are 0:63, while matlab (aka .mat files) are 1:64 + % DL - this maps the numbering on the NeuroNexus omnetics connector to + % the numbering on the Intan amplifier + + % NOTE: site 35 is entered twice in the matrix below + intan_amplifier = [49:56,...%shank1, nn sites 1-8 + 57:64,...%shank2 + 33:35, 37:39, 41:42,...%shank3 + 35,40,43:48,...%shank4 + 17:22,26,30,...%shank5 + 23:25, 27:29, 31:32,...%shank6 + 1:8,...%shank7 + 9:16]; %shank8 + + intan_amplifier_DL = [49, 48, 51, 50, 53, 52, 55, 54, ... + 57, 56, 59, 58, 61, 60, 63, 62, ... + 32, 33, 34, 36, 37, 38, 40, 41, ... + 42, 44, 45, 46, 47, 43, 39, 35, ... + 29, 25, 21, 17, 16, 19, 18, 20, ... + 23, 22, 24, 27, 26, 28, 31, 30, ... + 00, 01, 02, 03, 04, 05, 06, 07, ... + 08, 09, 10, 11, 12, 13, 14, 15]; + % above is the actual intan channel numbers. Add one because Matlab + % starts indexing at 1. Note that if this were ported to Python, would + % NOT want to add 1 here + intan_amplifier_DL = intan_amplifier_DL + 1; + + +% Map sites ventral to dorsal on the NeuroNexus H64LP A8x8 probe. +% THIS SECTION ORDERS THE NN-SITE BASED ON THE ACTUAL AMPLIFIER ORDER FROM +% THE LFP.MAT FILE OR REARRANGE FROM LINE 14-21 ABOVE. +% DL - this maps the ordering on the NN shank to the NN omnetics connector. +% Therefore, intan_amplifier(NNsite_order) gives the row in the original +% LFP file that corresponds to spatially ordered sites from VENTRAL to +% DORSAL + NNsite_order = [2,7,1,8,4,5,3,6,... %shank 1 + 10,15,9,16,12,13,11,14,... %shank2 + 17,24,18,23,19,22,20,21,...%shank3 + 27,25,29,26,30,28,31,32,...%shank4 + 40,37,39,35,38,36,34,33,...%shank5 + 42,47,41,48,43,46,45,44,...%shank6 + 49,56,50,55,51,54,52,53,...%shank7 + 57,64,58,63,59,62,60,61]; %shank8 + + NNsite_order_DL = [05, 04, 06, 03, 07, 02, 08, 01, ... + 13, 12, 14, 11, 15, 10, 16, 09, ... + 21, 20, 22, 19, 23, 18, 24, 17, ... + 29, 28, 30, 27, 31, 26, 32, 25, ... + 37, 36, 38, 35, 39, 34, 40, 33, ... + 45, 44, 46, 43, 47, 42, 48, 41, ... + 53, 52, 54, 51, 55, 50, 56, 49, ... + 61, 60, 62, 59, 63, 58, 64, 57]; + +% % Map sites ventral to dorsal on the NeuroNexus H64LP A8x8 probe. +% THIS CHUNK OF CODE IS THE LITERAL NEURONEXUS NUMBERS VENTRAL TO DORSAL ORDER. +% NNsite_order = [1,8,2,7,3,6,4,5,... %shank 1 +% 9,16,10,15,11,14,12,13,... %shank2 +% 17,24,18,23,19,22,20,21,...%shank3 +% 25,32,26,31,27,30,28,29,...%shank4 +% 33,40,34,39,35,38,36,37,...%shank5 +% 41,48,42,47,43,46,44,45,...%shank6 +% 49,56,50,55,51,54,52,53,...%shank7 +% 57,64,58,63,59,62,60,61];%shank8 + + intan_to_site_map = intan_amplifier(NNsite_order)'; % THIS IS VENTRAL TO DORSAL + intan_to_site_map_DL = intan_amplifier_DL(NNsite_order_DL)'; % THIS IS DORSAL TO VENTRAL + +elseif strcmpi(probe_type, 'assy156') + % Per Jen, Intan chip is facing down on the ASSY-156 probe, but this + % numbering suggests the chip was facing up. This doesn't seem to match + % with the way she did the NN mapping; for example, site 1 from + % Cambridge DOES NOT map to site 0 intan. I redid the mapping and they + % seem to match other than the duplication of site 36 in + % Cambridge156_order + intan_amplifier = [1:17,19:32,63,...% Shank A + 18,33:62, 64]; % Shank B + intan_amplifier_DL = [47, 46, 45, 44, 43, 42, 41, 40, ... + 39, 38, 37, 36, 35, 34, 33, 32, ... + 31, 30, 29, 28, 27, 26, 25, 24, ... + 23, 22, 21, 20, 19, 18, 17, 16, ... + 15, 14, 13, 12, 11, 10, 09, 08, ... + 07, 06, 05, 04, 03, 02, 01, 00, ... + 63, 62, 61, 60, 59, 58, 57, 56, ... + 55, 54, 53, 52, 51, 50, 49, 48]; + intan_amplifier_DL = intan_amplifier_DL + 1; + + Cambridge156_order_DL = [26, 35, 33, 24, 37, 28, 41, 39, ... + 27, 40, 29, 50, 47, 32, 19, 44, ... + 23, 36, 38, 25, 34, 21, 22, 43, ... + 30, 20, 45, 17, 48, 18, 46, 42, ... + 12, 53, 04, 14, 51, 03, 15, 01, ... + 31, 49, 06, 57, 58, 62, 07, 11, ... + 16, 02, 52, 13, 56, 54, 08, 61, ... + 63, 10, 59, 55, 05, 09, 60, 64]; + % note site 36 is entered twice in the matrix below +% Cambridge156_order = [22,14,16,24,12,20,8,10,...% Shank A. This is verified JM 11/5/2022 +% 21,9,19,32,2,17,29,5,... +% 25,13,11,23,36,27,26,6,... +% 18,28,4,31,1,30,3,7,... +% 38,61,46,36,63,47,35,49,...% Shank B +% 33,64,44,57,56,52,43,39,... +% 34,48,62,37,58,60,42,53,... +% 51,40,55,59,45,41,54,50]; + + % THIS GOES FROM DORSAL TO VENTRAL - DL +% intan_to_site_map = intan_amplifier(Cambridge156_order)'; + intan_to_site_map_DL = intan_amplifier_DL(Cambridge156_order_DL)'; + +elseif strcmpi(probe_type, 'assy236') + + % see Cambridge Neurotech Mini-Amp-64 User Guide + intan_amplifier_DL = [41, 39, 38, 37, 35, 34, 33, 32, ... + 29, 30, 28, 26, 25, 24, 22, 20, ... + 46, 45, 44, 43, 42, 40, 36, 31, ... + 27, 23, 21, 18, 19, 17, 16, 14, ... + 55, 53, 54, 52, 51, 50, 49, 48, ... + 47, 15, 13, 12, 11, 09, 10, 08, ... + 63, 62, 61, 60, 59, 58, 57, 56, ... + 07, 06, 05, 04, 03, 02, 01, 00]; + intan_amplifier_DL= intan_amplifier_DL + 1; + + % verified order below + Cambridge236_order_DL = [64, 48, 16, 61, 13, 60, 29, 12, ... + 59, 32, 42, 24, 09, 57, 44, 45, ... + 47, 14, 31, 62, 15, 63, 46, 30, ... + 58, 27, 10, 26, 25, 43, 28, 11, ... + 34, 18, 54, 23, 07, 38, 22, 40, ... + 56, 08, 52, 05, 17, 03, 51, 50, ... + 41, 55, 20, 36, 06, 39, 49, 19, ... + 01, 35, 04, 21, 53, 33, 37, 02]; +% intan_amplifier = [1:32,...% Shank A % Verified 11/5/2022 JM +% 33:64]; % Shank B +% Cambridge236_order = [1,9,21,4,26,5,20,27,...% Shank A % Verified 11/5/2022 +% 6,15,16,32,30,8,13,12,... +% 11,25,17,3,23,2,10,18,... +% 7,22,31,24,28,14,19,29,... +% 54,46,59,37,34,51,41,49,...%shankB +% 57,33,61,36,47,39,62,63,... +% 48,58,44,53,35,50,64,45,... +% 42,55,38,43,60,56,52,40]; + +% intan_to_site_map = intan_amplifier(Cambridge236_order)'; + intan_to_site_map_DL = intan_amplifier_DL(Cambridge236_order_DL)'; +end +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/utils/ratID_by_probe_type.xlsx b/LFPs/Analysis_code_JM/utils/ratID_by_probe_type.xlsx index 3bcc50b70e9cefce2fee8d89530db84858b546ea..560c51d4f3deff7e1173540e02532e74a4f4123d 100644 GIT binary patch delta 4707 zcmZ8lcQo8v*B(UgMxTgbjNVJMtC#3CIw86cBclfKV?-y!=sg&M=#l7ACniGFBzh1n zdMDbOd%v~r_r2f#W3P42-s}9a&o0liE3`9p>OK(x@5ZQC(+NNz90>?S4FZ9JyhH*K zNKZ!u!c#ctvDX_jW5kjSO_@n}MU`7DNrP_9t315& zYFFBT-8-UK?&kr8Tg!5i9eH}tx3*V8>FFI=he&`i^2rGbAj_} zyJ%MMBWF}zBbc72yC%@Y>WZGZ_R_KLmkPUASktKZ7Ke9!wuH;S2?}hfF8du{j&6N z0DGoJcCsehOo3}6eD<(4n#a8OM%(-fY<@#YQDU#z3$4}^z~kCQyU)kvI?dZ6EDhLg zHdsq5J720=@JlDQVkD)ZSKe)z zzr>@L$)9H&WR;lhLKe`+rnF?DEKc+kzSU2e8(-KL#0t=XSLb4eHps#yB0xLCQiuLzh zpxqqEZp>U8W=oa;`~C2k+b`bruDE@EeZsQ^7E75IDJ#Ew2M$U$`c#MMV;Zj-m8f@w$ntmOK8+Pxd!ebFcjqa= z?I=@`Fj!UZLg>N4!SX23|;^4&Ow(=qUwkLwqF`5*2IHmGWm&b2b&)AB; zY(x$3FGsyte1Gm3_G)*|uRb_l#Q)A0p3$>)#EnzHR#|Ycm!w;u)Q58j`XvE9dYY4} zF_R3APt_TOYP|VV!d$c<5Hkp^2xA5E(7MUFqV!Rx>A%?pcjF@d;x0-VxnFUiuErVP{L%YCc@gxcRT z)yZ4a$EAA|6}kBwJ-y!V-E!X=o&*&@Up*nL?m+lr^Iog?N{b3fHk+_iwR{BbwYk(Z zbq(&ot1VeSg3DUG+zkh|VHBojCS9LmJEF0tH01FiZx$vS{F!nXlYdCQZ+iwIEwNGe zDowqfRpA@u1m^By50ZL14RNvL$cCWOAS#i&bC>z(j2>1uekEn`P0vn*k`v4Fl1}UH z4Tqk%BO{f#*AL3{&e~GvP!|9r{e3UL4#&W#m^pOXAh=#wZg$%cJt=7|!oBI9hA}jL z*Ejg+Epw-HVFr5C=Q4BH4b#U)Wk*YHredEO`qF?e_e(42D$U0af$cjSk~V_=Riv$| zJ+Ow&vZLu-x}T`^jTAqXT!gyr7A7UnHEVyNgZ#xP%1&Yag-F<@@Hk*E$oFa~WaUH7 zvRlf`bjd!mJf$&i@Q^I8E3x<(%0^r%N=6$5w~j8Pl)xH3t8X~+S5afTzP%JMda5&< zU=VleRI7)Lcxno+51e1Ozp-e$Bi9D}>CQJd|ERRg$KEJq8s%EY6HpXOUoA*GiHRev z^n({nb7m$m&<*I7i!74>Vn=xp{aa4%WnZ4O7yR~IkjkvR_%$ZyQ?=2iWOzM^H}{M9 z>y^*hnL^UIXhChYz(QSsoy4sZg|2;p>qy*(kj+nJ&HnmgTuaSd4%}q5c^&hZQ=+U8 zd!UnF~BzQk!F{;e6HHVAo6_9t`JTV;!4?gDo*e{gBoIZPBs>ogJ z+%XwklA1e4L@&&3?}c=fL`qHyja54#TL%BWKZs5f=FW7|alDV5an{^+L}oK{X~LzC zDLsBWBB!$YUjHoX;z)APD}eR7*_n1+w)3&=jBWMFLNEKu#1|X%&Wh#SD-BA|7Kn8E=$_wzoriXU&Qc%WSkGMt&k96zZ}#HHsYRe)_tfzh+e2XzUF)!ORotnM zxT905p3QajV$sN+0*A4r<9mcidRb@#JW7b^4 z&t1ILnJan+Mw%RIecRWMBG}3LO`1-VW1`kl2x+{^_A%~xVx9DT{;O@wfnwB0buuZ@ z;!yhvYzFWg`+|CqjDxXQw{d|huJ%HSmeyJEO6F0r{cNYDx=l7sI>ec> zCE^ItpeI%z&YOj1-7O##s zscY{5XoF{TB6^pDg&#uCFW75MsRf4Z_LpXOL<$w3?$22O*GJ!9bqtM0kg}&Tlkc)B zo_IGfGp^UMv+s>-Q^3>(N$DfJV}5le3Iacx2#bYniD!h{hay~Ty9N*2GO90V3w4*W z&L7d+bSYrnW1f@~)Ks=mP*bnrCKO}~bDMKX*jiS1iu=fX07ZgexN!O$iH+-g5${X) zc(9|T&-QIeYsc}J8>>zbIui2d9LVYL0cl#*FpH3A!)#y#f7u&Qng<+>mq0URcRaHyNv&3tau&T|@ zHNKX$v`1B4qC0iFqZ(eY7OoiK{I*yz@RU=`97(@K`4Cr}-j>@EjS2lz=`6qQ)2t4) z35h;DIHdPku7kiVf*WO{TvMj~6hOU3tj^L74rWbVJW=5xX|pUFa!Rn9$&+a;ktnpT z=tvOL_~@QkAGj$IL&$cwF|+{k432L;)m_uqirTU@`$EcS#9h(qn$H;+S7#EyZa760 za>B?H>lTs9ysw{At1?kN5oJ28jrq2*K62{;%;;LBQzjp27fuChxyXGx55%VU2UNH% z4u2zjzjS&xgyLjnZhS{KrMo->&k^ukprCEy9ss+>7IpcI3dLG3e$kj{sq9}hXo>6a zI22WW=sYPerafRfi8#T5mUMbGB(vN+vuxT%eOkOnOL~R`MhOd|9c~!+ zYAJMillxRl=rBzH$Y|q`E}1{0sW<0Bq9E>$;)MF`%Nh1n(LPn;s*M>+5ii6-6Wvne zRXhASw@&I1z%hFC$d7$Vc}xp*`aauUv4R`VXoG1iVgIov%{Lz=Ii*C)P<@{etq4Y;9P56P2GeV z=a=_E4Cda;05lZi2ROm;wEj)WH!|{&CVlx{RM(#R+%#+~I?Ipzr^JBKm z_00oE{h`K?8j+pB^dzR!2blXc!GvcP6=!$w@LTPxC~_uU%gx=*XChTcHYLf1ysJ&u zCtHu_i@s4phPnwBC2613g zKa2c$MEH35L<#garf%e8b|9cK87UZI#{+?M|6po*P%0NA;DsJC=!4R0o^p2*Jlx$g z)v-~_W=@LBwes^@{N#`@&Mh>dI`nzQMglTE504pCScob*S$lO)DS#|L5bi1;|I)t+ zAs5KMKeKsg_rf?9D^+$noN?wzFuyqiVNg{cv|`ek#mdZs>3)5s;@-M+pKCZ=Devxc zkM9dntdmd*l_pi;r>#z#Re==dVH2qzk~A_@pcOhw<-gv#7m zup;}4FF~5&Wro6&AT{7%FoZG?6VcpmcE{t^=lC!SITPULqPJIl$>p4BG)z(X{EngX z4Kj5_V%`3qun}f-i!Yfr4&Ua&142`cb$kCXj|IXTHC&@zs`og{G}ZkRDAg^2cmzkw zChDgQGfG40*du;_#wzCsSe_Yc|xQ6i$|W^yWiszxB|`z9NIsnkyK+ZJ`n)xbsg zDM_azH3p9kI2onD=@D+GlMZ?Kkf79edK0A6auyPa)!$Wd+kNtHnWWPJzLvv#=;fRQ z!vcaABrRCDjBv|xGhy_xvN~}oJwd~Kb}@lg#H(<+w~bi_yw}Haq8J7F5k8n(#cbzE zKGlk0l{MQUxMMuJvDSVj!S@`(+J@s-y({eFD x{yX*m*Bt~JLEpf5ZvXSqe@Y_|9|ZctHvf-su%T7C6!5Ch;ao7H2+qGP{{g-c(x(6b delta 4575 zcmY*dbx<4L(hX4Df_stR!KGMnD!6Nb;83)<6KIPEXcF8@i?_H#fZ|?)yHl)qp+J$> z-}`3Xd*A(QXZD<#oqO-uIlF0UrK(j!I8e^kY%v5D0MLa80FVLzfB;uPe-AGg8xIc` zfdDtxFNSU&pCp0zVH0<_J^loo3IK77$VL~V(X#y?3xaSq+-#f3##&8e$-+aJE#B)^ zsT{B6cygIbqNKcxz&>;6d|Kq05^b@sxGp;7BkyOm1DMfwii_{h3YyEhuq#B&p;J^D zCAeMFf)X7MeyH+!Ka1H{*Z^KRU2j%;$ZTLHlKi~9g_X+Wi8#1AoFjN9up4hIKr4ou za9ND#g`n`)smI?O)2yblh&5FWirrLs(eH%xtT28BYB9*=r|faO;c!@NKu@%|0&Fx1 zc}bW`%92avgDae)X0hL+UNqD=LQj0xqKRln*4c$}m<%V9r`uLyz~M8&6ON}Kn9LgkS8O%QPTec9m zXL>Xxr|=pScAEFlQL$&0*qY49oLRrC*Bqa~{8HqWVQbhSHF%xNLpQ(H00j~P&j6%3 z>yo*z)wO|rb-?$ACLgLQ9_^mc&Q>~Cbd#LZQ&v3v&|x-&Cq}(XXcI|REN6Kh%;!~T z->ZVUNIQQg@(UAkuh{F>YIzAD9BC{!#m;GMQ$M=)GF#v1L02>ji)1^$1d440Kw#-2| z)nZ!O(r0BdQZRi}+@%f6 z68u4Pv(g(st?yNO?(@>9os(mc9#f3SKoTW;$1hX()&$D*u-5r|?E5Hcv6H2u}C z83}Tbhy}Wsm?Z>^ItE`b@vTx|Nx3SpmTOLw1RGxj9Hz6HR14SVAj{f=`^VYA+ni?j zuK4yYYp=$&7-DxP3CXZ*X1cz}^#M|6&=$-3+(%Mhe zGR9Z|Z{PP()m^ra(s>u)j4pT9jjw6hfBEqkatKXrp1~AsO{%kb&8VIJqvoS5Yh#j- zhM_737<5TbzpBi~eIyJu9-gsqGJE=Va_Q*OjUDDrRt;CX@y0DwiNEz-q#c$ZIFRE2 z2@DKwq-@Bx4fq`RtCcPo%}Y;QU)uU#&g%US-q&QfCr&8?nS;2PWQTu0k(mzRn}zqw5tb1dv3 zi7tzYEXx;EZGWjh^rLo6L7szgIZNs^_CGF@#J~_`2Z6WK`2OC z^{DVecER5Au_g8n_qPgqj~yD6@6MiJDl}Q=6m=@GMpFe*f*r4-bF4^20-Ns$1e)A)rE~QV_tJ_lk#z^7?fo` zL;n2$5?B1(RW^*c+h?z+;_LD1_n#}YLh}I!6`y2eOp$jA^B2Y6SBHfzyM3KCs;g68 zAFR|eKPG{A(memY_lbZ17CjTl9D9xk<$@x|B{^I_uKTXy*ei*?S%dh%Gzl2rc~ z{tqpQzB0O$<_Z8}11f(M#?36%r&F>RgTtGAr-LXsR!9||Zy2Qz3TX&Xc&D?Z@U%;a zxPPWVN-LM)mxW-r2&;@KlV=!Tt4S%QR4Ir`B&pi5yBqcaz}tzhA&P-IY@01-4+Z6B zIO)7>JBG1D@M6qyh&h#5rzL9Wa6^!u4sLEJ-swbkZPN!Q8#H{4MMMKHW-We2YS{dx zm_gaSO@!4brBI=kp%R9gK1{9R+KQc=+tk~7&2@!~j0L*jf1?4mYvBR_eaJf?BXl&L zL4vY_=0={#+y7R4Gl^qm?Yk>-ncXfYnX$g%r>>Ex2%?RF0+U1PLXZ1%VVaVMZ1RKx z7BT8q5442xcGN&SkSr8=>#f0=tVkV7a|qXu5%`v z4Vz16pG<|iNOFsXXunK`k=f(BL$3+>Zq*m_!o0}b2J!mmu&z~HKc+IPN-gqI_u@st zn>rmNBUU+K{V%&fdDQ)kOz&3GslkPMUui*zE6cYwI>DhLte~I7DQeK*(l+gNVYm`8 zjC<9%teWFv^=5aCQcUEo-Vqb)!kKlhu*~C);ECVdwAPP_z-J$~KOv zvU~o6NVA4jhzZ*JZ10=%1Pk6fv*1DqR*8B4#lf9fN5e!hhLhOal%j??>4Oya57xvw zH`5+T(aNP4V1PYdwn`lX&DFQRJLfO$I!~YKB*pauN4MptuGhkRuyL*b3L!RJ1&PlRR3r?3G#4vN3#Oy zxIfuHmDro&I_>J|xV;`u>v%YozNp$*q7rNmJv-Y&(yWGF>}V%3Ei5uJrJu0IR-aU? z+a7bqTSt)mImM9A=@C-uK`4;z`js3F4`5opV%hKVtvc*lWHjl+ZhP9{GT*{{+RUDq zQTe&}6#346;qGnp&q#(s>cx($|rVy5wVTNQ7=@U&sBel%88M*6%o zWucW;-v`zQr44SB^EMf`79HMcMjNwPr7-Pa~n#mroe4RQ7+coevO~c`y zpQN?caA45&rPYOyC{bEEzPFsuFhTp6pmp}spdZbidu|g5xlvICY+tTDLv2SZE+|Gh zFedNVQWe)_w81I}#xkAMegx=Du z^T~{+{xR)q$%vj3(QdYBX7Cc-Paq|8dB(=o6v4@gH-ON382tytyyyU1j>hKF`>NVopdxVM*^ukbO2W z5d`BV#)ikg^V%O3j>xK_f^T2@Z&(dMoo3tOCZv)RLDKO$eg)}vxn1J16(eYEFf*<8 zeCD^02Leyi%djp{+RGBm(?i}kuYWie_44jd`5^bAWwwaR&y=TXcnjU{wD`R$Tm+g) z$fpC<+SaE+Mqua^5GF_Pd&ME^L;KUds@LIKaev5HS<;A zJ5bBHx*1w(n|8qUk9ZpN1}a&sx2vP%kp|+vnP3=5eqt5BgfvaSTWyo#;(rL^am8I$ zo8wQWx9$KMywm$g)=(blM{6{ES7pBM%S*au1=lqvnLN0`Ft;9m=J&d?e^%gVbDMuO zk}N)612RHWzkajPZayF4c}&J)kn^X0DBsl0&pFbeUY7e2O6$}3&l%}R%dfAFiG!A_ z(2P${P#|KGg=u%40||n9uf|t+&K&k(pG-?|Q`BTi8X4~L?^wXLR@*$GcI|-Q&aDj( z82`4nVYF6QBsZ8MW+WH@z$hjFKnXy)vr|J|5t`cX|1r6o_qY?Si=;zoJj=8Rv1zhZ zK__;+Fhcygm+|v=zilpUtP(>Vq`$XmPTxQMg(lT#_ikVh>3{jC!B5jsns@uiUQQ&!yc3CPN9nFaJ2kt6sxAQgg4IHoyR2@<60FjO(z0+UQa61H!m>NX+M(EZ z%G%hrJWLvnss^p|QHX(OGK)vSQT<>b4|>So4BH~(qYP6PQI4I1vFOdy94;q8gz8y9If8MJ z9lP6rt}&D}S*#6ZxLura%?Nrih;B^RiYX;~MolS^#0p)|)IOB1l_7FslZ>;;TNS~jnkAC+ z>8rPN?_3Q(o-^q9gXI!86jXBlLf=Mno`xTT%QGY%TXLxMQxkSn5K93FQHxRPUvvb> zwk}Z&_n}6{tU)TVKtFpUwCJRsZIdkcOZPF=N*(lmLp4rYxn^=Yb6ODP<*g-6pSu`~ zf3a%?iOMV`q82AB)#!h2N7$;tcdG>;|%GRJ=8xy8w!yZyXZVywN*lT;nNA{^Jx`004^rBK}6%$WxF45yM~R-(`!pPoS$k63R}+@c+O2|1yG+ZtPr)|9~Ke>MaXT6m+ diff --git a/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx b/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx new file mode 100644 index 0000000000000000000000000000000000000000..ec55be99ac5fc45c96f056b7c3dedb46f48d0273 GIT binary patch literal 162 zcmWgkO-#=#EiTT_(^2qB&CAP7OD$p`2!t7Y84?-N8S)rP8H#~0AIQ>SP+;(4NCmR; z7%~~sfGmVTpQ<26W=D7`3h~@zTyf)N{k_Eu46C~=f3KRzC)q@C^3zn}G} G)&l@k6Cld~ literal 0 HcmV?d00001 diff --git a/silicon_probe_LFP_analysis/script_extract_power_spectra.asv b/silicon_probe_LFP_analysis/script_extract_power_spectra.asv new file mode 100644 index 00000000..880fc721 --- /dev/null +++ b/silicon_probe_LFP_analysis/script_extract_power_spectra.asv @@ -0,0 +1,128 @@ +% script_extract_power_spectra + +intan_choicetask_parent = 'X:\Neuro-Leventhal\data\ChoiceTask'; + +% loop through all the processed data folders here, load the lfp file +valid_rat_folders = find_processed_folders(intan_choicetask_parent); +valid_trials_folder = find_trials_struct_folders(intan_choicetask_parent); + +%% +% probe_type = 'NN8x8'; % Need to edit this to reflect different probe types per ratID +Fs = 500; +% lfp_fname = dir(fullfile(intan_choicetask_parent,'**','*_lfp.mat')); % This +% generates a matrix of '*_lfp.mat' filenames + +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457", "R0456", "R0459", "R0460", "R0463", "R0465", "R0466"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% R0427_20220920a does not have an 'info.rhd' file + +%% + +for i_ratfolder = 1 : length(valid_rat_folders) + + session_folders = valid_rat_folders(i_ratfolder).processed_folders; + + for i_sessionfolder = 1 : length(session_folders) + % extract the ratID and session name from the LFP file + session_path_processed = session_folders{i_sessionfolder}; + pd_processed_data = parse_processed_folder(session_path_processed); + ratID = pd_processed_data.ratID; + session_name = pd_processed_data.session_name; + + if any(strcmp(session_name, sessions_to_ignore)) + continue; + end + + if contains(ratID, NN8x8) + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + % create filenames to hold mono- and diff-LFPs + power_fn = [session_name, '_monopolarpower.mat']; + power_fn = fullfile(session_path_processed, power_fn); + + diff_power_fn = [session_name, '_diffpower.mat']; + diff_power_fn = fullfile(session_path_processed, diff_power_fn); + + % Might be good to add a check here to see if mono_power_fn and/or diff_power_fn + % exists, if exists skip reading in the data to save time. + + lfp_file = dir(fullfile(session_path_processed, '**', '*_lfp.mat')); + cd(session_path_processed); + + for i_file = 1 : length(lfp_file) + lfp_fname = lfp_file(i_file).name; + name_parts = split(lfp_fname, '_'); + + if strcmp(name_parts(3), 'bipolar') + bipolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); + else + monopolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); + end + end + + % lfp = load(lfp_fname.name); % I think the lfp needs to be loaded + % in the lfp_NNsite_order script in the next line of this fxn. + + % LFP file needs to be loaded before the [power_lfps,f] function +% lfp_fname = fullfile(lfp_file.folder, lfp_file.name); + + if exist(power_fn, 'file') && exist(diff_power_fn, 'file') + continue + end + + for i_lfp = 1 : 2 + if i_lfp == 1 + isbipolar = true; + else: + isbipolar = fal + isbipolar + + lfp_data = load(lfp_fname); + Fs = lfp_data.actual_Fs; + + num_rows = size(lfp_data.lfp,1); % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. Need to rewrite lfp_NNsite_order and diff functions to fix this issue by determining which channel was not recorded. + if num_rows < 64 + continue + end + + if ~exist(power_fn, 'file') + [ordered_lfp, intan_site_order, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); % lfp_by_probe_site_ALL has the three probe types listed. + % Working on changing probe_type to a list of rats with + % each probe_type so it runs and writes the diff/monopolars + % correctly + % lfp_NNsite_order = lfp_by_probe_site(lfp_data, probe_type); % grandfathered code + [power_lfps, f] = extract_power(ordered_lfp,Fs); % in the original code (LFP, Fs); + save(power_fn, 'power_lfps', 'f', 'Fs'); + end + + if ~exist(diff_power_fn, 'file') + % Reorganize by site and calculate the diffs; specify + % probe_type so it reorganzies the lfp files based on sites + if strcmpi(probe_type, 'nn8x8') + lfp_NNsite_diff = diff_probe_site_mapping(lfp_data, probe_type); % calculates diffs + [power_lfps_diff, f] = extract_power(lfp_NNsite_diff,Fs); + save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); + elseif strcmpi(probe_type, 'ASSY236') + diff_lfps = diff_probe_site_mapping_CAMBRIDGE(lfp_data, probe_type); + [power_lfps_diff, f] = extract_power(diff_lfps,Fs); + save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); + elseif strcmpi(probe_type, 'ASSY156') + diff_lfps = diff_probe_site_mapping_CAMBRIDGE(lfp_data, probe_type); + [power_lfps_diff, f] = extract_power(diff_lfps,Fs); + save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); + end + end + + end + +end \ No newline at end of file diff --git a/silicon_probe_LFP_analysis/script_extract_power_spectra.m b/silicon_probe_LFP_analysis/script_extract_power_spectra.m index 8b91f3b1..8202348b 100644 --- a/silicon_probe_LFP_analysis/script_extract_power_spectra.m +++ b/silicon_probe_LFP_analysis/script_extract_power_spectra.m @@ -14,7 +14,7 @@ NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457", "R0456", "R0459", "R0460", "R0463", "R0465", "R0466"]; sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; @@ -58,19 +58,46 @@ lfp_file = dir(fullfile(session_path_processed, '**', '*_lfp.mat')); cd(session_path_processed); + + for i_file = 1 : length(lfp_file) + lfp_fname = lfp_file(i_file).name; + name_parts = split(lfp_fname, '_'); + + if strcmp(name_parts(3), 'bipolar') + bipolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); + else + monopolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); + end + end + % lfp = load(lfp_fname.name); % I think the lfp needs to be loaded % in the lfp_NNsite_order script in the next line of this fxn. % LFP file needs to be loaded before the [power_lfps,f] function - lfp_fname = fullfile(lfp_file.folder, lfp_file.name); +% lfp_fname = fullfile(lfp_file.folder, lfp_file.name); -% if exist(power_fn, 'file') && exist(diff_power_fn, 'file') -% continue -% end + if exist(power_fn, 'file') && exist(diff_power_fn, 'file') + continue + end - lfp_data = load(lfp_fname); - Fs = lfp_data.actual_Fs; + for i_lfp = 1 : 2 + if i_lfp == 1 + isbipolar = true; + else + isbipolar = false; + end + + if isbipolar + lfp_fname = bipolar_lfpname; + else + lfp_fname = monopolar_lfpname; + end + + lfp_data = load(lfp_fname); + Fs = lfp_data.actual_Fs; + end + num_rows = size(lfp_data.lfp,1); % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. Need to rewrite lfp_NNsite_order and diff functions to fix this issue by determining which channel was not recorded. if num_rows < 64 continue From feef0a5d00d57348c4554e92a662a8be013321ac Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Mon, 8 May 2023 10:06:54 -0400 Subject: [PATCH 09/19] updating code from Dan's files --- .../script_calculate_perievent_scalograms.m | 69 ++++++++++ .../create_scalo_folder.m | 18 +++ .../find_data_folder.m | 28 ++++ .../find_log_file.m | 30 ++++ .../script_extract_power_spectra.asv | 128 ------------------ 5 files changed, 145 insertions(+), 128 deletions(-) create mode 100644 LFPs/Analysis_code_JM/utils/script_calculate_perievent_scalograms.m create mode 100644 intan_choice_task_navigation_utils/create_scalo_folder.m create mode 100644 intan_choice_task_navigation_utils/find_data_folder.m create mode 100644 intan_choice_task_navigation_utils/find_log_file.m delete mode 100644 silicon_probe_LFP_analysis/script_extract_power_spectra.asv diff --git a/LFPs/Analysis_code_JM/utils/script_calculate_perievent_scalograms.m b/LFPs/Analysis_code_JM/utils/script_calculate_perievent_scalograms.m new file mode 100644 index 00000000..57b4cc12 --- /dev/null +++ b/LFPs/Analysis_code_JM/utils/script_calculate_perievent_scalograms.m @@ -0,0 +1,69 @@ +% script_calculate_perievent_scalograms + +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; + +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + logData = readLogData(session_log); + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder) + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder) + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder) + continue + end + + % read in rhd info + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + % update here for next steps in calculating perievent scalograms + + sprintf('placeholder') + end + +end \ No newline at end of file diff --git a/intan_choice_task_navigation_utils/create_scalo_folder.m b/intan_choice_task_navigation_utils/create_scalo_folder.m new file mode 100644 index 00000000..b7b9946e --- /dev/null +++ b/intan_choice_task_navigation_utils/create_scalo_folder.m @@ -0,0 +1,18 @@ +function scalo_folder = create_scalo_folder(session_name,event_name,parent_directory) +%UNTITLED2 Summary of this function goes here +% Detailed explanation goes here + +session_name_parts = split(session_name,'_'); +ratID = session_name_parts{1}; +processed_folder = find_data_folder(ratID, 'processed', parent_directory); + +session_folder = fullfile(processed_folder, session_name); + +if exist(session_folder, 'dir') + scalo_folder = sprintf('%s_scalos_%s', session_name, event_name); + scalo_folder = fullfile(session_folder, scalo_folder); +else + scalo_folder = ''; +end + +end \ No newline at end of file diff --git a/intan_choice_task_navigation_utils/find_data_folder.m b/intan_choice_task_navigation_utils/find_data_folder.m new file mode 100644 index 00000000..ca65c9e4 --- /dev/null +++ b/intan_choice_task_navigation_utils/find_data_folder.m @@ -0,0 +1,28 @@ +function session_path = find_data_folder(session_name, data_type, parent_directory) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here + + +str_parts = split(session_name, '_'); +ratID = str_parts{1}; + +rd_folder = find_rat_data_folder(parent_directory, ratID, data_type); + +if length(ratID) == 5 + session_path = rd_folder; +elseif isfolder(fullfile(rd_folder, session_name)) + session_path = fullfile(rd_folder, session_name); +else + session_path = ''; +end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function rd_folder = find_rat_data_folder(parent_directory, ratID, data_type) + +rat_folder = fullfile(parent_directory, ratID); +rd_folder = fullfile(rat_folder, strcat(ratID, '-', data_type)); + +end \ No newline at end of file diff --git a/intan_choice_task_navigation_utils/find_log_file.m b/intan_choice_task_navigation_utils/find_log_file.m new file mode 100644 index 00000000..6a55b203 --- /dev/null +++ b/intan_choice_task_navigation_utils/find_log_file.m @@ -0,0 +1,30 @@ +function log_fname = find_log_file(session_name, parent_directory) +%UNTITLED15 Summary of this function goes here +% Detailed explanation goes here + +session_name_parts = split(session_name, '_'); +ratID = session_name_parts{1}; +session_date = session_name_parts{2}(1:8); + +rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); +rawdata_session_folder = fullfile(rawdata_folder, session_name); + +test_name = strcat(ratID, '_', session_date, '_*.log'); +test_name = fullfile(rawdata_session_folder, test_name); + +poss_logs = dir(test_name); + +log_fname = ''; +if isempty(poss_logs) + sprintf('no log file found for %s', session_name); +else + for ii = 1 : length(poss_logs) + if contains(poss_logs(ii).name, 'old') + continue + else + log_fname = fullfile(poss_logs(ii).folder, poss_logs(ii).name); + end + end +end + +end \ No newline at end of file diff --git a/silicon_probe_LFP_analysis/script_extract_power_spectra.asv b/silicon_probe_LFP_analysis/script_extract_power_spectra.asv deleted file mode 100644 index 880fc721..00000000 --- a/silicon_probe_LFP_analysis/script_extract_power_spectra.asv +++ /dev/null @@ -1,128 +0,0 @@ -% script_extract_power_spectra - -intan_choicetask_parent = 'X:\Neuro-Leventhal\data\ChoiceTask'; - -% loop through all the processed data folders here, load the lfp file -valid_rat_folders = find_processed_folders(intan_choicetask_parent); -valid_trials_folder = find_trials_struct_folders(intan_choicetask_parent); - -%% -% probe_type = 'NN8x8'; % Need to edit this to reflect different probe types per ratID -Fs = 500; -% lfp_fname = dir(fullfile(intan_choicetask_parent,'**','*_lfp.mat')); % This -% generates a matrix of '*_lfp.mat' filenames - -NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type -ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457", "R0456", "R0459", "R0460", "R0463", "R0465", "R0466"]; - -sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a'}; -sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; -sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; -% R0427_20220920a does not have an 'info.rhd' file - -%% - -for i_ratfolder = 1 : length(valid_rat_folders) - - session_folders = valid_rat_folders(i_ratfolder).processed_folders; - - for i_sessionfolder = 1 : length(session_folders) - % extract the ratID and session name from the LFP file - session_path_processed = session_folders{i_sessionfolder}; - pd_processed_data = parse_processed_folder(session_path_processed); - ratID = pd_processed_data.ratID; - session_name = pd_processed_data.session_name; - - if any(strcmp(session_name, sessions_to_ignore)) - continue; - end - - if contains(ratID, NN8x8) - probe_type = 'NN8x8'; - elseif contains(ratID, ASSY156) - probe_type = 'ASSY156'; - elseif contains(ratID, ASSY236) - probe_type = 'ASSY236'; - end - - % create filenames to hold mono- and diff-LFPs - power_fn = [session_name, '_monopolarpower.mat']; - power_fn = fullfile(session_path_processed, power_fn); - - diff_power_fn = [session_name, '_diffpower.mat']; - diff_power_fn = fullfile(session_path_processed, diff_power_fn); - - % Might be good to add a check here to see if mono_power_fn and/or diff_power_fn - % exists, if exists skip reading in the data to save time. - - lfp_file = dir(fullfile(session_path_processed, '**', '*_lfp.mat')); - cd(session_path_processed); - - for i_file = 1 : length(lfp_file) - lfp_fname = lfp_file(i_file).name; - name_parts = split(lfp_fname, '_'); - - if strcmp(name_parts(3), 'bipolar') - bipolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); - else - monopolar_lfpname = fullfile(lfp_file(i_file).folder, lfp_fname); - end - end - - % lfp = load(lfp_fname.name); % I think the lfp needs to be loaded - % in the lfp_NNsite_order script in the next line of this fxn. - - % LFP file needs to be loaded before the [power_lfps,f] function -% lfp_fname = fullfile(lfp_file.folder, lfp_file.name); - - if exist(power_fn, 'file') && exist(diff_power_fn, 'file') - continue - end - - for i_lfp = 1 : 2 - if i_lfp == 1 - isbipolar = true; - else: - isbipolar = fal - isbipolar - - lfp_data = load(lfp_fname); - Fs = lfp_data.actual_Fs; - - num_rows = size(lfp_data.lfp,1); % for now, skipping R0378_20210507a because the session only recorded 63 channels instead of 64. Need to rewrite lfp_NNsite_order and diff functions to fix this issue by determining which channel was not recorded. - if num_rows < 64 - continue - end - - if ~exist(power_fn, 'file') - [ordered_lfp, intan_site_order, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); % lfp_by_probe_site_ALL has the three probe types listed. - % Working on changing probe_type to a list of rats with - % each probe_type so it runs and writes the diff/monopolars - % correctly - % lfp_NNsite_order = lfp_by_probe_site(lfp_data, probe_type); % grandfathered code - [power_lfps, f] = extract_power(ordered_lfp,Fs); % in the original code (LFP, Fs); - save(power_fn, 'power_lfps', 'f', 'Fs'); - end - - if ~exist(diff_power_fn, 'file') - % Reorganize by site and calculate the diffs; specify - % probe_type so it reorganzies the lfp files based on sites - if strcmpi(probe_type, 'nn8x8') - lfp_NNsite_diff = diff_probe_site_mapping(lfp_data, probe_type); % calculates diffs - [power_lfps_diff, f] = extract_power(lfp_NNsite_diff,Fs); - save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); - elseif strcmpi(probe_type, 'ASSY236') - diff_lfps = diff_probe_site_mapping_CAMBRIDGE(lfp_data, probe_type); - [power_lfps_diff, f] = extract_power(diff_lfps,Fs); - save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); - elseif strcmpi(probe_type, 'ASSY156') - diff_lfps = diff_probe_site_mapping_CAMBRIDGE(lfp_data, probe_type); - [power_lfps_diff, f] = extract_power(diff_lfps,Fs); - save(diff_power_fn, 'power_lfps_diff', 'f', 'Fs'); - end - end - - end - -end \ No newline at end of file From bd1229637a4657804e1422f5f500c4bcc18e822f Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Mon, 8 May 2023 11:22:02 -0400 Subject: [PATCH 10/19] working through Dan's repository --- Analysis/script_loop_through_data_folders.m | 67 ++++ Analysis/script_rename_scalos_to_monopolar.m | 80 +++++ Analysis/trial_scalograms.m | 20 ++ .../createTrialsStruct_simpleChoice_Intan.m | 81 +++-- .../create_and_save_trials_struct_Intan.asv | 61 ++++ .../create_and_save_trials_struct_Intan.m | 83 +++++ .../extractEventsFromIntanSystem.m | 4 + .../intan2nex.m | 322 ++++++++++++++++++ Helpers/display_scalogram.m | 48 +++ Helpers/extract_perievent_data.m | 29 ++ Helpers/extract_trials_by_features.m | 63 ++++ Helpers/extract_trials_by_outcome.m | 28 ++ Helpers/find_physiology_data.m | 43 +++ Helpers/get_rat_list.m | 19 ++ Helpers/get_shank_and_site_num.m | 47 +++ Helpers/readLogData.m | 98 ++++++ Helpers/read_Jen_xls_summary.m | 16 + Helpers/ts_from_trials.m | 17 + LFPs/calculate_bipolar_LFPs.m | 40 +++ .../find_rawdata_folder.m | 67 ++++ .../get_rawdata_ephys_folder.m | 26 ++ 21 files changed, 1239 insertions(+), 20 deletions(-) create mode 100644 Analysis/script_loop_through_data_folders.m create mode 100644 Analysis/script_rename_scalos_to_monopolar.m create mode 100644 Analysis/trial_scalograms.m create mode 100644 ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.asv create mode 100644 ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.m create mode 100644 ChoiceTask_Intan_behavior_analysis/intan2nex.m create mode 100644 Helpers/display_scalogram.m create mode 100644 Helpers/extract_perievent_data.m create mode 100644 Helpers/extract_trials_by_features.m create mode 100644 Helpers/extract_trials_by_outcome.m create mode 100644 Helpers/find_physiology_data.m create mode 100644 Helpers/get_rat_list.m create mode 100644 Helpers/get_shank_and_site_num.m create mode 100644 Helpers/readLogData.m create mode 100644 Helpers/read_Jen_xls_summary.m create mode 100644 Helpers/ts_from_trials.m create mode 100644 LFPs/calculate_bipolar_LFPs.m create mode 100644 intan_choice_task_navigation_utils/find_rawdata_folder.m create mode 100644 intan_choice_task_navigation_utils/get_rawdata_ephys_folder.m diff --git a/Analysis/script_loop_through_data_folders.m b/Analysis/script_loop_through_data_folders.m new file mode 100644 index 00000000..ca97f01f --- /dev/null +++ b/Analysis/script_loop_through_data_folders.m @@ -0,0 +1,67 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_types = {'monopolar', 'bipolar'}; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +t_window = [-2.5, 2.5]; +event_list = {'cueOn', 'centerIn', 'tone', 'centerOut' 'sideIn', 'sideOut', 'foodClick', 'foodRetrieval'}; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + for i_lfptype = 1 : length(lfp_types) + + lfp_type = lfp_types{i_lfptype}; + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s', session_name, event_name) + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + + for i_channel = 1 : num_channels + + + end + end + end + end + +end \ No newline at end of file diff --git a/Analysis/script_rename_scalos_to_monopolar.m b/Analysis/script_rename_scalos_to_monopolar.m new file mode 100644 index 00000000..ef4660bf --- /dev/null +++ b/Analysis/script_rename_scalos_to_monopolar.m @@ -0,0 +1,80 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_types = {'monopolar', 'bipolar'}; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +t_window = [-2.5, 2.5]; +event_list = {'cueOn', 'centerIn', 'tone', 'centerOut' 'sideIn', 'sideOut', 'foodClick', 'foodRetrieval'}; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + for i_lfptype = 1 : length(lfp_types) + + lfp_type = lfp_types{i_lfptype}; + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s', session_name, event_name) + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + if ~exist(scalo_folder, 'dir') + continue + end + + for i_channel = 1 : num_channels + [shank_num, site_num] = get_shank_and_site_num(probe_lfp_type, i_channel); + + old_scalo_name = sprintf('%s_scalos_%s_shank%02d_site%02d.mat',session_name, event_name, shank_num, site_num); + old_scalo_name = fullfile(scalo_folder, old_scalo_name); + + if exist(old_scalo_name, 'file') + new_scalo_name = sprintf('%s_scalos_%s_%s_shank%02d_site%02d.mat',session_name, lfp_type, event_name, shank_num, site_num); + new_scalo_name = fullfile(scalo_folder, new_scalo_name); + + movefile(old_scalo_name, new_scalo_name) + end + + end + end + end + end + +end \ No newline at end of file diff --git a/Analysis/trial_scalograms.m b/Analysis/trial_scalograms.m new file mode 100644 index 00000000..26a96539 --- /dev/null +++ b/Analysis/trial_scalograms.m @@ -0,0 +1,20 @@ +function [event_related_scalos, f, coi] = trial_scalograms(event_triggered_lfps, fb) +%UNTITLED2 Summary of this function goes here +% INPUTS +% event_triggered_lfps - num_trials x samples_per_event array +% Detailed explanation goes here + +num_trials = size(event_triggered_lfps, 1); +samples_per_event = size(event_triggered_lfps, 2); + +f = centerFrequencies(fb); +num_freqs = length(f); + +real_event_related_scalos = zeros(num_trials, num_freqs, samples_per_event); +event_related_scalos = complex(real_event_related_scalos, 0); + +for i_trial = 1 : num_trials + [event_related_scalos(i_trial, :, :), ~, coi] = wt(fb, squeeze(event_triggered_lfps(i_trial, :))); +end + +end \ No newline at end of file diff --git a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m index 669d782b..a4cf1234 100644 --- a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m +++ b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m @@ -95,7 +95,7 @@ %why are there two Idxs? is this legacy for some system that had these %times on different rows or something? if isempty(GO_startIdx) - error('Could not find trial start sequence.'); + error('lognexmerge:lognexmismatch', 'Could not find trial start sequence.'); else GO_endIdx = GO_startIdx; end @@ -448,11 +448,32 @@ % trials) trialData.movementDirection = 2; % moved right sideInAfterCue = trialEvents{NoseInidx(CueID(1) + 1)}.timestamps(trialEvents{NoseInidx(CueID(1) + 1)}.timestamps > CueTS(1)); - trialData.timestamps.sideIn = sideInAfterCue(1); - trialData.timestamps.sideOut = ... - events{NoseOutidx(CueID(1) + 1)}.timestamps(events{NoseOutidx(CueID(1) + 1)}.timestamps > NoseInTS(1)); - trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); - % done this way to prevent the algorithm from counting a nose-out + if isempty(sideInAfterCue) + % this trial was probably at the very end of a session, and the + % session ended mid-trial before the rat could poke the side + % port. Not sure how this got counted as correct - maybe + % recorded that way in the .log file but the sideIn wasn't + % registered on the Intan system. -DL 12/19/2022 + % label as an invalid trial, doesn't count as a trial, make + % sure listed as not correct so not incorporated in analysis + trialData.countsAsTrial = 0; + trialData.valid = 0; + trialData.correct = 0; + else + trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 + trialData.timestamps.sideOut = ... + events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); + trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); + trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; + + trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timestamps.centerOut; + trialData.timing.foodDelay = trialData.timestamps.foodClick - ... + trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... + trialData.timestamps.sideIn; + end + else % tone 1 (low tone) was played trialData.tone = 1; @@ -460,34 +481,48 @@ trialData.sideNP = trialData.centerNP - 1; trialData.movementDirection = 1; sideInAfterCue = trialEvents{NoseInidx(CueID(1) - 1)}.timestamps(trialEvents{NoseInidx(CueID(1) - 1)}.timestamps > CueTS(1)); - trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 - trialData.timestamps.sideOut = ... + if isempty(sideInAfterCue) + % this trial was probably at the very end of a session, and the + % session ended mid-trial before the rat could poke the side + % port. Not sure how this got counted as correct - maybe + % recorded that way in the .log file but the sideIn wasn't + % registered on the Intan system. -DL 12/19/2022 + % label as an invalid trial, doesn't count as a trial, make + % sure listed as not correct so not incorporated in analysis + trialData.countsAsTrial = 0; + trialData.valid = 0; + trialData.correct = 0; + else + trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 + trialData.timestamps.sideOut = ... events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); - trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); + trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); + trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; + + trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timestamps.centerOut; + trialData.timing.foodDelay = trialData.timestamps.foodClick - ... + trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... + trialData.timestamps.sideIn; + end + % done this way to prevent the algorithm from counting a nose-out % event that may be left over from a previous trial end % end if isempty(trialEvents{Tone1idx}.timestamps) - - trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; % calculate timing of events within the trial trialData.timing.pretone = trialData.timestamps.tone - ... trialData.timestamps.centerIn; trialData.timing.RT = trialData.timestamps.centerOut - ... trialData.timestamps.tone; - trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timestamps.centerOut; - trialData.timing.foodDelay = trialData.timestamps.foodClick - ... - trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... - trialData.timestamps.sideIn; - + % extract the FIRST time the rat went into the reward port. This is a % bit tricky because this may occur AFTER the next trial started % depending on how the behavior software was running and if the food % port sensor was working at all - if FoodSensidx ~= 0 % the food port sensor was working + if FoodSensidx ~= 0 && ~isempty(sideInAfterCue) % the food port sensor was working and there was a valid sideInAfterCue event firstFoodRetrieval = find(events{FoodSensidx}.timestamps > ... trialData.timestamps.sideIn); if ~isempty(firstFoodRetrieval) @@ -508,7 +543,13 @@ % and target ports match up boxLogConflicts.outcome = ~(logTrial.outcome == 0); boxLogConflicts.RT = ~(abs(logTrial.RT - trialData.timing.RT) < timingTolerance); - boxLogConflicts.MT = ~(abs(logTrial.MT - trialData.timing.MT) < timingTolerance); + if ~isempty(sideInAfterCue) + % no MT is there was no sideIn, which could happen on a "correct" + % trial according to the behavior log if this was the very last + % trial so the sideIn was not registered on the Intan system + % -DL 12/19/2022 + boxLogConflicts.MT = ~(abs(logTrial.MT - trialData.timing.MT) < timingTolerance); + end boxLogConflicts.pretone = ~(abs(logTrial.pretone - trialData.timing.pretone) < timingTolerance); boxLogConflicts.centerNP = ~(logTrial.Center == trialData.centerNP); boxLogConflicts.sideNP = ~(logTrial.Target == trialData.sideNP); diff --git a/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.asv b/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.asv new file mode 100644 index 00000000..c658760b --- /dev/null +++ b/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.asv @@ -0,0 +1,61 @@ +% script create_and_save_trials_struct_Intan + +% loop through all rats with valid choice task data, create trials +% structure for each session, save in the processed data folder to save +% time + +parent_directory = 'Z:\data\ChoiceTask\'; + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_processed_dir = fullfile(session_dirs(i_session).folder, session_name); + cur_rawdata_dir = fullfile(rawdata_folder, session_name); + cd(cur_processed_dir) + + lfp_fname = strcat(session_name, '_lfp.mat'); + if ~isfile(lfp_fname) + sprintf('%s not found, skipping', lfp_file) + continue + end + + trials_name = sprintf('%s_trials.mat', session_name); + trials_name = fullfile(cur_processed_dir, trials_name); + if exist(trial_name, 'file') + + continue + end + + rawdata_ephys_folder = get_rawdata_ephys_folder(rawdata_folder,session_name); + nexData = extractEventsFromIntanSystem(rawdata_ephys_folder); + + log_file = find_log_file(session_name, parent_directory); + logData = readLogData(log_file); + + sprintf('loaded logData and nexData for %s', session_name) + + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + + + + end + +end \ No newline at end of file diff --git a/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.m b/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.m new file mode 100644 index 00000000..11270a43 --- /dev/null +++ b/ChoiceTask_Intan_behavior_analysis/create_and_save_trials_struct_Intan.m @@ -0,0 +1,83 @@ +% script create_and_save_trials_struct_Intan + +% loop through all rats with valid choice task data, create trials +% structure for each session, save in the processed data folder to save +% time + +parent_directory = 'Z:\data\ChoiceTask\'; + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_processed_dir = fullfile(session_dirs(i_session).folder, session_name); + cur_rawdata_dir = fullfile(rawdata_folder, session_name); + cd(cur_processed_dir) + + lfp_fname = strcat(session_name, '_lfp.mat'); + if ~isfile(lfp_fname) + sprintf('%s not found, skipping', lfp_file) + continue + end + + trials_name = sprintf('%s_trials.mat', session_name); + trials_name = fullfile(cur_processed_dir, trials_name); + if exist(trials_name, 'file') + % skip if already calculated + sprintf('trials structure already calculated for %s', session_name) + continue + end + + rawdata_ephys_folder = get_rawdata_ephys_folder(rawdata_folder,session_name); + % check that the digitalIn file exists - was missing from some + % early sessions + digitalin_fname = fullfile(rawdata_ephys_folder, 'digitalin.dat'); + if ~exist(digitalin_fname, 'file') + sprintf('no digital input file found for %s', session_name) + continue + end + + nexData = extractEventsFromIntanSystem(rawdata_ephys_folder); + if isempty(nexData) + % something was wrong with the analog/digital input files from + % the intan system + sprintf('nexData could not be generated for %s', session_name) + continue + end + + log_file = find_log_file(session_name, parent_directory); + logData = readLogData(log_file); + + sprintf('loaded logData and nexData for %s', session_name) + + try + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch ME + if strcmp(ME.identifier, 'lognexmerge:lognexmismatch') + sprintf('mismatch between log and nex files for %s', session_name) + continue + end + end + + save(trials_name, 'trials'); + + end + +end \ No newline at end of file diff --git a/ChoiceTask_Intan_behavior_analysis/extractEventsFromIntanSystem.m b/ChoiceTask_Intan_behavior_analysis/extractEventsFromIntanSystem.m index acb32328..65a26512 100644 --- a/ChoiceTask_Intan_behavior_analysis/extractEventsFromIntanSystem.m +++ b/ChoiceTask_Intan_behavior_analysis/extractEventsFromIntanSystem.m @@ -28,6 +28,10 @@ digital_word = readIntanDigitalFile(dig_in_file); toc tic +if ~isfield(intan_info, 'board_adc_channels') + nexData = []; + return +end ADC_signals = readIntanAnalogFile(analog_in_file,intan_info.board_adc_channels); toc diff --git a/ChoiceTask_Intan_behavior_analysis/intan2nex.m b/ChoiceTask_Intan_behavior_analysis/intan2nex.m new file mode 100644 index 00000000..cf2f1f34 --- /dev/null +++ b/ChoiceTask_Intan_behavior_analysis/intan2nex.m @@ -0,0 +1,322 @@ +function nexData = intan2nex(dig_in,analog_in,intan_info,varargin) +% +% usage: nexData = intan2nex(dig_in,analog_in,intan_info,varargin) +% +% function to read in timestamps from intan digital and analog in lines and +% convert to a .nex file with events for the choice task +% +% INPUTS: +% dig_in - name of digital input file recorded with the intan system. +% These are generally digital lines from the NI boards running the +% choice task. +% analog_in - name of analog input file recorded with the intan system. +% These are generally digital lines from the NI boards running the +% choice task, plugged into analog lines if we run out of digital +% lines. Note that as of 3/26/2020, the line names are hard-coded in +% the dig_linenames = ... and analog_linenames = ... lines below. +% intan_info - data structure containing info read in from the rhd file +% .XXX - +% TO ADD HERE: DESCRIPTION OF THE INFORMATION IN THE INTAN_INFO FILE, +% WHICH I THINK IS WHAT'S READ IN FROM THE .RHD FILE +% +% VARARGS: +% 'writefile' - whether or not to write the nex formatted data to a new +% file; default filename is the original filename with .nex appended +% - that is, should be "XXXX.box.nex" where XXXX is the original base +% filename. NOT SURE IF WE STILL NEED THIS +% +% OUTPUTS: +% nexData - nex data structure +% nexData.version - file version +% nexData.comment - file comment +% nexData.tbeg - beginning of recording session (in seconds) +% nexData.tend - end of resording session (in seconds) +% +% nexData.neurons - array of neuron structures +% neurons.name - name of a neuron variable +% neurons.timestamps - array of neuron timestamps (in seconds) +% to access timestamps for neuron 2 use {n} notation: +% nexData.neurons{2}.timestamps +% +% nexData.events - array of event structures +% event.name - name of neuron variable +% event.timestamps - array of event timestamps (in seconds) +% to access timestamps for event 3 use {n} notation: +% nexData.events{3}.timestamps +% +% nexData.intervals - array of interval structures +% interval.name - name of neuron variable +% interval.intStarts - array of interval starts (in seconds) +% interval.intEnds - array of interval ends (in seconds) +% +% nexData.waves - array of wave structures +% wave.name - name of neuron variable +% wave.NPointsWave - number of data points in each wave +% wave.WFrequency - A/D frequency for wave data points +% wave.timestamps - array of wave timestamps (in seconds) +% wave.waveforms - matrix of waveforms (in milliVolts), each +% waveform is a vector +% +% nexData.contvars - array of contvar structures +% contvar.name - name of neuron variable +% contvar.ADFrequency - A/D frequency for data points +% +% continuous (a/d) data come in fragments. Each fragment has a timestamp +% and an index of the a/d data points in data array. The timestamp corresponds to +% the time of recording of the first a/d value in this fragment. +% +% contvar.timestamps - array of timestamps (fragments start times in seconds) +% contvar.fragmentStarts - array of start indexes for fragments in contvar.data array +% contvar.data - array of data points (in milliVolts) +% +% nexData.markers - array of marker structures +% marker.name - name of marker variable +% marker.timestamps - array of marker timestamps (in seconds) +% marker.values - array of marker value structures +% marker.value.name - name of marker value +% marker.value.strings - array of marker value strings +% +% +% make it optional to supply a file or list of files; if none supplied, +% then use uigetfile +% +% change log: +% 8/1/12: found that sometimes you get "pops" from high to low to high, +% but can also get them low to high to low. Added code to take +% account of this possibility. +% 03/25/2020 - this may not be necessasry anymore + +analog_thresh = 2; % volts + +writeFile = true; + +% names of what each digital line represents. I think this is correct as of +% 3/25/2020. -DL +dig_linenames = {'', 'foodport', 'food', 'nose5', 'houselight', 'nose4', ... + 'cue5', 'nose3', 'cue4', 'nose2', 'cue3', 'nose1', ... + 'cue2', 'gotrial', 'cue1', 'camframe'}; +% names of what each analog line represents. I think this is correct as of +% 3/25/2020. -DL +analog_linenames = {'tone1','tone2','whitenoise'}; + +% concatenate the linenames so we have a full list +all_linenames = [dig_linenames,analog_linenames]; + +for iarg = 1 : 2 : nargin - 3 + switch lower(varargin{iarg}) + case 'writefile' + writeFile = varargin{iarg + 1}; + case 'analog_thresh' + analog_thresh = varargin{iarg + 1}; + end +end + +num_dig_lines = length(dig_linenames); +% num_analog_lines = length(analog_linenames); + + +% numLines = 16; % 16 digital in lines on the intan system. doesn't count the analog in lines being used as digital lines +numBytesPerSample = 2; % assume uint16's +nSamples = length(dig_in); +totalBytes = nSamples * numBytesPerSample; + +% pull in the sample rate from the intan_info structure +nSampleRate = max(intan_info.frequency_parameters.board_adc_sample_rate,... + intan_info.frequency_parameters.board_dig_in_sample_rate); % these should always be the same +maxNumEvents = 20000; % will choke if there are more than this many events on a line + +% Set up the NEX file data structure +nexData.version = 100; +nexData.comment = 'Converted by intan2nex.m. Dan Leventhal and Jen Magnusson, 2020'; +nexData.freq = nSampleRate; +nexData.tbeg = 0; +nexData.tend = totalBytes/(numBytesPerSample*nSampleRate); +nexData.events = {}; +on.events = {}; +off.events = {}; + +dataOffset = 0; + +usedLines = []; +numUsedLines = 0; +num_usedDigLines = 0; +numLines = length(all_linenames); +for i=1:numLines + if strcmp(all_linenames{i}, ''); continue; end + numUsedLines = numUsedLines + 1; + if i <= num_dig_lines + num_usedDigLines = num_usedDigLines + 1; + end + usedLines(end+1) = i; + + % create nexData.events for each time a line goes "high" or "low". Note + % that transitions from high to low are actually lights turning on, + % nose ports becoming occupied, etc. + + % COMMENTS BELOW NOT RELEVANT RIGHT NOW (3/25/2020) BECAUSE WE'RE NOT USING + % OPTOGENETICS IN THESE EXPERIMENTS... + % this chunk of code will name the events differently for laser + % and shutter lines. 'On' events are generally going from high + % to low (ie, nose-pokes, lighting cue lights, etc) because the + % relays to the MedAssociates boxes are inverted. Laser "on" + % events, however, are indicated by low to high transitions. + % The laser shutter opens on a high value and closes on a low + % value. -DL 02/03/2012 + if contains(lower(all_linenames{i}), 'laser') + % this is a laser line + nexData.events{end+1}.name = [all_linenames{i} 'Off']; + nexData.events{end}.timestamps = {}; + + nexData.events{end+1}.name = [all_linenames{i} 'On']; + nexData.events{end}.timestamps = {}; + + elseif contains(lower(all_linenames{i}), 'video') + % this is a video trigger line + nexData.events{end+1}.name = [all_linenames{i} 'Off']; + nexData.events{end}.timestamps = {}; + + nexData.events{end+1}.name = [all_linenames{i} 'On']; + nexData.events{end}.timestamps = {}; + + elseif contains(lower(all_linenames{i}), 'shutter') + % this is a shutter line + nexData.events{end+1}.name = [all_linenames{i} 'Closed']; + nexData.events{end}.timestamps = {}; + + nexData.events{end+1}.name = [all_linenames{i} 'Open']; + nexData.events{end}.timestamps = {}; + + elseif contains(lower(all_linenames{i}), 'nose') + % this is a nose in/out line + nexData.events{end + 1}.name = [all_linenames{i} 'In']; + nexData.events{end}.timestamps = {}; + + nexData.events{end + 1}.name = [all_linenames{i} 'Out']; + nexData.events{end}.timestamps = {}; + + else + % all other channels + nexData.events{end+1}.name = [all_linenames{i} 'On']; + nexData.events{end}.timestamps = {}; + + nexData.events{end+1}.name = [all_linenames{i} 'Off']; + nexData.events{end}.timestamps = {}; + end + +end + +allLines = false(numUsedLines, nSamples); +allOnEvents = zeros(numUsedLines, maxNumEvents); % maximum 20000 events or so +allOffEvents = zeros(numUsedLines, maxNumEvents); +onEventIdx = ones(numUsedLines,1); +offEventIdx = ones(numUsedLines,1); + +% digital_data = readIntanDigitalFile(dig_in); + +% CREATE A LOOP TO READ IN BLOCKS OF DATA AND CONVERT TO .NEX EVENTS +% Collect line values from every line we care about +for i=1:numUsedLines + if i <= num_usedDigLines + allLines(i,:) = bitget(dig_in, usedLines(i)); % dig_in should really be the array of digital inputs read in + else + analog_idx = i - num_usedDigLines; + allLines(i,:) = (analog_in(analog_idx,:) > analog_thresh); % analog_in should be data read from the analog_in file + end +end + + % Sometimes all the lines are low at the same time + % This is incorrect, and we're going to fix it right here + % in software. + % NOTE: this doesn't explicitly detect "pops", where + % the lines go low then high again, but instead + % just detects whether all lines are low. Should be fine, I _think_... + % above is from AW. + + % this needs to be changed because it's not always true that + % ALL lines "pop" simultaneously. Rewrite the algorithm to + % detect transitions to "low" and then immediately back to + % "high". This happens one SOME but not all lines every time a + % digital port read is initiated in LV. Fucking annoying. There + % may be a way to fix this with a clever combination of + % resistors, but I think this software work-around will be OK. + + % hopefully, this isn't a problem in the Intan system, so I commented it + % out - DL, 12/2019 + +% for iLine = 1 : numLines +% highIdx = find([lastSamp(iLine), allLines(iLine,:)] == 1); +% % compute spacing between high values along each line +% if isempty(highIdx); continue; end; +% +% highDiff = diff(highIdx); +% popIdx = (highDiff == 2); % find indices of events where line went from high to low to high in 3 samples +% +% % 8/1/12 DL%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% lowIdx = find([lastSamp(iLine), allLines(iLine,:)] == 0); +% lowDiff = diff(lowIdx); +% inversePopIdx = (lowDiff == 2); % find indices of events where line went from low to high to low in 3 samples +% % 8/1/12 DL%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% allLines(iLine, highIdx(popIdx)) = 1; +% allLines(iLine, lowIdx(inversePopIdx)) = 0; % 8/1/12 DL +% end +% +% % below is left-over from when a line pop was considered when +% % ALL lines go low simultaneously +% % for i=1:length(idx) +% % +% % allLines(:,idx(i)) = allLines(:,idx(i)-1); +% % end +% +% Now we'll extract on and off times +for i=1:numUsedLines + % A channel is considered to have flipped "on" when it goes from 1 to 0 + % A channel is considered to have flipped "off" when it goes from 0 to 1 + + % added lastSamp into the calculation below to account for + % the possibility that a transition takes place exactly + % where a new block of values is loaded. -DL 20110627 + onTimes = find( diff(allLines(i,:)) == -1 )/nSampleRate; + offTimes = find( diff(allLines(i,:)) == 1 )/nSampleRate; + numOn = length(onTimes); + numOff = length(offTimes); + allOnEvents(i,onEventIdx(i):onEventIdx(i)+numOn-1) = onTimes; + allOffEvents(i,offEventIdx(i):offEventIdx(i)+numOff-1) = offTimes; + onEventIdx(i) = onEventIdx(i) + numOn; + offEventIdx(i) = offEventIdx(i) + numOff; +end + +% lastSamp = allLines(:, end); +% + + +% Stick in the events +for i=1:numUsedLines + nexData.events{i*2-1}.timestamps = unique(allOnEvents(i,1:onEventIdx(i)-1)'); + nexData.events{i*2}.timestamps = unique(allOffEvents(i,1:offEventIdx(i)-1)'); +end +nexData.events = nexData.events'; + +% Make intervals +nexData.intervals = {}; +for i=1:numUsedLines + + intStarts = nexData.events{i*2-1}.timestamps; + intEnds = nexData.events{i*2}.timestamps; + + if isempty(intEnds) || isempty(intStarts); continue; end + + intEnds = intEnds( intEnds > intStarts(1) ); + + if isempty(intEnds); continue; end + intStarts = intStarts( intStarts < intEnds(end) ); + + nexData.intervals{end+1}.name = all_linenames{usedLines(i)}; + nexData.intervals{end}.intStarts = intStarts; % notice we used end+1 above. that created the entry, and now we can just refer to it as "end" + nexData.intervals{end}.intEnds = intEnds; +end +nexData.intervals = nexData.intervals'; % stupid, STUPID requirement for writeNexFile... + +% if writeFile +% writeNexFile(nexData, [filename '.nex']); +% end \ No newline at end of file diff --git a/Helpers/display_scalogram.m b/Helpers/display_scalogram.m new file mode 100644 index 00000000..e7780024 --- /dev/null +++ b/Helpers/display_scalogram.m @@ -0,0 +1,48 @@ +function [outputArg1,outputArg2] = display_scalogram(scalo, t_window, fb, varargin) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here + +cmap = 'jet'; +h_ax = 0; +c_lim = [0, 0]; + +f_ticks = [1, 10, 20, 50, 100]; + +for i_arg = 4 : 2 : nargin - 1 + switch lower(varargin{iarg}) + case 'colormap' + cmap = varargin{iarg + 1}; + case 'ax' + h_ax = varargin{iarg + 1}; + case 'fticks' + f_ticks = varargin{iarg + 1}; + case 'clim' + c_lim = varargin{iarg + 1}; + end +end + +if h_ax == 0 + figure; + h_ax = gca; +end + +num_samples = size(scalo, 2); + +t = linspace(t_window(1), t_window(2), num_samples); +f = centerFrequencies(fb); + +axes(h_ax) + +surface(t, f, scalo); + +axis tight +shading flat + +if any(c_lim ~= 0) + set(gca,'clim',c_lim) +end +set(gca,'ytick',f_ticks); +set(gca,'yscale','log') + +colormap(cmap) +end \ No newline at end of file diff --git a/Helpers/extract_perievent_data.m b/Helpers/extract_perievent_data.m new file mode 100644 index 00000000..db029d00 --- /dev/null +++ b/Helpers/extract_perievent_data.m @@ -0,0 +1,29 @@ +function perievent_data = extract_perievent_data(ephys_data, trials, event_name, t_window, Fs) +%UNTITLED2 Summary of this function goes here +% INPUTS +% ephys_data - num_channels x num_samples array +% ts - vector of timestamps with times in seconds +% +% Detailed explanation goes here + +ts = ts_from_trials(trials, event_name); +num_trials = length(ts); +num_channels = size(ephys_data, 1); +total_samples = size(ephys_data, 2); + +samp_window = round(t_window * Fs); +center_samps = round(ts * Fs); +samp_windows = center_samps + samp_window; +samps_per_window = range(samp_window) + 1; + +perievent_data = zeros(num_trials, num_channels, samps_per_window); + +for i_trial = 1 : num_trials + + if samp_windows(i_trial, 1) < 1 || samp_windows(i_trial, 2) > total_samples + % if window starts before start of recording or ends after end of + % recording, skip + continue + end + perievent_data(i_trial, :, :) = ephys_data(:, samp_windows(i_trial, 1) : samp_windows(i_trial, 2)); +end \ No newline at end of file diff --git a/Helpers/extract_trials_by_features.m b/Helpers/extract_trials_by_features.m new file mode 100644 index 00000000..602fde58 --- /dev/null +++ b/Helpers/extract_trials_by_features.m @@ -0,0 +1,63 @@ +function [valid_trials, valid_trial_flags] = extract_trials_by_features(trials, trialfeatures) +% INPUTS +% trials +% trialfeatures - string containing trial features to extract. If any of +% the following strings are containes in 'trialfeatures', the +% following will be extracted. Can do this in any combination +% 'correct' - extracts correct trials +% 'wrong' - extracts incorrect trials +% 'moveright' - extracts trials in which rat moved right +% 'moveleft' - extracts trials in which rat moved left +% 'cuedleft' - extracts trials in which tone prompted rat to move +% left +% 'cuedright' - extracts trials in which tone prompted rat to move +% right +% 'falsestart' - extracts false start trials +% Detailed explanation goes here + +num_trials = length(trials); +valid_trial_flags = true(num_trials, 1); +if contains(lower(trialfeatures), 'correct') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'correct', true); +end + +if contains(lower(trialfeatures), 'wrong') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'correct', false); +end + +if contains(lower(trialfeatures), 'moveright') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'movementDirection', 1); +end + +if contains(lower(trialfeatures), 'moveleft') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'movementDirection', 2); +end + +if contains(lower(trialfeatures), 'cuedleft') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'tone', 1); +end + +if contains(lower(trialfeatures), 'cuedright') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'tone', 2); +end + +if contains(lower(trialfeatures), 'falsestart') + valid_trial_flags = valid_trial_flags & find_trials_by_field(trials, 'falseStart', 1); +end + +valid_trials = trials(valid_trial_flags); + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function is_valid_trial = find_trials_by_field(trials, field, value) + +num_trials = length(trials); +is_valid_trial = false(num_trials, 1); + +for i_trial = 1 : num_trials + is_valid_trial(i_trial) = (trials(i_trial).(field) == value); +end + +end \ No newline at end of file diff --git a/Helpers/extract_trials_by_outcome.m b/Helpers/extract_trials_by_outcome.m new file mode 100644 index 00000000..b1237f09 --- /dev/null +++ b/Helpers/extract_trials_by_outcome.m @@ -0,0 +1,28 @@ +function [outputArg1,outputArg2] = extract_trials_by_outcome(trials, trialoutcome) +% INPUTS +% trials +% trialoutcome +% Detailed explanation goes here + +valid_trial_idx = +if contains(lower(trialoutcome), 'correct') + +end + +if contains(lower(trialoutcome), 'moveright') + +end + +if contains(lower(trialoutcome), 'moveleft') + +end +outputArg1 = inputArg1; +outputArg2 = inputArg2; +end + + +function is_valid_trial = find_trials_by_field(trials, field, value) + +num_trials = length(trials); + +for i_trial = 1 : num_trials diff --git a/Helpers/find_physiology_data.m b/Helpers/find_physiology_data.m new file mode 100644 index 00000000..663382ca --- /dev/null +++ b/Helpers/find_physiology_data.m @@ -0,0 +1,43 @@ +function physiology_folder = find_physiology_data(session_dir) + +physiology_folder = ''; + +[~, session_name, ~] = fileparts(session_dir); +str_parts = split(session_name, '_'); +ratID = str_parts{1}; + + +if length(str_parts) == 1 + % workaround for a poorly named folder + return +end +if strcmpi('str_parts{2}', 'check') + % workaround for a poorly named pair of folders + return +end + +session_datestr = str_parts{2}(1:8); % assume yyyymmdd date format + +rat_date = strcat(ratID, '_', session_datestr); + +subdirs = dir(fullfile(session_dir, strcat(rat_date, '*'))); + +num_subdirs = length(subdirs); + +for i_dir = 1 : num_subdirs + + cur_path = fullfile(session_dir, subdirs(i_dir).name); + if isfolder(cur_path) + + % look for an amplifier.dat and info.rhd file + amp_file = fullfile(cur_path, 'amplifier.dat'); + info_file = fullfile(cur_path, 'info.rhd'); + + if isfile(amp_file) && isfile(info_file) + physiology_folder = cur_path; + end + end + +end + +end \ No newline at end of file diff --git a/Helpers/get_rat_list.m b/Helpers/get_rat_list.m new file mode 100644 index 00000000..74c309c0 --- /dev/null +++ b/Helpers/get_rat_list.m @@ -0,0 +1,19 @@ +function [rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list() +% list of rats to be analyzed from thalamic recordings +% update rat_nums (and hopefully not ratnums_with_bad_histo) to indicate +% which rats should be analyzed + +rat_nums = [326, 327, 372, 374, 376, 378, 379, 394, 395, 396, 411, 412, 413, 419, 420, 425]; + +ratnums_with_bad_histo = [374, 376, 396, 413]; + +rats_with_good_histo = 0; +for i_rat = 1 : length(rat_nums) + ratIDs{i_rat} = sprintf('R%04d', rat_nums(i_rat)); + + if ~ismember(rat_nums(i_rat), ratnums_with_bad_histo) + rats_with_good_histo = rats_with_good_histo + 1; + + ratIDs_goodhisto{rats_with_good_histo} = ratIDs{i_rat}; + end +end \ No newline at end of file diff --git a/Helpers/get_shank_and_site_num.m b/Helpers/get_shank_and_site_num.m new file mode 100644 index 00000000..898a4b1c --- /dev/null +++ b/Helpers/get_shank_and_site_num.m @@ -0,0 +1,47 @@ +function [column_num,site_num] = get_shank_and_site_num(probe_type, row_idx) +%UNTITLED7 Summary of this function goes here +% INPUTS +% row_idx = the index of the row in the ordered_lfp array. It should be +% ordered such that we start at shank 1, most dorsal site, then go +% down the shank to site 8 (most ventral sitefor an NN8x8), then +% shank 2 running from dorsal to ventral, etc. For a Cambridge probe, +% it should start at the most dorsal site and go down 16 sites, with +% 4 columns of electrodes total +% +% OUTPUTS +% column_num - number of recording column - could be a single shank, or +% there could be multiple columns of recording sites per shank +% site_num - site going from dorsal to ventral along the column (note, +% might not be a physical site for bipolar). e.g., site 1 is the most +% dorsal, site 2 ventral to site 1, etc, then start over in the next +% column + +probe_parts = split(probe_type, '_'); + +% which style of probe was used? +switch lower(probe_parts{1}) + case 'nn8x8' + % 8 shanks with 8 sites each + sites_per_column = 8; + + case 'assy156' + sites_per_column = 16; + + case 'assy236' + sites_per_column = 16; + +end + +% monopolar vs bipolar +switch lower(probe_parts{2}) + + case 'monopolar' + signals_per_column = sites_per_column; + + case 'bipolar' + signals_per_column = sites_per_column - 1; + +end + +column_num = ceil(row_idx / signals_per_column); +site_num = row_idx - (column_num-1) * signals_per_column; \ No newline at end of file diff --git a/Helpers/readLogData.m b/Helpers/readLogData.m new file mode 100644 index 00000000..1bf0b885 --- /dev/null +++ b/Helpers/readLogData.m @@ -0,0 +1,98 @@ +function logData = readLogData(fname) +% +% update 08/22/2014 to allow varargin for filename +% +% usage: logData = readLogData( fname ) +% +% INPUTS: +% fname - name of the .log file +% +% OUTPUTS: +% logData - structure with the following fields: +% fileVersion (uint16) - version of the logData file written by LabView +% taskID (uint8) - this is a task identifier (ie, stop-signal, +% go-nogo, simple choice, RL, food-water, etc.). This number +% should match with the code used in the sql database +% taskVersion - version number of the specific task. This differs +% from "fileVersion" in that fileVersion refers to the log file +% structure, while "taskVersion" refers to the version of the +% actual data written for the specific task +% subject - string containing the subject name. Max 10 characters in +% fileVersion 1 +% date - string containing the data formatted as yyyymmdd +% startTime - string containing 24-hour start time based on the +% behavior computer clock, in 'HH:MM' format. +% comment - string containing a session comment (max 1024 characters) +% +% After that is a collection of "header" fields. The names of these +% fields are written into the .log file. These are parameters +% that do not change over the course of a session and are +% task-specific. +% +% After that comes the actual data. The structure data field names +% are also written into the .log file and are task-specific. + +%fname = varargin{1}; //there's only one input, so no need for varargin +bitOrder = 'b'; + +commentLength = 200; +%open the file that was input to read from +fid = fopen(fname, 'r'); + +logData.fileVersion = fread(fid, 1, 'uint16', 0, bitOrder); +if logData.fileVersion > 1000 % indicates that this is not the standard log file for Leventhal lab, could be a legacy from Berke lab + logData = []; + return; +end + +%fill in fields of logData from the file +logData.taskID = fread(fid, 1, 'uint8', 0, bitOrder); +logData.taskVersion = fread(fid, 1, 'uint8', 0, bitOrder); +logData.subject = deblank(fread(fid, 10, '*char')'); +logData.date = fread(fid, 8, '*char')'; +logData.startTime = fread(fid, 5, '*char')'; + +%change positions within the file +fseek(fid, 2 * 1024, 'bof'); + +%get rid of null characters within the comment +logData.comment = deblank(fread(fid, 1024, '*char')'); + +fseek(fid, 3 * 1024, 'bof'); +% read in the header fields +fullHeaderString = deblank(fread(fid, 1024, '*char')'); +dlmIdx = findstr(fullHeaderString, ','); % find the location of all the commas +dlmIdx = [0, dlmIdx, length(fullHeaderString)+1]; +numHeaderFields = length(dlmIdx) - 1; +headerFieldNames = cell(1, numHeaderFields); + +for iField = 1 : numHeaderFields + headerFieldNames{iField} = fullHeaderString(dlmIdx(iField)+1:dlmIdx(iField+1)-1); +end + +fseek(fid, 4 * 1024, 'bof'); +% read in the values for the header fields +for iField = 1 : numHeaderFields + logData.(headerFieldNames{iField}) = fread(fid, 1, 'double', 0, bitOrder); +end + +fseek(fid, 5 * 1024, 'bof'); +% read in the data fields +fullDataString = deblank(fread(fid, 1024, '*char')'); +dlmIdx = findstr(fullDataString, ','); % find the location of all the commas +dlmIdx = [0, dlmIdx, length(fullDataString)+1]; +numDataFields = length(dlmIdx) - 1; +dataFieldNames = cell(1, numDataFields); +for iField = 1 : numDataFields + dataFieldNames{iField} = fullDataString(dlmIdx(iField)+1:dlmIdx(iField+1)-1); +end + +fseek(fid, 6 * 1024, 'bof'); +% read in the actual data +data = fread(fid, [numDataFields, inf], 'double', 0, bitOrder); +if ~isempty(data) + for iField = 1 : numDataFields + logData.(dataFieldNames{iField}) = data(iField, :)'; + end +end +fclose(fid); \ No newline at end of file diff --git a/Helpers/read_Jen_xls_summary.m b/Helpers/read_Jen_xls_summary.m new file mode 100644 index 00000000..7ff7e2e5 --- /dev/null +++ b/Helpers/read_Jen_xls_summary.m @@ -0,0 +1,16 @@ +function xls_data = read_Jen_xls_summary(filename, sheetname) +%UNTITLED8 Summary of this function goes here +% Detailed explanation goes here + +% update this function when need information from the other spreadsheets + +switch sheetname + case 'probe_type' + xls_data = readtable(filename,'filetype','spreadsheet',... + 'sheet','probe_type',... + 'texttype','string'); + otherwise + xls_data = ''; +end + +end \ No newline at end of file diff --git a/Helpers/ts_from_trials.m b/Helpers/ts_from_trials.m new file mode 100644 index 00000000..3f822976 --- /dev/null +++ b/Helpers/ts_from_trials.m @@ -0,0 +1,17 @@ +function ts = ts_from_trials(trials, event_name) +%UNTITLED6 Summary of this function goes here +% Detailed explanation goes here + +num_trials = length(trials); + +ts = NaN(num_trials, 1); + +for i_trial = 1 : num_trials + + if isfield(trials(i_trial).timestamps, event_name) + ts(i_trial) = trials(i_trial).timestamps.(event_name); + end + +end + +end diff --git a/LFPs/calculate_bipolar_LFPs.m b/LFPs/calculate_bipolar_LFPs.m new file mode 100644 index 00000000..3b942c75 --- /dev/null +++ b/LFPs/calculate_bipolar_LFPs.m @@ -0,0 +1,40 @@ +function [bipolar_LFPs, probe_site_mapping] = calculate_bipolar_LFPs(lfp, probe_type) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here + +% re-arrange the rows to reflect the order of LFPs +probe_site_mapping = probe_site_mapping_all_probes(probe_type); + +% first, rearrange field potentials so they are sorted from dorsal to +% ventral + +sorted_lfps = lfp(probe_site_mapping, :); +num_lfps = size(lfp, 1); % assume each row is a recording channel +num_pts = size(lfp, 2); + +switch lower(probe_type) + case 'nn8x8' + sites_per_column = 8; + case 'assy156' + sites_per_column = 16; + case 'assy236' + sites_per_column = 16; +end +num_columns = num_lfps / sites_per_column; +num_bipolar_lfps = num_lfps - num_columns; + +bipolar_LFPs = zeros(num_bipolar_lfps, num_pts); + +for i_sitecol = 1 : num_columns + + start_LFP_row = (i_sitecol - 1) * sites_per_column + 1; + end_LFP_row = i_sitecol * sites_per_column; + + start_bipolar_row = (i_sitecol-1) * (sites_per_column-1) + 1; + end_bipolar_row = i_sitecol * (sites_per_column-1); + + bipolar_LFPs(start_bipolar_row:end_bipolar_row, :) = diff(sorted_lfps(start_LFP_row:end_LFP_row, :), 1, 1); + +end + +end \ No newline at end of file diff --git a/intan_choice_task_navigation_utils/find_rawdata_folder.m b/intan_choice_task_navigation_utils/find_rawdata_folder.m new file mode 100644 index 00000000..dab30548 --- /dev/null +++ b/intan_choice_task_navigation_utils/find_rawdata_folder.m @@ -0,0 +1,67 @@ +function session_path = find_rawdata_folder(input1, varargin) +%UNTITLED Summary of this function goes here +% Detailed explanation goes here + +parent_directory = 'Z:\data\ChoiceTask'; + +if nargin > 1 + if strcmpi(varargin{1}, 'parent_directory') + parent_directory = varargin{2}; + end +end +if nargin > 2 + if strcmpi(varargin{2}, 'parent_directory') + parent_directory = varargin{3}; + end +end + +if nargin == 1 || (nargin > 1 && strcmpi(varargin{1}, 'parent_directory')) + % assume the full session name was given - i.e., 'RXXXX_YYYYMMDDz' + + str_parts = split(input1, '_'); + ratID = str_parts{1}; + + rat_rd_folder = find_rat_rawdata_folder(parent_directory, ratID); + + if isfolder(fullfile(rat_rd_folder, input1)) + session_path = fullfile(rat_rd_folder, input1); + else + session_path = ''; + end + +elseif nargin == 2 + % assume the first argument is the rat number or ratID, the second + % argument is the date string or date (if date, assume it's session a) + + if isinteger(input1) + ratID = sprintf('R%04d', input1); + elseif ischar(input1) + ratID = input1; + end + rat_rd_folder = find_rat_rawdata_folder(parent_directory, ratID); + + if ischar(varargin{1}) + session_name = strcat(ratID, '_', varargin{1}); + elseif isdatetime(varargin{1}) + date_string = datestr(varargin{1}, 'yyyymmdd'); + session_name = strcat(ratID, '_', date_string, 'a'); + end + + if isfolder(fullfile(rat_rd_folder, session_name)) + session_path = fullfile(rat_rd_folder, session_name); + else + session_path = ''; + end + +end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function rat_rd_folder = find_rat_rawdata_folder(parent_directory, ratID) + +rat_folder = fullfile(parent_directory, ratID); +rat_rd_folder = fullfile(rat_folder, strcat(ratID, '-rawdata')); + +end \ No newline at end of file diff --git a/intan_choice_task_navigation_utils/get_rawdata_ephys_folder.m b/intan_choice_task_navigation_utils/get_rawdata_ephys_folder.m new file mode 100644 index 00000000..6f23d2b4 --- /dev/null +++ b/intan_choice_task_navigation_utils/get_rawdata_ephys_folder.m @@ -0,0 +1,26 @@ +function rawdata_ephys_folder = get_rawdata_ephys_folder(rawdata_folder,session_name) +%UNTITLED13 Summary of this function goes here +% Detailed explanation goes here + +rawdata_session_folder = fullfile(rawdata_folder, session_name); + +session_name_parts = split(session_name, '_'); +session_date_str = session_name_parts{2}(1:8); +intan_date_str = session_date_str(3:8); + +test_name = strcat(session_name_parts{1}, '_', session_date_str, '*', intan_date_str, '*'); +test_name = fullfile(rawdata_session_folder, test_name); + +rawdata_ephys_dirs = dir(test_name); + +if length(rawdata_ephys_dirs) == 1 + rawdata_ephys_folder = fullfile(rawdata_ephys_dirs.folder, rawdata_ephys_dirs.name); +elseif length(rawdata_ephys_dirs) > 1 + sprintf('multiple ephys folders found for %s', session_name) + rawdata_ephys_folder = ''; +else + sprintf('no ephys folders found for %s', session_name) + rawdata_ephys_folder = ''; +end + +end \ No newline at end of file From bf64cceb281456a6b3ac18e8e37a50a69a832aa5 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Mon, 8 May 2023 14:44:01 -0400 Subject: [PATCH 11/19] updating with Dan's code --- .../createTrialsStruct_simpleChoice_Intan.m | 24 ++- LFPs/calculate_trial_spectrograms.m | 134 ++++++++++++++++ ...trial_spectrograms_from_saved_bipolars.asv | 137 ++++++++++++++++ ...e_trial_spectrograms_from_saved_bipolars.m | 151 ++++++++++++++++++ LFPs/create_scalogram_map.m | 63 ++++++++ LFPs/diff_lfp_from_monopolar.m | 39 +++++ ...cript_display_session_trial_spectrograms.m | 62 +++++++ LFPs/script_extract_LFPs_DL.m | 66 ++++++++ LFPs/script_extract_bipolar_LFPs_DL.m | 63 ++++++++ 9 files changed, 726 insertions(+), 13 deletions(-) create mode 100644 LFPs/calculate_trial_spectrograms.m create mode 100644 LFPs/calculate_trial_spectrograms_from_saved_bipolars.asv create mode 100644 LFPs/calculate_trial_spectrograms_from_saved_bipolars.m create mode 100644 LFPs/create_scalogram_map.m create mode 100644 LFPs/diff_lfp_from_monopolar.m create mode 100644 LFPs/script_display_session_trial_spectrograms.m create mode 100644 LFPs/script_extract_LFPs_DL.m create mode 100644 LFPs/script_extract_bipolar_LFPs_DL.m diff --git a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m index a4cf1234..5d9f00cd 100644 --- a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m +++ b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m @@ -95,7 +95,7 @@ %why are there two Idxs? is this legacy for some system that had these %times on different rows or something? if isempty(GO_startIdx) - error('lognexmerge:lognexmismatch', 'Could not find trial start sequence.'); + error('Could not find trial start sequence.'); else GO_endIdx = GO_startIdx; end @@ -459,12 +459,11 @@ trialData.countsAsTrial = 0; trialData.valid = 0; trialData.correct = 0; - else + else trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 trialData.timestamps.sideOut = ... events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); - trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example trialData.timestamps.centerOut; @@ -473,7 +472,11 @@ trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... trialData.timestamps.sideIn; end - + trialData.timestamps.sideIn = sideInAfterCue(1); + trialData.timestamps.sideOut = ... + events{NoseOutidx(CueID(1) + 1)}.timestamps(events{NoseOutidx(CueID(1) + 1)}.timestamps > NoseInTS(1)); + trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); + % done this way to prevent the algorithm from counting a nose-out else % tone 1 (low tone) was played trialData.tone = 1; @@ -497,7 +500,6 @@ trialData.timestamps.sideOut = ... events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); - trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example trialData.timestamps.centerOut; @@ -510,6 +512,8 @@ % done this way to prevent the algorithm from counting a nose-out % event that may be left over from a previous trial end % end if isempty(trialEvents{Tone1idx}.timestamps) + + trialData.timestamps.foodClick = trialEvents{FHidx}.timestamps; % calculate timing of events within the trial trialData.timing.pretone = trialData.timestamps.tone - ... @@ -522,7 +526,7 @@ % depending on how the behavior software was running and if the food % port sensor was working at all - if FoodSensidx ~= 0 && ~isempty(sideInAfterCue) % the food port sensor was working and there was a valid sideInAfterCue event + if FoodSensidx ~= 0 % the food port sensor was working firstFoodRetrieval = find(events{FoodSensidx}.timestamps > ... trialData.timestamps.sideIn); if ~isempty(firstFoodRetrieval) @@ -543,13 +547,7 @@ % and target ports match up boxLogConflicts.outcome = ~(logTrial.outcome == 0); boxLogConflicts.RT = ~(abs(logTrial.RT - trialData.timing.RT) < timingTolerance); - if ~isempty(sideInAfterCue) - % no MT is there was no sideIn, which could happen on a "correct" - % trial according to the behavior log if this was the very last - % trial so the sideIn was not registered on the Intan system - % -DL 12/19/2022 - boxLogConflicts.MT = ~(abs(logTrial.MT - trialData.timing.MT) < timingTolerance); - end + boxLogConflicts.MT = ~(abs(logTrial.MT - trialData.timing.MT) < timingTolerance); boxLogConflicts.pretone = ~(abs(logTrial.pretone - trialData.timing.pretone) < timingTolerance); boxLogConflicts.centerNP = ~(logTrial.Center == trialData.centerNP); boxLogConflicts.sideNP = ~(logTrial.Target == trialData.sideNP); diff --git a/LFPs/calculate_trial_spectrograms.m b/LFPs/calculate_trial_spectrograms.m new file mode 100644 index 00000000..f1bf6fb4 --- /dev/null +++ b/LFPs/calculate_trial_spectrograms.m @@ -0,0 +1,134 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_types = {'monopolar', 'bipolar'}; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +t_window = [-2.5, 2.5]; +event_list = {'cueOn', 'centerIn', 'tone', 'centerOut' 'sideIn', 'sideOut', 'foodClick', 'foodRetrieval'}; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + % load trials structure + trials_name = sprintf('%s_trials.mat', session_name); + trials_name = fullfile(cur_dir, trials_name); + + if ~exist(trials_name) + sprintf('no trials structure found for %s', session_name) + continue + end + + load(trials_name) + + selected_trials = extract_trials_by_features(trials, trials_to_analyze); + if isempty(selected_trials) + sprintf('no %s trials found for %s', trials_to_analyze, session_name) + continue + end + + lfp_fname = strcat(session_name, '_lfp.mat'); + if ~isfile(lfp_fname) + sprintf('%s not found, skipping', lfp_fname) + continue + end + + lfp_data = load(lfp_fname); + + Fs = lfp_data.actual_Fs; + samp_window = round(t_window * Fs); + samples_per_event = range(samp_window) + 1; + fb = cwtfilterbank('signallength', samples_per_event, ... + 'samplingfrequency', Fs, ... + 'wavelet','amor',... + 'frequencylimits', [1, 100]); + + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + + for i_lfptype = 1 : length(lfp_types) + + lfp_type = lfp_types{i_lfptype}; + if strcmpi(lfp_type, 'bipolar') + ordered_lfp = diff_lfp_from_monopolar(ordered_lfp, probe_type); + end + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + num_channels = size(ordered_lfp, 1); + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s, %s', session_name, event_name, lfp_type) + + perievent_data = extract_perievent_data(ordered_lfp, selected_trials, event_list{4}, t_window, Fs); + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + % scalo_folder = sprintf('%s_scalos_%s', session_name, event_name); + % scalo_folder = fullfile(cur_dir, scalo_folder); + if ~exist(scalo_folder, 'dir') + mkdir(scalo_folder) + end + + for i_channel = 1 : num_channels + [shank_num, site_num] = get_shank_and_site_num(probe_lfp_type, i_channel); + + scalo_name = sprintf('%s_scalos_%s_%s_shank%02d_site%02d.mat',session_name, lfp_type, event_name, shank_num, site_num); + scalo_name = fullfile(scalo_folder, scalo_name); + +% if exist(scalo_name, 'file') +% continue +% end + + event_triggered_lfps = squeeze(perievent_data(:, i_channel, :)); + + % comment back in if running on a machine without a gpu +% disp('cpu') +% tic +% [event_related_scalos, ~, coi] = trial_scalograms(event_triggered_lfps, fb); +% toc + + etl_g = gpuArray(event_triggered_lfps); + [event_related_scalos, ~, coi] = trial_scalograms(etl_g, fb); + + save(scalo_name, 'event_related_scalos', 'event_triggered_lfps', 'fb', 'coi', 't_window', 'i_channel'); + % saving i_channel is a check to make sure that shank + % and site are numbered correctly later + + end + end + end + end + +end \ No newline at end of file diff --git a/LFPs/calculate_trial_spectrograms_from_saved_bipolars.asv b/LFPs/calculate_trial_spectrograms_from_saved_bipolars.asv new file mode 100644 index 00000000..9386f40d --- /dev/null +++ b/LFPs/calculate_trial_spectrograms_from_saved_bipolars.asv @@ -0,0 +1,137 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_types = {'monopolar', 'bipolar'}; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +t_window = [-2.5, 2.5]; +event_list = {'cueOn', 'centerIn', 'tone', 'centerOut' 'sideIn', 'sideOut', 'foodClick', 'foodRetrieval'}; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + % load trials structure + trials_name = sprintf('%s_trials.mat', session_name); + trials_name = fullfile(cur_dir, trials_name); + + if ~exist(trials_name) + sprintf('no trials structure found for %s', session_name) + continue + end + + load(trials_name) + + selected_trials = extract_trials_by_features(trials, trials_to_analyze); + if isempty(selected_trials) + sprintf('no %s trials found for %s', trials_to_analyze, session_name) + continue + end + + lfp_fname = strcat(session_name, '_lfp.mat'); + if ~isfile(lfp_fname) + sprintf('%s not found, skipping', lfp_fname) + continue + end + + lfp_data = load(lfp_fname); + + Fs = lfp_data.actual_Fs; + samp_window = round(t_window * Fs); + samples_per_event = range(samp_window) + 1; + fb = cwtfilterbank('signallength', samples_per_event, ... + 'samplingfrequency', Fs, ... + 'wavelet','amor',... + 'frequencylimits', [1, 100]); + + [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + + for i_lfptype = 1 : length(lfp_types) + + lfp_type = lfp_types{i_lfptype}; + if strcmpi(lfp_type, 'bipolar') + lfp_fname = strcat(session_name, '_bipolar_lfp.mat'); + else + lfp_fname = strcat(session_name, '_lfp.mat'); + end + lfp_fname = fullfile(cur_dir, ) + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + num_channels = size(ordered_lfp, 1); + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s, %s', session_name, event_name, lfp_type) + + perievent_data = extract_perievent_data(ordered_lfp, selected_trials, event_list{4}, t_window, Fs); + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + % scalo_folder = sprintf('%s_scalos_%s', session_name, event_name); + % scalo_folder = fullfile(cur_dir, scalo_folder); + if ~exist(scalo_folder, 'dir') + mkdir(scalo_folder) + end + + for i_channel = 1 : num_channels + [shank_num, site_num] = get_shank_and_site_num(probe_lfp_type, i_channel); + + scalo_name = sprintf('%s_scalos_%s_%s_shank%02d_site%02d.mat',session_name, lfp_type, event_name, shank_num, site_num); + scalo_name = fullfile(scalo_folder, scalo_name); + +% if exist(scalo_name, 'file') +% continue +% end + + event_triggered_lfps = squeeze(perievent_data(:, i_channel, :)); + + % comment back in if running on a machine without a gpu +% disp('cpu') +% tic +% [event_related_scalos, ~, coi] = trial_scalograms(event_triggered_lfps, fb); +% toc + + etl_g = gpuArray(event_triggered_lfps); + [event_related_scalos, ~, coi] = trial_scalograms(etl_g, fb); + + save(scalo_name, 'event_related_scalos', 'event_triggered_lfps', 'fb', 'coi', 't_window', 'i_channel'); + % saving i_channel is a check to make sure that shank + % and site are numbered correctly later + + end + end + end + end + +end \ No newline at end of file diff --git a/LFPs/calculate_trial_spectrograms_from_saved_bipolars.m b/LFPs/calculate_trial_spectrograms_from_saved_bipolars.m new file mode 100644 index 00000000..1612abe3 --- /dev/null +++ b/LFPs/calculate_trial_spectrograms_from_saved_bipolars.m @@ -0,0 +1,151 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_types = {'monopolar', 'bipolar'}; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +t_window = [-2.5, 2.5]; +event_list = {'cueOn', 'centerIn', 'tone', 'centerOut' 'sideIn', 'sideOut', 'foodClick', 'foodRetrieval'}; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + % load trials structure + trials_name = sprintf('%s_trials.mat', session_name); + trials_name = fullfile(cur_dir, trials_name); + + if ~exist(trials_name) + sprintf('no trials structure found for %s', session_name) + continue + end + + load(trials_name) + + selected_trials = extract_trials_by_features(trials, trials_to_analyze); + if isempty(selected_trials) + sprintf('no %s trials found for %s', trials_to_analyze, session_name) + continue + end + +% lfp_fname = strcat(session_name, '_lfp.mat'); +% if ~isfile(lfp_fname) +% sprintf('%s not found, skipping', lfp_fname) +% continue +% end +% +% lfp_data = load(lfp_fname); + + Fs = lfp_data.actual_Fs; + samp_window = round(t_window * Fs); + samples_per_event = range(samp_window) + 1; + fb = cwtfilterbank('signallength', samples_per_event, ... + 'samplingfrequency', Fs, ... + 'wavelet','amor',... + 'frequencylimits', [1, 100]); + +% [ordered_lfp, intan_site_order, intan_site_order_for_trials_struct, site_order] = lfp_by_probe_site_ALL(lfp_data, probe_type); + + for i_lfptype = 1 : length(lfp_types) + + lfp_type = lfp_types{i_lfptype}; + if strcmpi(lfp_type, 'bipolar') + lfp_fname = strcat(session_name, '_bipolar_lfp.mat'); + else + lfp_fname = strcat(session_name, '_lfp.mat'); + end + lfp_fname = fullfile(cur_dir, lfp_fname); + if ~isfile(lfp_fname) + sprintf('%s not found, skipping', lfp_fname) + continue + end + + lfp_data = load(lfp_fname); + + if strcmpi(lfp_type, 'bipolar') + ordered_lfp = lfp_data.bipolar_lfp; + else + probe_site_mapping = probe_site_mapping_all_probes(probe_type); + ordered_lfp = lfp_data.lfp(probe_site_mapping, :); + end + + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + num_channels = size(ordered_lfp, 1); + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s, %s', session_name, event_name, lfp_type) + + perievent_data = extract_perievent_data(ordered_lfp, selected_trials, event_name, t_window, Fs); + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + % scalo_folder = sprintf('%s_scalos_%s', session_name, event_name); + % scalo_folder = fullfile(cur_dir, scalo_folder); + if ~exist(scalo_folder, 'dir') + mkdir(scalo_folder) + end + + for i_channel = 1 : num_channels + [shank_num, site_num] = get_shank_and_site_num(probe_lfp_type, i_channel); + + scalo_name = sprintf('%s_scalos_%s_%s_shank%02d_site%02d.mat',session_name, lfp_type, event_name, shank_num, site_num); + scalo_name = fullfile(scalo_folder, scalo_name); + +% if exist(scalo_name, 'file') +% continue +% end + + event_triggered_lfps = squeeze(perievent_data(:, i_channel, :)); + + % comment back in if running on a machine without a gpu +% disp('cpu') +% tic +% [event_related_scalos, ~, coi] = trial_scalograms(event_triggered_lfps, fb); +% toc + + etl_g = gpuArray(event_triggered_lfps); + [event_related_scalos, ~, coi] = trial_scalograms(etl_g, fb); + + save(scalo_name, 'event_related_scalos', 'event_triggered_lfps', 'fb', 'coi', 't_window', 'i_channel'); + % saving i_channel is a check to make sure that shank + % and site are numbered correctly later + + end + end + end + end + +end \ No newline at end of file diff --git a/LFPs/create_scalogram_map.m b/LFPs/create_scalogram_map.m new file mode 100644 index 00000000..392d7169 --- /dev/null +++ b/LFPs/create_scalogram_map.m @@ -0,0 +1,63 @@ +function [outputArg1,outputArg2] = create_scalogram_map(session_name,event_name,lfp_type,parent_directory) +%UNTITLED Summary of this function goes here +% function to create a map of scalograms for a specific event across all +% channels + +scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); + +h_fig = figure('papertype','usletter',... + 'PaperOrientation','landscape', ... + 'units', 'inches',... + 'position',[0 0 11 8.5]); +fig_title = sprintf('%s, %s, %s', session_name, event_name, lfp_type); + +num_cols = 8; % may need to change for the Cambridge probes +switch lfp_type + case 'monopolar' + num_rows = 8; + fname_append = ''; + case 'bipolar' + num_rows = 7; + fname_append = 'bipolar'; +end +t_layout = tiledlayout(num_rows, 8, 'tilespacing','tight'); + +for ii = 1 : 64 + shank_num = ceil(ii/num_rows); + site_num = ii - (shank_num-1) * num_rows; + + scalo_name = sprintf('%s_scalos_%s_shank%02d_site%02d.mat',session_name, event_name, shank_num, site_num); + scalo_name = fullfile(scalo_folder, scalo_name); + + load(scalo_name) +% % f = centerFrequencies(fb); +% + mean_scalo = squeeze(mean(log(abs(event_related_scalos)), 1)); + + tile_num = (site_num-1) * num_cols + shank_num; + ax = nexttile(tile_num); + display_scalogram(mean_scalo, t_window, fb, 'ax', ax); +% plot(sin(site_num*(1:10))) + if shank_num > 1 + set(gca,'yticklabel','') + end + if site_num < num_rows + set(gca,'XTickLabel','') + end +end + +title(t_layout, fig_title, 'interpreter', 'none') +xlabel(t_layout, 'time (s)') +ylabel(t_layout, 'frequency (Hz)') + +savename = sprintf('%s_%s_%s_meanlogpower.pdf', session_name, event_name, lfp_type); +fig_savename = sprintf('%s_%s_%s_meanlogpower.fig', session_name, event_name, lfp_type); +savename = fullfile(scalo_folder, savename); +fig_savename = fullfile(scalo_folder, fig_savename); + +print(savename, '-dpdf') +savefig(h_fig, fig_savename, 'compact') + +close(h_fig) + +end \ No newline at end of file diff --git a/LFPs/diff_lfp_from_monopolar.m b/LFPs/diff_lfp_from_monopolar.m new file mode 100644 index 00000000..735aeff2 --- /dev/null +++ b/LFPs/diff_lfp_from_monopolar.m @@ -0,0 +1,39 @@ +function diff_lfps = diff_lfp_from_monopolar(monopolar_ordered_lfp,probe_type) +%UNTITLED8 Summary of this function goes here +% INPUTS +% monopolar_ordered_lfp: num_channels x num_points array +% probe_type: string containing probe type. possibilities are 'nn8x8', + +num_sites = size(monopolar_ordered_lfp, 1); +num_points = size(monopolar_ordered_lfp, 2); +switch lower(probe_type) + case 'nn8x8' + % assume lfp is ordered such that monopolar_ordered_lfp(1:8,:) is + % the signal from dorsal to ventral on shank 1, + % monopolar_ordered_lfp(9:16,:) is the signal from dorsal to + % ventral on shank 2, etc. + + sites_per_shank = 8; + diff_sites_per_shank = sites_per_shank - 1; + num_shanks = num_sites / sites_per_shank; + + num_diff_sites = diff_sites_per_shank * num_shanks; + diff_lfps = zeros(num_diff_sites, num_points); + + for i_shank = 1 : num_shanks + diff_chan_start_idx = (i_shank-1) * diff_sites_per_shank + 1; + diff_chan_end_idx = i_shank * diff_sites_per_shank; + + mono_chan_start_idx = (i_shank-1) * sites_per_shank + 1; + mono_chan_end_idx = i_shank * sites_per_shank; + + % take differences going down columns + diff_lfps(diff_chan_start_idx:diff_chan_end_idx, :) = ... + diff(monopolar_ordered_lfp(mono_chan_start_idx:mono_chan_end_idx,:),1,1); + + end + +end + + +end \ No newline at end of file diff --git a/LFPs/script_display_session_trial_spectrograms.m b/LFPs/script_display_session_trial_spectrograms.m new file mode 100644 index 00000000..43138dcc --- /dev/null +++ b/LFPs/script_display_session_trial_spectrograms.m @@ -0,0 +1,62 @@ +% script to calculate scalograms for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +% change the line below to allow looping through multiple trial types, +% extract left vs right, etc. +trials_to_analyze = 'correct'; +lfp_type = 'monopolar'; +% trials_to_analyze = 'all'; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + probe_lfp_type = sprintf('%s_%s', probe_type, lfp_type); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + for i_event = 1 : length(event_list) + event_name = event_list{i_event}; + sprintf('working on session %s, event %s', session_name, event_name) + + perievent_data = extract_perievent_data(ordered_lfp, selected_trials, event_list{4}, t_window, Fs); + + scalo_folder = create_scalo_folder(session_name, event_name, parent_directory); +% scalo_folder = sprintf('%s_scalos_%s', session_name, event_name); +% scalo_folder = fullfile(cur_dir, scalo_folder); + if ~exist(scalo_folder, 'dir') + continue + end + create_scalogram_map(session_name, event_name, lfp_type, parent_directory); + + end + end + +end \ No newline at end of file diff --git a/LFPs/script_extract_LFPs_DL.m b/LFPs/script_extract_LFPs_DL.m new file mode 100644 index 00000000..1478822a --- /dev/null +++ b/LFPs/script_extract_LFPs_DL.m @@ -0,0 +1,66 @@ +% script to calculate LFPs for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +target_Fs = 500; % in Hz, target LFP sampling rate after decimating the raw signal +convert_to_microvolts = false; + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); + session_dirs = dir(fullfile(rawdata_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + phys_folder = find_physiology_data(cur_dir); + + if isempty(phys_folder) + sprintf('no physiology data found for %s', session_name) + continue + end + + lfp_fname = strcat(session_name, '_lfp.mat'); + processed_session_folder = fullfile(processed_folder, session_name); + full_lfp_name = fullfile(processed_session_folder, lfp_fname); + if ~isfolder(processed_session_folder) + mkdir(processed_session_folder) + end +% if isfile(lfp_fname) +% sprintf('%s already calculated, skipping', lfp_fname) +% continue +% end + + sprintf('working on %s', session_name) + [lfp, actual_Fs] = calculate_monopolar_LFPs(phys_folder, target_Fs, convert_to_microvolts); + + save(full_lfp_name, 'lfp', 'actual_Fs', 'convert_to_microvolts'); + + end + +end \ No newline at end of file diff --git a/LFPs/script_extract_bipolar_LFPs_DL.m b/LFPs/script_extract_bipolar_LFPs_DL.m new file mode 100644 index 00000000..c8c4b397 --- /dev/null +++ b/LFPs/script_extract_bipolar_LFPs_DL.m @@ -0,0 +1,63 @@ +% script to calculate LFPs for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'Z:\data\ChoiceTask\'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +target_Fs = 500; % in Hz, target LFP sampling rate after decimating the raw signal + +num_rats = length(ratIDs); + +for i_rat = 16 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.RatID == ratID, 2}; + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); + session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + if strcmp(session_name, 'R0378_20210507a') || strcmp(session_name, 'R0425_20220728a') + % skip this session because for some reason only 63 channels + % were recorded + continue + end + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + lfp_fname = strcat(session_name, '_lfp.mat'); + full_lfp_name = fullfile(processed_folder, session_name, lfp_fname); + if isfile(full_lfp_name) + lfp_data = load(full_lfp_name); + else + continue + end + actual_Fs = lfp_data.actual_Fs; + + sprintf('working on %s', session_name) + lfp_bipolar_name = strcat(session_name, '_bipolar_lfp.mat'); + lfp_bipolar_name = fullfile(processed_folder, session_name, lfp_bipolar_name); + [bipolar_lfp, intan2probe_mapping] = calculate_bipolar_LFPs(lfp_data.lfp, probe_type); + + save(lfp_bipolar_name, 'bipolar_lfp', 'actual_Fs', 'probe_type', 'intan2probe_mapping', 'full_lfp_name'); + + end + +end \ No newline at end of file From 12dc8ac3448001822a93ee106115301828ffd437 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Tue, 9 May 2023 09:11:41 -0400 Subject: [PATCH 12/19] psths testing files, may not keep --- .../plots/CalculatePSTH_TEST.m | 210 ++++++++++++++++++ LFPs/Analysis_code_JM/plots/psth_TEST.m | 50 +++++ .../~$P_Analysis_Workflow.docx | Bin 162 -> 0 bytes 3 files changed, 260 insertions(+) create mode 100644 LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m create mode 100644 LFPs/Analysis_code_JM/plots/psth_TEST.m delete mode 100644 LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx diff --git a/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m b/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m new file mode 100644 index 00000000..6e8b4c9b --- /dev/null +++ b/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m @@ -0,0 +1,210 @@ +function [psth,psthTrialAvg,varTrialAvg] = CalculatePSTH_TEST(SpikeTimes,start,varargin) +% ---------[psth] = CalculatePSTH(SpikeTimes,EventTimes,varargin)------------- +% +% Calculates peri-stimulus time histograms (PSTHs) from a matrix or cell +% array of spiketimes (in seconds), given a user-defined bin-width. Plots +% PSTHs and saves in current directory. +% +% >>> INPUTS >>> +% Required: +% SpikeTimes = matrix or cell of spiketimes in SECONDS +% If matrix, will assume columns are trials, rows are spiketimes. +% If cell, will assume each cell is a trial, and in each cell +% columns are channels, rows are spiketimes. +% start = n-element vector containing times of events (in seconds)...if +% spiketimes are relative (i.e. blocks of spikeitmes, each block relative +% to stim onset), then user should define "start" as the time of the +% onset of the stim relative to the start of the block. For instance, if +% stim is 6 seconds into the start of each block, then set "start" = 6. +% * if spikes NOT relative, start = nx1 array of starting times. +% Optional: +% pre_time = time (in SECONDS) to subtract from starting time... +% makes plots relative to stim onset (default = 1s); +% post_time = time (in SECONDS) to add to starting time... +% (default = 1s); +% bin_width = bin (ms) for PSTH calculation. Default = 10ms. +% name = name to save figure (default = "psth.pdf") +% saving = 0 or 1 (default 1). If 1, saves figures to current directory. +% +% <<< OUTPUTS <<< +% psth = bin-counts of spiketimes occuring within specified time range. +% If SpikeTimes is a cell array, psth is an nxtrialsxchan matrix. +% If SpikeTimes is a matrix, psth is an nxtrials matrix +% psthTrialAvg = average of psth across trials per channel +% varTrialAvg = average variance of psth across trials per channel +% +% Example: +% SpikeTimes{1} = sort(rand(100)); % fake spiketimes for ch1 +% SpikeTimes{2} = sort(rand(100)); % fake spiketimes for ch2 +% [psth,trialAvg,varAvg] = CalculatePSTH(SpikeTimes,.5,.2,.5,10,'control',1) +% % plots histogram and variances for each channel, from -0.2s : 0.5s +% % around the starting point, (here 0.5s into the SpikeTimes). Save +% % the figures and appends "control" to the figure name +% +% By JMS, 11/13/2015 +%------------------------------------------------------- +% check optionals +if nargin>2 && ~isempty(varargin{1}) + pre_time = varargin{1}; +else pre_time = 1; end % default 1s before start +if nargin>3 && ~isempty(varargin{2}) + post_time = varargin{2}; +else post_time = 1; end % default 1s after start +if nargin>4 && ~isempty(varargin{3}) + bw = varargin{3}; else bw = 10; end % default 10s bin width +if nargin>5 && ~isempty(varargin{4}) + name = varargin{4}; end % default no name for saving figs +if nargin>6 && ~isempty(varargin{5}) + saving = varargin{5}; +else saving = 1; end +% compute plotting times +lastBin = ceil((post_time*1000)); % last bin edge in ms +edge = EdgeCalculator(bw,-pre_time*1000,lastBin); % extract edges for psth +xmin = edge(1); % for plotting +xmax = edge(end); % for plotting +% check if SpikeTimes is cell or matrix +if iscell(SpikeTimes) + chans = max(size(SpikeTimes)); + ntrials = size(SpikeTimes{1},2); +else + ntrials = size(SpikeTimes,2); + chans = 1; +end +% error check if size(start) ~= ntrials....if so, repeat "start" so that it +% has same dimension as ntrials +if numel(start) == 1 && ntrials > 1 + start = ones(ntrials,1)*start; +else + error('Error: starting times and # trials not same dimension'); +end +% -------- begin loop ------------ +disp('calculating PSTHs...'); +clear psth +try % compute PSTH and plot + if iscell(SpikeTimes) + psth = zeros(numel(edge),ntrials,chans); + for ch = 1:chans + for trial = 1:ntrials + if ~isempty(SpikeTimes{ch}) + psthSpikes = SpikeTimes{ch}(SpikeTimes{ch}(:,trial) > start(trial)-pre_time & SpikeTimes{ch}(:,trial) < start(trial)+post_time,trial); % extract spikes occuring within pre/post times of start time + psth(:,trial,ch) = histc((psthSpikes-start(trial))*1000,edge) / (bw/1000) / ntrials; % make spikes relative to start and extract spike count per bin, divide by bw in seconds to get firing rate + clear psthSpikes + end + end + end + psthTrialAvg = squeeze(mean(psth,2)); % take mean across trials, squeeze into nxchan array + varTrialAvg = squeeze(var(psth,0,2)); + psthylim = [0 max(max(psthTrialAvg))]; % for plotting + varylim = [0 max(max(varTrialAvg))]; + else % if not a cell array + psth = zeros(numel(edge),ntrials); + for trial = 1:ntrials + psthSpikes = SpikeTimes(SpikeTimes(:,trial) > start(trial)-pre_time & SpikeTimes(:,trial) < start(trial)+post_time,trial); % extract spikes occuring within pre/post times of start time + psth(:,trial) = histc((psthSpikes-start(trial))*1000,edge) / (bw/1000) / ntrials; % make spikes relative to start and extract spike count per bin, divide by bw in seconds to get firing rate + clear psthSpikes + end + psthTrialAvg = mean(psth,2); % take mean across trials + varTrialAvg = var(psth,0,2); % take variance across trials + psthylim = [0 max(psthTrialAvg)]; % for plotting + varylim = [0 max(varTrialAvg)]; + end + % --- PSTH bar plots --- + pH = figure; + if iscell(SpikeTimes) + for ch = 1:chans + if chans>6 + subplot(3,3,ch); + bar(edge,psthTrialAvg(:,ch),'histc'); + set(gca,'xlim',[xmin xmax],'ylim',psthylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + ylabel('SpikeRate'); + elseif chans>4 + subplot(3,2,ch); + bar(edge,psthTrialAvg(:,ch),'histc'); + set(gca,'xlim',[xmin xmax],'ylim',psthylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + ylabel('SpikeRate'); + elseif chans>2 + subplot(2,2,ch); + bar(edge,psthTrialAvg(:,ch),'histc'); + set(gca,'xlim',[xmin xmax],'ylim',psthylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + ylabel('SpikeRate'); + else + subplot(2,1,ch); + bar(edge,psthTrialAvg(:,ch),'histc'); + set(gca,'xlim',[xmin xmax],'ylim',psthylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + ylabel('SpikeRate'); + end + end + else + % plot variance and psth in same figure if only one channel + subplot(2,1,1); + bar(edge,psthTrialAvg,'histc'); + set(gca,'xlim',[xmin xmax],'ylim',psthylim,... + 'box','off','tickdir','out'); + title('PSTH'); + ylabel('Spike Rate'); + subplot(2,1,2); + plot(edge,varTrialAvg); + set(gca,'xlim',[xmin xmax],'ylim',varylim,... + 'box','off','tickdir','out'); + title('Variance'); + end + % print the psth, append "name" if it exists + if exist('name','var') + print([name,'_psth.pdf'],'-dpdf'); + else + print('psth.pdf','-dpdf'); + end + % plot variance for channels in separate figure if Spiketimes is cell array + if iscell(SpikeTimes) + vH = figure; + for ch = 1:chans + if chans>6 + subplot(3,3,ch); + plot(edge,varTrialAvg(:,ch)); + set(gca,'xlim',[xmin xmax],'ylim',varylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + elseif chans>4 + subplot(3,2,ch); + plot(edge,varTrialAvg(:,ch)); + set(gca,'xlim',[xmin xmax],'ylim',varylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + elseif chans>2 + subplot(2,2,ch); + plot(edge,varTrialAvg(:,ch)); + set(gca,'xlim',[xmin xmax],'ylim',varylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + else + subplot(2,1,ch); + plot(edge,varTrialAvg(:,ch)); + set(gca,'xlim',[xmin xmax],'ylim',varylim,... + 'box','off','tickdir','out'); + title(['Ch: ',num2str(ch)]) + end + end + end + % print the psth, append "name" if it exists + if saving>0 + disp('Saving figure....') + if exist('name','var') + print([name,'_variance.pdf'],'-dpdf'); + else + print('variance.pdf','-dpdf'); + end + end +catch + disp('Error in file:...problem computing PSTH'); + msg = lasterr; + disp(msg); +end % catch loop +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/plots/psth_TEST.m b/LFPs/Analysis_code_JM/plots/psth_TEST.m new file mode 100644 index 00000000..3c50354f --- /dev/null +++ b/LFPs/Analysis_code_JM/plots/psth_TEST.m @@ -0,0 +1,50 @@ +function ph = psth_TEST(times, binsize, fs, ntrials, triallen, varargin) +% PSTH Computes the peri-stimulus time histogram from spike times. +% The routine plots the trial averaged spike rate as a function of time. +% H = PSTH(TIMES, BINSIZE, FS,NTRIALS,TRIALLEN) +% H = PSTH(TIMES, BINSIZE, FS,NTRIALS,TRIALLEN ,AXESHANDLE) +% TIMES - spike times (samples) +% BINSIZE - binwidth (ms) +% FS - sampling rate (hz) +% NTRIALS - number of trials +% TRIALLEN - length of a trial (samples) +% H - plot handle +% +% An example: +% %spike times can be specified in continuous time +% %here we have 3 trials and a trial length of 1000 samples +% t = [10, 250, 900, 1300, 1600, 2405, 2900]; +% +% %the same spike times can also be specified per trial +% t2 =[10, 250, 900, 300, 600, 405, 900]; +% r = psth(t,10,1000,3,1000) ; +% r2 = psth(t2,10,1000,3,1000); +% +% Author: Rajiv Narayan +% askrajiv@gmail.com +% Boston University, Boston, MA +h_color ='k'; +nin=nargin; +error(nargchk(5,6, nin)); +switch(nin) + + case 5 %no plot handle + figure; + h=gca; + + case 6 + if(ishandle(varargin{1})) + h=varargin{1}; + else + error('Invalid Plot handle'); + end +end +%Compute PSTH +lastBin = binsize * ceil((triallen-1)*(1000/(fs*binsize))); +edges = 0 : binsize : lastBin; +x = (mod(times-1,triallen)+1)*(1000/fs); +r = (histc(x,edges)*1000) / (ntrials*binsize); +%Plot histogram +axes(h); +ph=bar(edges(1:end-1),r(1:end-1),'histc'); +set(ph,'edgecolor',h_color,'facecolor',h_color); diff --git a/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx b/LFPs/Analysis_code_JM/~$P_Analysis_Workflow.docx deleted file mode 100644 index ec55be99ac5fc45c96f056b7c3dedb46f48d0273..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmWgkO-#=#EiTT_(^2qB&CAP7OD$p`2!t7Y84?-N8S)rP8H#~0AIQ>SP+;(4NCmR; z7%~~sfGmVTpQ<26W=D7`3h~@zTyf)N{k_Eu46C~=f3KRzC)q@C^3zn}G} G)&l@k6Cld~ From e2062f2a4495c9971b2f437c287a629d9494f92e Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Wed, 10 May 2023 11:04:01 -0400 Subject: [PATCH 13/19] updating code for monopolar from Dan's files --- .../plots/CalculatePSTH_TEST.m | 210 ------------------ LFPs/Analysis_code_JM/plots/psth_TEST.m | 50 ----- .../script_analyze_choice_task_LFPs.asv | 53 +++++ LFPs/script_extract_LFPs_DL.m | 14 +- .../calculate_monopolar_LFPs_DL.m | 113 ++++++++++ 5 files changed, 176 insertions(+), 264 deletions(-) delete mode 100644 LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m delete mode 100644 LFPs/Analysis_code_JM/plots/psth_TEST.m create mode 100644 LFPs/Analysis_code_JM/script_analyze_choice_task_LFPs.asv create mode 100644 silicon_probe_LFP_analysis/calculate_monopolar_LFPs_DL.m diff --git a/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m b/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m deleted file mode 100644 index 6e8b4c9b..00000000 --- a/LFPs/Analysis_code_JM/plots/CalculatePSTH_TEST.m +++ /dev/null @@ -1,210 +0,0 @@ -function [psth,psthTrialAvg,varTrialAvg] = CalculatePSTH_TEST(SpikeTimes,start,varargin) -% ---------[psth] = CalculatePSTH(SpikeTimes,EventTimes,varargin)------------- -% -% Calculates peri-stimulus time histograms (PSTHs) from a matrix or cell -% array of spiketimes (in seconds), given a user-defined bin-width. Plots -% PSTHs and saves in current directory. -% -% >>> INPUTS >>> -% Required: -% SpikeTimes = matrix or cell of spiketimes in SECONDS -% If matrix, will assume columns are trials, rows are spiketimes. -% If cell, will assume each cell is a trial, and in each cell -% columns are channels, rows are spiketimes. -% start = n-element vector containing times of events (in seconds)...if -% spiketimes are relative (i.e. blocks of spikeitmes, each block relative -% to stim onset), then user should define "start" as the time of the -% onset of the stim relative to the start of the block. For instance, if -% stim is 6 seconds into the start of each block, then set "start" = 6. -% * if spikes NOT relative, start = nx1 array of starting times. -% Optional: -% pre_time = time (in SECONDS) to subtract from starting time... -% makes plots relative to stim onset (default = 1s); -% post_time = time (in SECONDS) to add to starting time... -% (default = 1s); -% bin_width = bin (ms) for PSTH calculation. Default = 10ms. -% name = name to save figure (default = "psth.pdf") -% saving = 0 or 1 (default 1). If 1, saves figures to current directory. -% -% <<< OUTPUTS <<< -% psth = bin-counts of spiketimes occuring within specified time range. -% If SpikeTimes is a cell array, psth is an nxtrialsxchan matrix. -% If SpikeTimes is a matrix, psth is an nxtrials matrix -% psthTrialAvg = average of psth across trials per channel -% varTrialAvg = average variance of psth across trials per channel -% -% Example: -% SpikeTimes{1} = sort(rand(100)); % fake spiketimes for ch1 -% SpikeTimes{2} = sort(rand(100)); % fake spiketimes for ch2 -% [psth,trialAvg,varAvg] = CalculatePSTH(SpikeTimes,.5,.2,.5,10,'control',1) -% % plots histogram and variances for each channel, from -0.2s : 0.5s -% % around the starting point, (here 0.5s into the SpikeTimes). Save -% % the figures and appends "control" to the figure name -% -% By JMS, 11/13/2015 -%------------------------------------------------------- -% check optionals -if nargin>2 && ~isempty(varargin{1}) - pre_time = varargin{1}; -else pre_time = 1; end % default 1s before start -if nargin>3 && ~isempty(varargin{2}) - post_time = varargin{2}; -else post_time = 1; end % default 1s after start -if nargin>4 && ~isempty(varargin{3}) - bw = varargin{3}; else bw = 10; end % default 10s bin width -if nargin>5 && ~isempty(varargin{4}) - name = varargin{4}; end % default no name for saving figs -if nargin>6 && ~isempty(varargin{5}) - saving = varargin{5}; -else saving = 1; end -% compute plotting times -lastBin = ceil((post_time*1000)); % last bin edge in ms -edge = EdgeCalculator(bw,-pre_time*1000,lastBin); % extract edges for psth -xmin = edge(1); % for plotting -xmax = edge(end); % for plotting -% check if SpikeTimes is cell or matrix -if iscell(SpikeTimes) - chans = max(size(SpikeTimes)); - ntrials = size(SpikeTimes{1},2); -else - ntrials = size(SpikeTimes,2); - chans = 1; -end -% error check if size(start) ~= ntrials....if so, repeat "start" so that it -% has same dimension as ntrials -if numel(start) == 1 && ntrials > 1 - start = ones(ntrials,1)*start; -else - error('Error: starting times and # trials not same dimension'); -end -% -------- begin loop ------------ -disp('calculating PSTHs...'); -clear psth -try % compute PSTH and plot - if iscell(SpikeTimes) - psth = zeros(numel(edge),ntrials,chans); - for ch = 1:chans - for trial = 1:ntrials - if ~isempty(SpikeTimes{ch}) - psthSpikes = SpikeTimes{ch}(SpikeTimes{ch}(:,trial) > start(trial)-pre_time & SpikeTimes{ch}(:,trial) < start(trial)+post_time,trial); % extract spikes occuring within pre/post times of start time - psth(:,trial,ch) = histc((psthSpikes-start(trial))*1000,edge) / (bw/1000) / ntrials; % make spikes relative to start and extract spike count per bin, divide by bw in seconds to get firing rate - clear psthSpikes - end - end - end - psthTrialAvg = squeeze(mean(psth,2)); % take mean across trials, squeeze into nxchan array - varTrialAvg = squeeze(var(psth,0,2)); - psthylim = [0 max(max(psthTrialAvg))]; % for plotting - varylim = [0 max(max(varTrialAvg))]; - else % if not a cell array - psth = zeros(numel(edge),ntrials); - for trial = 1:ntrials - psthSpikes = SpikeTimes(SpikeTimes(:,trial) > start(trial)-pre_time & SpikeTimes(:,trial) < start(trial)+post_time,trial); % extract spikes occuring within pre/post times of start time - psth(:,trial) = histc((psthSpikes-start(trial))*1000,edge) / (bw/1000) / ntrials; % make spikes relative to start and extract spike count per bin, divide by bw in seconds to get firing rate - clear psthSpikes - end - psthTrialAvg = mean(psth,2); % take mean across trials - varTrialAvg = var(psth,0,2); % take variance across trials - psthylim = [0 max(psthTrialAvg)]; % for plotting - varylim = [0 max(varTrialAvg)]; - end - % --- PSTH bar plots --- - pH = figure; - if iscell(SpikeTimes) - for ch = 1:chans - if chans>6 - subplot(3,3,ch); - bar(edge,psthTrialAvg(:,ch),'histc'); - set(gca,'xlim',[xmin xmax],'ylim',psthylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - ylabel('SpikeRate'); - elseif chans>4 - subplot(3,2,ch); - bar(edge,psthTrialAvg(:,ch),'histc'); - set(gca,'xlim',[xmin xmax],'ylim',psthylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - ylabel('SpikeRate'); - elseif chans>2 - subplot(2,2,ch); - bar(edge,psthTrialAvg(:,ch),'histc'); - set(gca,'xlim',[xmin xmax],'ylim',psthylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - ylabel('SpikeRate'); - else - subplot(2,1,ch); - bar(edge,psthTrialAvg(:,ch),'histc'); - set(gca,'xlim',[xmin xmax],'ylim',psthylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - ylabel('SpikeRate'); - end - end - else - % plot variance and psth in same figure if only one channel - subplot(2,1,1); - bar(edge,psthTrialAvg,'histc'); - set(gca,'xlim',[xmin xmax],'ylim',psthylim,... - 'box','off','tickdir','out'); - title('PSTH'); - ylabel('Spike Rate'); - subplot(2,1,2); - plot(edge,varTrialAvg); - set(gca,'xlim',[xmin xmax],'ylim',varylim,... - 'box','off','tickdir','out'); - title('Variance'); - end - % print the psth, append "name" if it exists - if exist('name','var') - print([name,'_psth.pdf'],'-dpdf'); - else - print('psth.pdf','-dpdf'); - end - % plot variance for channels in separate figure if Spiketimes is cell array - if iscell(SpikeTimes) - vH = figure; - for ch = 1:chans - if chans>6 - subplot(3,3,ch); - plot(edge,varTrialAvg(:,ch)); - set(gca,'xlim',[xmin xmax],'ylim',varylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - elseif chans>4 - subplot(3,2,ch); - plot(edge,varTrialAvg(:,ch)); - set(gca,'xlim',[xmin xmax],'ylim',varylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - elseif chans>2 - subplot(2,2,ch); - plot(edge,varTrialAvg(:,ch)); - set(gca,'xlim',[xmin xmax],'ylim',varylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - else - subplot(2,1,ch); - plot(edge,varTrialAvg(:,ch)); - set(gca,'xlim',[xmin xmax],'ylim',varylim,... - 'box','off','tickdir','out'); - title(['Ch: ',num2str(ch)]) - end - end - end - % print the psth, append "name" if it exists - if saving>0 - disp('Saving figure....') - if exist('name','var') - print([name,'_variance.pdf'],'-dpdf'); - else - print('variance.pdf','-dpdf'); - end - end -catch - disp('Error in file:...problem computing PSTH'); - msg = lasterr; - disp(msg); -end % catch loop -end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/plots/psth_TEST.m b/LFPs/Analysis_code_JM/plots/psth_TEST.m deleted file mode 100644 index 3c50354f..00000000 --- a/LFPs/Analysis_code_JM/plots/psth_TEST.m +++ /dev/null @@ -1,50 +0,0 @@ -function ph = psth_TEST(times, binsize, fs, ntrials, triallen, varargin) -% PSTH Computes the peri-stimulus time histogram from spike times. -% The routine plots the trial averaged spike rate as a function of time. -% H = PSTH(TIMES, BINSIZE, FS,NTRIALS,TRIALLEN) -% H = PSTH(TIMES, BINSIZE, FS,NTRIALS,TRIALLEN ,AXESHANDLE) -% TIMES - spike times (samples) -% BINSIZE - binwidth (ms) -% FS - sampling rate (hz) -% NTRIALS - number of trials -% TRIALLEN - length of a trial (samples) -% H - plot handle -% -% An example: -% %spike times can be specified in continuous time -% %here we have 3 trials and a trial length of 1000 samples -% t = [10, 250, 900, 1300, 1600, 2405, 2900]; -% -% %the same spike times can also be specified per trial -% t2 =[10, 250, 900, 300, 600, 405, 900]; -% r = psth(t,10,1000,3,1000) ; -% r2 = psth(t2,10,1000,3,1000); -% -% Author: Rajiv Narayan -% askrajiv@gmail.com -% Boston University, Boston, MA -h_color ='k'; -nin=nargin; -error(nargchk(5,6, nin)); -switch(nin) - - case 5 %no plot handle - figure; - h=gca; - - case 6 - if(ishandle(varargin{1})) - h=varargin{1}; - else - error('Invalid Plot handle'); - end -end -%Compute PSTH -lastBin = binsize * ceil((triallen-1)*(1000/(fs*binsize))); -edges = 0 : binsize : lastBin; -x = (mod(times-1,triallen)+1)*(1000/fs); -r = (histc(x,edges)*1000) / (ntrials*binsize); -%Plot histogram -axes(h); -ph=bar(edges(1:end-1),r(1:end-1),'histc'); -set(ph,'edgecolor',h_color,'facecolor',h_color); diff --git a/LFPs/Analysis_code_JM/script_analyze_choice_task_LFPs.asv b/LFPs/Analysis_code_JM/script_analyze_choice_task_LFPs.asv new file mode 100644 index 00000000..26aed75d --- /dev/null +++ b/LFPs/Analysis_code_JM/script_analyze_choice_task_LFPs.asv @@ -0,0 +1,53 @@ +% probe_mapping_fname = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/Probe Histology Summary/ProbeSite_Mapping_MATLAB.xlsx'; + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; + +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); + +% test_folder = '/Volumes/SharedX/Neuro-Leventhal/data/ChoiceTask/R0327/R0327-rawdata/R0327_20191218a/R0327_20191218_ChVE_191218_140437'; +% cd(test_folder); + + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a','R0427_20220919a' }; % R0425_20220728a debugging because the intan side was left on for 15 hours; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255', 'R0427_20220920a'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; % R0427_20220920a does not have an 'info.rhd' file + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + pd_folder = create_processed_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + + lfp_fname = fullfile(pd_folder, create_lfp_fname(rd_metadata)); + + if exist(lfp_fname, 'file') + continue + end + + session_path = intan_folders{i_sessionfolder}; + pd_processed_data = parse_processed_folder(session_path); + ratID = pd_processed_data.ratID; + session_name = pd_processed_data.session_name; + + if any(strcmp(session_name, sessions_to_ignore)) + continue; + end + + if contains(session_name, sessions_to_ignore) || contains(intan_session_name, sessions_to_ignore1)|| contains(ratID, 'DigiInputTest') % Just always ignore these sessions. R0411 no data, DigitInputTest is t est files + continue; + end + + [lfp, actual_Fs] = calculate_NNprobe_monopolar_LFPs(intan_folders{i_sessionfolder}, 500); + + save(lfp_fname, 'lfp', 'actual_Fs'); + + end + +end +%% \ No newline at end of file diff --git a/LFPs/script_extract_LFPs_DL.m b/LFPs/script_extract_LFPs_DL.m index 1478822a..a15ee697 100644 --- a/LFPs/script_extract_LFPs_DL.m +++ b/LFPs/script_extract_LFPs_DL.m @@ -1,11 +1,13 @@ % script to calculate LFPs for all of Jen's rats; store in files in % the processed data folders -parent_directory = 'Z:\data\ChoiceTask\'; +parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; -summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls_dir = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary'; summary_xls = fullfile(summary_xls_dir, summary_xls); +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a','R0427_20220919a' }; % R0425_20220728a debugging because the intan side was left on for 15 hours; + probe_type_sheet = 'probe_type'; probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); % NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER @@ -26,7 +28,7 @@ continue; end - probe_type = probe_types{probe_types.RatID == ratID, 2}; + probe_type = probe_types{probe_types.ratID == ratID, 2}; % changed probe_types.RatID to probe_types.ratID due to error processed_folder = find_data_folder(ratID, 'processed', parent_directory); rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); session_dirs = dir(fullfile(rawdata_folder, strcat(ratID, '*'))); @@ -45,6 +47,10 @@ continue end + if any(strcmp(session_name, sessions_to_ignore)) % Jen added this in to ignore sessions as an attempt to debut "too many input arguments" + continue; + end + lfp_fname = strcat(session_name, '_lfp.mat'); processed_session_folder = fullfile(processed_folder, session_name); full_lfp_name = fullfile(processed_session_folder, lfp_fname); @@ -57,7 +63,7 @@ % end sprintf('working on %s', session_name) - [lfp, actual_Fs] = calculate_monopolar_LFPs(phys_folder, target_Fs, convert_to_microvolts); + [lfp, actual_Fs] = calculate_monopolar_LFPs_DL(phys_folder, target_Fs, convert_to_microvolts); save(full_lfp_name, 'lfp', 'actual_Fs', 'convert_to_microvolts'); diff --git a/silicon_probe_LFP_analysis/calculate_monopolar_LFPs_DL.m b/silicon_probe_LFP_analysis/calculate_monopolar_LFPs_DL.m new file mode 100644 index 00000000..be3054b4 --- /dev/null +++ b/silicon_probe_LFP_analysis/calculate_monopolar_LFPs_DL.m @@ -0,0 +1,113 @@ +function [lfp_data, actual_lfpFs] = calculate_monopolar_LFPs_DL(intan_folder, target_Fs, convert_to_microvolts) +% +% INPUTS +% intan_folder - folder containing intan data (amplifier.dat, info.rhd) +% target_Fs - target sampling rate + +raw_block_size = 100000; % number of samples to handle at a time (titrate to memory), may want to make this a varargin +bytes_per_sample = 2; +filtOrder = 1000; + +cd(intan_folder); + +rhd_file = dir('*.rhd'); +if length(rhd_file) > 1 + error('more than one rhd file in ' + intan_folder); + return +elseif isempty(rhd_file) + error('no rhd files found in ' + intan_folder); + return +end + +amp_file = dir('amplifier.dat'); %rename for Watson Data; change back to amplifier.dat +if isempty(amp_file) + error('no amplifier files found in ' + intan_folder); + return +end + +rhd_info = read_Intan_RHD2000_file_DL(rhd_file.name); +amplifier_channels = rhd_info.amplifier_channels; +num_channels = length(amplifier_channels); +Fs = rhd_info.frequency_parameters.amplifier_sample_rate; + +samples_per_channel = amp_file.bytes / (num_channels * bytes_per_sample); + +r = round(Fs / target_Fs); +actual_lfpFs = Fs/r; +raw_overlap_size = ceil(filtOrder * 2 / r) * r; % can use this line to check the overlap by making it equal to zero +lfp_overlap_size = raw_overlap_size / r; + +lfp_block_size = raw_block_size / r; +num_lfp_samples = ceil(samples_per_channel / r); +lfp_data = zeros(num_channels, num_lfp_samples); + +% calculate the number of blocks that will be needed +net_lfp_samples_per_block = lfp_block_size - lfp_overlap_size; +num_blocks = ceil(num_lfp_samples / net_lfp_samples_per_block); + +currentLFP = zeros(num_channels, lfp_block_size); + +% do the first block separate from the rest, since there will be some +% overlap for the rest of the blocks +LFPstart = 1; +LFPend = (LFPstart + lfp_block_size - 1) - lfp_overlap_size; + +disp(['Block 1 of ' num2str(num_blocks)]); +amplifier_data = readIntanAmplifierData_by_sample_number(amp_file.name,1,raw_block_size,amplifier_channels,convert_to_microvolts); +for i_ch = 1 : num_channels + currentLFP(i_ch, :) = ... + decimate(amplifier_data(i_ch, :), r, filtOrder, 'fir'); +end +lfp_data(:, LFPstart:LFPend) = currentLFP(:, 1:LFPend); +clear currentLFP; + +LFPstart = LFPend + 1; +raw_block_plus_overlap_size = raw_block_size + raw_overlap_size; +LFPblock_start = lfp_overlap_size + 1; +LFPblock_end = (LFPblock_start + lfp_block_size - 1) - lfp_overlap_size; + +read_final_samples = false; +for i_block = 2 : num_blocks + + disp(['Block ' num2str(i_block) ' of ' num2str(num_blocks)]); + +% read_start_sample = (i_block-1) * raw_block_size - raw_overlap_size + 1; + read_start_sample = (LFPstart-1) * r - raw_overlap_size; + read_end_sample = read_start_sample + raw_block_plus_overlap_size - 1; + + new_amplifier_data = readIntanAmplifierData_by_sample_number(amp_file.name,read_start_sample,read_end_sample,amplifier_channels,convert_to_microvolts); + + if i_block < num_blocks + if read_end_sample > samples_per_channel + % rarely, the end of the padded block goes past the end of the + % file, and messes up the indices + clear currentLFP + LFPend = size(lfp_data, 2); + read_final_samples = true; + else + LFPend = (LFPstart + lfp_block_size - 1) - lfp_overlap_size; + end + else + clear currentLFP; + read_final_samples = true; + LFPend = size(lfp_data, 2); + end + + for i_ch = 1 : num_channels + currentLFP(i_ch,:) = ... + decimate(new_amplifier_data(i_ch, :), r, filtOrder, 'fir'); + end + + if read_final_samples + LFPblock_end = size(currentLFP, 2); + end + try + lfp_data(:, LFPstart:LFPend) = currentLFP(:, LFPblock_start : LFPblock_end); + catch + keyboard + end + if read_final_samples + break + end + LFPstart = LFPend + 1; +end \ No newline at end of file From 43b89b6506f69c0ae2e0f0978509cd69eb9bc922 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Tue, 16 May 2023 15:57:08 -0400 Subject: [PATCH 14/19] updating --- .../createTrialsStruct_simpleChoice_Intan.m | 59 ++++--------------- Helpers/get_rat_list.m | 2 +- LFPs/Analysis_code_JM/PETHS/test_peths.m | 15 +++++ .../script_analyze_choice_task_LFPs.asv | 53 ----------------- LFPs/script_extract_LFPs_DL.m | 8 +-- 5 files changed, 30 insertions(+), 107 deletions(-) create mode 100644 LFPs/Analysis_code_JM/PETHS/test_peths.m delete mode 100644 LFPs/Analysis_code_JM/script_analyze_choice_task_LFPs.asv diff --git a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m index 5d9f00cd..669d782b 100644 --- a/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m +++ b/ChoiceTask_Intan_behavior_analysis/createTrialsStruct_simpleChoice_Intan.m @@ -448,30 +448,6 @@ % trials) trialData.movementDirection = 2; % moved right sideInAfterCue = trialEvents{NoseInidx(CueID(1) + 1)}.timestamps(trialEvents{NoseInidx(CueID(1) + 1)}.timestamps > CueTS(1)); - if isempty(sideInAfterCue) - % this trial was probably at the very end of a session, and the - % session ended mid-trial before the rat could poke the side - % port. Not sure how this got counted as correct - maybe - % recorded that way in the .log file but the sideIn wasn't - % registered on the Intan system. -DL 12/19/2022 - % label as an invalid trial, doesn't count as a trial, make - % sure listed as not correct so not incorporated in analysis - trialData.countsAsTrial = 0; - trialData.valid = 0; - trialData.correct = 0; - else - trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 - trialData.timestamps.sideOut = ... - events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); - trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); - - trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timestamps.centerOut; - trialData.timing.foodDelay = trialData.timestamps.foodClick - ... - trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... - trialData.timestamps.sideIn; - end trialData.timestamps.sideIn = sideInAfterCue(1); trialData.timestamps.sideOut = ... events{NoseOutidx(CueID(1) + 1)}.timestamps(events{NoseOutidx(CueID(1) + 1)}.timestamps > NoseInTS(1)); @@ -484,31 +460,10 @@ trialData.sideNP = trialData.centerNP - 1; trialData.movementDirection = 1; sideInAfterCue = trialEvents{NoseInidx(CueID(1) - 1)}.timestamps(trialEvents{NoseInidx(CueID(1) - 1)}.timestamps > CueTS(1)); - if isempty(sideInAfterCue) - % this trial was probably at the very end of a session, and the - % session ended mid-trial before the rat could poke the side - % port. Not sure how this got counted as correct - maybe - % recorded that way in the .log file but the sideIn wasn't - % registered on the Intan system. -DL 12/19/2022 - % label as an invalid trial, doesn't count as a trial, make - % sure listed as not correct so not incorporated in analysis - trialData.countsAsTrial = 0; - trialData.valid = 0; - trialData.correct = 0; - else - trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 - trialData.timestamps.sideOut = ... + trialData.timestamps.sideIn = sideInAfterCue(1); % Patched for sideIn timestamp empty JM 20200612 + trialData.timestamps.sideOut = ... events{NoseOutidx(CueID(1) - 1)}.timestamps(events{NoseOutidx(CueID(1) - 1)}.timestamps > NoseInTS(1)); - trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); - - trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timestamps.centerOut; - trialData.timing.foodDelay = trialData.timestamps.foodClick - ... - trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example - trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... - trialData.timestamps.sideIn; - end - + trialData.timestamps.sideOut = trialData.timestamps.sideOut(1); % done this way to prevent the algorithm from counting a nose-out % event that may be left over from a previous trial end % end if isempty(trialEvents{Tone1idx}.timestamps) @@ -520,7 +475,13 @@ trialData.timestamps.centerIn; trialData.timing.RT = trialData.timestamps.centerOut - ... trialData.timestamps.tone; - + trialData.timing.MT = trialData.timestamps.sideIn - ... % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timestamps.centerOut; + trialData.timing.foodDelay = trialData.timestamps.foodClick - ... + trialData.timestamps.sideIn; % Patched for sideIn timestamp empty JM 20200612 R0326_20200226 trial 162 example + trialData.timing.sidePortHold = trialData.timestamps.sideOut - ... + trialData.timestamps.sideIn; + % extract the FIRST time the rat went into the reward port. This is a % bit tricky because this may occur AFTER the next trial started % depending on how the behavior software was running and if the food diff --git a/Helpers/get_rat_list.m b/Helpers/get_rat_list.m index 74c309c0..718ee581 100644 --- a/Helpers/get_rat_list.m +++ b/Helpers/get_rat_list.m @@ -3,7 +3,7 @@ % update rat_nums (and hopefully not ratnums_with_bad_histo) to indicate % which rats should be analyzed -rat_nums = [326, 327, 372, 374, 376, 378, 379, 394, 395, 396, 411, 412, 413, 419, 420, 425]; +rat_nums = [326, 327, 372, 374, 376, 378, 379, 394, 395, 396, 411, 412, 413, 419, 420, 425, 427, 456, 459, 460, 462, 464, 463, 466, 465]; ratnums_with_bad_histo = [374, 376, 396, 413]; diff --git a/LFPs/Analysis_code_JM/PETHS/test_peths.m b/LFPs/Analysis_code_JM/PETHS/test_peths.m new file mode 100644 index 00000000..6d64910b --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/test_peths.m @@ -0,0 +1,15 @@ +% This code assumes spike times and behavior initiation times in ms +pre=3000; post=35000; binW=50; +thisBresponse=[]; +for n1=1:size(nn,1) %for each neuron, could be for each channel +nt=nn(n1,:); +thisN=[]; +for bt=st%for each behavior instance +thisN=[thisN, nt(nt>bt-pre & nt Date: Fri, 19 May 2023 14:10:40 -0400 Subject: [PATCH 15/19] for peths --- .../PETHS/Nex_Utilities/nex_info.m | 56 +++++++++++++++++++ .../PETHS/cluster_spike_time_info.m | 16 ++++++ LFPs/Analysis_code_JM/PETHS/test_peths.asv | 41 ++++++++++++++ LFPs/Analysis_code_JM/PETHS/test_peths.m | 25 +++++---- LFPs/Analysis_code_JM/PETHS/test_peths_B.m | 30 ++++++++++ 5 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 LFPs/Analysis_code_JM/PETHS/Nex_Utilities/nex_info.m create mode 100644 LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m create mode 100644 LFPs/Analysis_code_JM/PETHS/test_peths.asv create mode 100644 LFPs/Analysis_code_JM/PETHS/test_peths_B.m diff --git a/LFPs/Analysis_code_JM/PETHS/Nex_Utilities/nex_info.m b/LFPs/Analysis_code_JM/PETHS/Nex_Utilities/nex_info.m new file mode 100644 index 00000000..f193148d --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/Nex_Utilities/nex_info.m @@ -0,0 +1,56 @@ +function [nvar, names, types, freq] = nex_info(filename) +% nex_info(filename) -- read and display .nex file info +% +% [nvar, names, types] = nex_info(filename) +% +% INPUT: +% filename - if empty string, will use File Open dialog +% OUTPUT: +% nvar - number of variables in the file +% names - [nvar 64] array of variable names +% types - [1 nvar] array of variable types +% Interpretation of type values: 0-neuron, 1-event, 2-interval, 3-waveform, +% 4-population vector, 5-continuous variable, 6 - marker + +nvar = 0; +names = []; +types = []; + +if(nargin ~= 1) + disp('1 input arguments are required') + return +end + +if(length(filename) == 0) + [fname, pathname] = uigetfile('*.nex', 'Select a Nex file'); + filename = strcat(pathname, fname); +end + +fid = fopen(filename, 'r'); +if(fid == -1) + disp('cannot open file'); + return +end + +% % disp(strcat('file = ', filename)); +magic = fread(fid, 1, 'int32'); +version = fread(fid, 1, 'int32'); +comment = fread(fid, 256, 'char'); +freq = fread(fid, 1, 'double'); +tbeg = fread(fid, 1, 'int32'); +tend = fread(fid, 1, 'int32'); +nvar = fread(fid, 1, 'int32'); +fseek(fid, 260, 'cof'); +% % disp(strcat('version = ', num2str(version))); +% % disp(strcat('frequency = ', num2str(freq))); +% % disp(strcat('duration (sec) = ', num2str((tend - tbeg)/freq))); +% % disp(strcat('number of variables = ', num2str(nvar))); +names = zeros(1, 64); +for i=1:nvar + types(i) = fread(fid, 1, 'int32'); + var_version = fread(fid, 1, 'int32'); + names(i, :) = fread(fid, [1 64], 'char'); + dummy = fread(fid, 128+8, 'char'); +end +names = setstr(names); +fclose(fid); \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m b/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m new file mode 100644 index 00000000..c1c82189 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m @@ -0,0 +1,16 @@ +% read in spike_clusters +spike_clusters = readNPY('spike_clusters.npy'); +% read in spike_times +spike_times = readNPY('spike_times.npy'); +% concatenate spike clusters and spike times +cluster_times = [spike_clusters spike_times]; + +% Where spike times == st and cluster numbers == clu +sClust=nan(max(spike_clusters)+1,1); +for a=1:length(sClust) + sClust(a)=sum(spike_clusters==a-1); +end +sClust=nan(length(sClust),max(sClust)); +for a=1:size(sClust,1) + sClust(a,1:sum(spike_clusters==a-1))=spike_times(spike_clusters==a-1)'; +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/PETHS/test_peths.asv b/LFPs/Analysis_code_JM/PETHS/test_peths.asv new file mode 100644 index 00000000..23bb2a28 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/test_peths.asv @@ -0,0 +1,41 @@ +% This code assumes spike times and behavior initiation times in ms +pre=3000; +post=3000; +binW=50; +pethEntries=[]; +for iUnit=1:size(sClust,1) %for each neuron, could be for each channel + nt=sClust(iUnit,:); + unitBehavior=[]; + for bt=trial_ts %for each behavior instance + unitBehavior=[unitBehavior, nt(nt>bt-pre & ntbt-pre & ntbt-pre & ntbt-pre & nt trial_ts(iEvent) - pethHalfWidth & sClust < trial_ts(iEvent) + pethHalfWidth); + % subtract starting value to center ts entries + if ~isempty(tsFitCriteria) + pethEntries = [pethEntries sClust(tsFitCriteria) - trial_ts(iEvent)]; + end + end + allTs{totalUnits} = {sClust,unitName}; + totalUnits = totalUnits + 1; + + figure; + histogram(tsFitCriteria,binSize); + xlabel('time (s)'); + ylabel('spikes'); + title([strrep(clusternumbers(iUnit),'_','-')]); + disp(length(pethEntries)) +end \ No newline at end of file From 289ee99e182c7330d0acd25c1f5671a91a8d01bf Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Fri, 26 May 2023 15:12:21 -0400 Subject: [PATCH 16/19] updating minor fixes for scalograms --- Analysis/script_loop_through_data_folders.m | 4 +- Analysis/script_rename_scalos_to_monopolar.m | 6 +- Helpers/get_rat_list.m | 2 +- LFPs/calculate_trial_spectrograms.m | 6 +- LFPs/script_extract_LFPs_DL.asv | 72 ++++++++++++++++++++ LFPs/script_extract_LFPs_DL.m | 2 +- 6 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 LFPs/script_extract_LFPs_DL.asv diff --git a/Analysis/script_loop_through_data_folders.m b/Analysis/script_loop_through_data_folders.m index ca97f01f..a92ce5ab 100644 --- a/Analysis/script_loop_through_data_folders.m +++ b/Analysis/script_loop_through_data_folders.m @@ -1,9 +1,9 @@ % script to calculate scalograms for all of Jen's rats; store in files in % the processed data folders -parent_directory = 'Z:\data\ChoiceTask\'; +parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; -summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls_dir = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary'; summary_xls = fullfile(summary_xls_dir, summary_xls); % change the line below to allow looping through multiple trial types, diff --git a/Analysis/script_rename_scalos_to_monopolar.m b/Analysis/script_rename_scalos_to_monopolar.m index ef4660bf..87d1a87a 100644 --- a/Analysis/script_rename_scalos_to_monopolar.m +++ b/Analysis/script_rename_scalos_to_monopolar.m @@ -1,9 +1,9 @@ % script to calculate scalograms for all of Jen's rats; store in files in % the processed data folders -parent_directory = 'Z:\data\ChoiceTask\'; +parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; -summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls_dir = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary'; summary_xls = fullfile(summary_xls_dir, summary_xls); % change the line below to allow looping through multiple trial types, @@ -33,7 +33,7 @@ continue; end - probe_type = probe_types{probe_types.RatID == ratID, 2}; + probe_type = probe_types{probe_types.ratID == ratID, 2}; processed_folder = find_data_folder(ratID, 'processed', parent_directory); session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); num_sessions = length(session_dirs); diff --git a/Helpers/get_rat_list.m b/Helpers/get_rat_list.m index 718ee581..d011c39d 100644 --- a/Helpers/get_rat_list.m +++ b/Helpers/get_rat_list.m @@ -3,7 +3,7 @@ % update rat_nums (and hopefully not ratnums_with_bad_histo) to indicate % which rats should be analyzed -rat_nums = [326, 327, 372, 374, 376, 378, 379, 394, 395, 396, 411, 412, 413, 419, 420, 425, 427, 456, 459, 460, 462, 464, 463, 466, 465]; +rat_nums = [326, 327, 372, 374, 376, 378, 379, 394, 395, 396, 411, 412, 413, 419, 420, 425, 427, 456, 459, 460, 462, 464, 463, 466, 465, 467, 479]; ratnums_with_bad_histo = [374, 376, 396, 413]; diff --git a/LFPs/calculate_trial_spectrograms.m b/LFPs/calculate_trial_spectrograms.m index f1bf6fb4..8e2e7a50 100644 --- a/LFPs/calculate_trial_spectrograms.m +++ b/LFPs/calculate_trial_spectrograms.m @@ -1,9 +1,9 @@ % script to calculate scalograms for all of Jen's rats; store in files in % the processed data folders -parent_directory = 'Z:\data\ChoiceTask\'; +parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; -summary_xls_dir = 'Z:\data\ChoiceTask\Probe Histology Summary'; +summary_xls_dir = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary'; summary_xls = fullfile(summary_xls_dir, summary_xls); % change the line below to allow looping through multiple trial types, @@ -33,7 +33,7 @@ continue; end - probe_type = probe_types{probe_types.RatID == ratID, 2}; + probe_type = probe_types{probe_types.ratID == ratID, 2}; processed_folder = find_data_folder(ratID, 'processed', parent_directory); session_dirs = dir(fullfile(processed_folder, strcat(ratID, '*'))); num_sessions = length(session_dirs); diff --git a/LFPs/script_extract_LFPs_DL.asv b/LFPs/script_extract_LFPs_DL.asv new file mode 100644 index 00000000..9c51ca5e --- /dev/null +++ b/LFPs/script_extract_LFPs_DL.asv @@ -0,0 +1,72 @@ +% script to calculate LFPs for all of Jen's rats; store in files in +% the processed data folders + +parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +summary_xls = 'ProbeSite_Mapping_MATLAB.xlsx'; +summary_xls_dir = 'X:\Neuro-Leventhal\data\ChoiceTask\Probe Histology Summary'; +summary_xls = fullfile(summary_xls_dir, summary_xls); + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a','R0427_20220919a' }; % R0425_20220728a debugging because the intan side was left on for 15 hours; + +probe_type_sheet = 'probe_type'; +probe_types = read_Jen_xls_summary(summary_xls, probe_type_sheet); +% NOTE - UPDATE FUNCTION read_Jen_xls_summary WHEN WE NEED OTHER +% INFORMATION OUT OF THAT SPREADSHEET + +[rat_nums, ratIDs, ratIDs_goodhisto] = get_rat_list(); + +target_Fs = 500; % in Hz, target LFP sampling rate after decimating the raw signal +convert_to_microvolts = false; + +num_rats = length(ratIDs); + +for i_rat = 1 : num_rats + ratID = ratIDs{i_rat}; + rat_folder = fullfile(parent_directory, ratID); + + if ~isfolder(rat_folder) + continue; + end + + probe_type = probe_types{probe_types.ratID == ratID, 2}; % changed probe_types.RatID to probe_types.ratID due to error + processed_folder = find_data_folder(ratID, 'processed', parent_directory); + rawdata_folder = find_data_folder(ratID, 'rawdata', parent_directory); + session_dirs = dir(fullfile(rawdata_folder, strcat(ratID, '*'))); + num_sessions = length(session_dirs); + + for i_session = 1 : num_sessions + + session_name = session_dirs(i_session).name; + cur_dir = fullfile(session_dirs(i_session).folder, session_name); + cd(cur_dir) + + phys_folder = find_physiology_data(cur_dir); + + if isempty(phys_folder) + sprintf('no physiology data found for %s', session_name) + continue + end + + if any(strcmp(session_name, sessions_to_ignore)) % Jen added this in to ignore sessions as an attempt to debut "too many input arguments" + continue; + end + + lfp_fname = strcat(session_name, '_lfp.mat'); + processed_session_folder = fullfile(processed_folder, session_name); + full_lfp_name = fullfile(processed_session_folder, lfp_fname); + if ~isfolder(processed_session_folder) + mkdir(processed_session_folder) + end + if exist(lfp_fname) % the lfp_fname exists in the processed folder but this section is not recognizing it exists so still writes the file. + sprintf('%s already calculated, skipping', lfp_fname) + continue + end + + sprintf('working on %s', session_name) + [lfp, actual_Fs] = calculate_monopolar_LFPs_DL(phys_folder, target_Fs, convert_to_microvolts); + + save(full_lfp_name, 'lfp', 'actual_Fs', 'convert_to_microvolts'); + + end + +end \ No newline at end of file diff --git a/LFPs/script_extract_LFPs_DL.m b/LFPs/script_extract_LFPs_DL.m index 3acb6072..229cc8d6 100644 --- a/LFPs/script_extract_LFPs_DL.m +++ b/LFPs/script_extract_LFPs_DL.m @@ -57,7 +57,7 @@ if ~isfolder(processed_session_folder) mkdir(processed_session_folder) end - if isfile(lfp_fname) % the lfp_fname exists in the processed folder but this section is not recognizing it exists so still writes the file. + if isfile(full_lfp_name) == 1 % the lfp_fname exists in the processed folder but this section is not recognizing it exists so still writes the file. sprintf('%s already calculated, skipping', lfp_fname) continue end From 8b4c93d6a9e577215fc6588bf18cf2cd64f28ad8 Mon Sep 17 00:00:00 2001 From: Jennifer Magnusson <54630297+jmagnu1@users.noreply.github.com> Date: Wed, 31 May 2023 13:54:30 -0400 Subject: [PATCH 17/19] working on peths and rasters --- Helpers/plotSpikeRaster_color.asv | 44 +++++++++++ Helpers/plotSpikeRaster_color.m | 21 +++++ .../PETHS/cluster_spike_time_info.m | 3 + .../Analysis_code_JM/PETHS/sort_ts_to_units.m | 20 +++++ LFPs/Analysis_code_JM/PETHS/test_peths.asv | 79 +++++++++++-------- LFPs/Analysis_code_JM/PETHS/test_peths.m | 76 +++++++++++++++--- 6 files changed, 200 insertions(+), 43 deletions(-) create mode 100644 Helpers/plotSpikeRaster_color.asv create mode 100644 LFPs/Analysis_code_JM/PETHS/sort_ts_to_units.m diff --git a/Helpers/plotSpikeRaster_color.asv b/Helpers/plotSpikeRaster_color.asv new file mode 100644 index 00000000..223fc74e --- /dev/null +++ b/Helpers/plotSpikeRaster_color.asv @@ -0,0 +1,44 @@ +function plotSpikeRaster_color(xPoints,yPoints,groups,colors,figPos,markerSize) +% INPUTS +% xPoints - vector of x coordinates at which to put a raster mark +% (timestamps relative to a behavioral event for an entire session) +% yPoints - vector of y coordinates at which to put a raster mark +% xPoints and yPoints should have the same length, and xPoints(1) +% goes with yPoints(1), xPoints(2)-->yPoints(2), etc. +% the unique values of yPoints indicates a single trial, so all +% indicates of yPoints with the same value can be used to find +% xPoints that go with them, and plot them all the same color along +% the same row +% yPoints should be integers representing trial #'s (i.e., 1, 2, 3, +% ...) +% groups - vector containing num_trials (number of unique yPoints) list +% integers, with each integer representing a different group (for +% example, maybe 1 - leftward movement, 2-rightward movement, then +% they will show up as different colors in the raster +% colors - vector of colors corresponding to groups (i.e., colors(1) is +% the color that all members of group 1 will be plotted) +% markerSize - size of the marker to use for each raster point + + +% % if numel(xPoints) ~= numel(yPoints) || numel(unique(yPoints)) ~= numel(groups) ||... +% % numel(unique(groups)) ~= size(colors,1) +% % error('check input dimensions'); +% % end + +yPoints_unique = unique(yPoints); + +if ~isempty(figPos) + figure('position',figPos); +end +for iTrial = 1:numel(unique(yPoints)) + cur_y = yPoints_unique(iTrial); + pointIdxs = find(yPoints == cur_y); + plot(xPoints(pointIdxs),yPoints(pointIdxs),'.','color',colors(groups(iTrial) == unique(groups),:),'markerSize',markerSize); + hold on; +end +ylim([1 numel(unique(yPoints))]); +set(gca,'ydir','reverse'); +if ~isempty(figPos) + xlabel('time (s)'); + ylabel('trials'); +end \ No newline at end of file diff --git a/Helpers/plotSpikeRaster_color.m b/Helpers/plotSpikeRaster_color.m index b493c905..4a334cda 100644 --- a/Helpers/plotSpikeRaster_color.m +++ b/Helpers/plotSpikeRaster_color.m @@ -1,4 +1,25 @@ function plotSpikeRaster_color(xPoints,yPoints,groups,colors,figPos,markerSize) +% INPUTS +% xPoints - vector of x coordinates at which to put a raster mark +% (timestamps relative to a behavioral event for an entire session) +% yPoints - vector of y coordinates at which to put a raster mark +% xPoints and yPoints should have the same length, and xPoints(1) +% goes with yPoints(1), xPoints(2)-->yPoints(2), etc. +% the unique values of yPoints indicates a single trial, so all +% indicates of yPoints with the same value can be used to find +% xPoints that go with them, and plot them all the same color along +% the same row +% yPoints should be integers representing trial #'s (i.e., 1, 2, 3, +% ...) +% groups - vector containing num_trials (number of unique yPoints) list +% integers, with each integer representing a different group (for +% example, maybe 1 - leftward movement, 2-rightward movement, then +% they will show up as different colors in the raster +% colors - vector of colors corresponding to groups (i.e., colors(1) is +% the color that all members of group 1 will be plotted) +% figPos - figure position +% markerSize - size of the marker to use for each raster point + % % if numel(xPoints) ~= numel(yPoints) || numel(unique(yPoints)) ~= numel(groups) ||... % % numel(unique(groups)) ~= size(colors,1) diff --git a/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m b/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m index c1c82189..708b811d 100644 --- a/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m +++ b/LFPs/Analysis_code_JM/PETHS/cluster_spike_time_info.m @@ -5,6 +5,9 @@ % concatenate spike clusters and spike times cluster_times = [spike_clusters spike_times]; +% This file is grandfathered in and is replaced by the sort_ts_to_units +% function + % Where spike times == st and cluster numbers == clu sClust=nan(max(spike_clusters)+1,1); for a=1:length(sClust) diff --git a/LFPs/Analysis_code_JM/PETHS/sort_ts_to_units.m b/LFPs/Analysis_code_JM/PETHS/sort_ts_to_units.m new file mode 100644 index 00000000..851edd80 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/sort_ts_to_units.m @@ -0,0 +1,20 @@ +function unit_struct = sort_ts_to_units(spike_clusters, spike_times, Fs) +% INPUTS +% spike_clusters - npy file read in from kilosort output with cluster IDs +% spike_times - npy file read in from kilosort output with timestamps for +% the cluster IDs +% Fs - sampling frequency in Hz +% +% OUTPUT +% unit_sruct - array of structures with the following fields: +% .id - the unit ID from phy +% .ts - timestamps for that unit in seconds + +unit_ids = unique(spike_clusters); +for i_unit = 1 : length(unit_ids) + + unit_struct(i_unit).id = unit_ids(i_unit); + unit_bools = (spike_clusters == unit_ids(i_unit)); + unit_struct(i_unit).ts = double(spike_times(unit_bools)) / Fs; + +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/PETHS/test_peths.asv b/LFPs/Analysis_code_JM/PETHS/test_peths.asv index 23bb2a28..336f30ba 100644 --- a/LFPs/Analysis_code_JM/PETHS/test_peths.asv +++ b/LFPs/Analysis_code_JM/PETHS/test_peths.asv @@ -1,41 +1,58 @@ +function [unit_peths, unit_spike_times] = test_peths(unit_struct, trial_ts) +% INPUTS +% sClust - matrix for each neuron, could be for each channel +% trial_ts - trial_ts is an m x n array where m is num_trials and n is +% samples. This is generated looking for a specific time of the trial +% structure (e.g. correct trials). Units should be seconds + % This code assumes spike times and behavior initiation times in ms -pre=3000; -post=3000; -binW=50; +pre=3; % in seconds +post=3; +% pre (before the behavior of interest), post (after the behavior of interest), and bw (bin width) are all in milliseconds +binW=0.050; % in seconds + +trial_ts = sort(trial_ts); pethEntries=[]; -for iUnit=1:size(sClust,1) %for each neuron, could be for each channel - nt=sClust(iUnit,:); - unitBehavior=[]; - for bt=trial_ts %for each behavior instance - unitBehavior=[unitBehavior, nt(nt>bt-pre & nt(bt-pre) & unit_spike_times<(bt+post))-bt; -% pre=3000; post=35000; binW=50; -% thisBresponse=[]; -% for n1=1:size(nn,1) %for each neuron, could be for each channel -% nt=nn(n1,:); -% thisN=[]; -% for bt=st%for each behavior instance -% thisN=[thisN, nt(nt>bt-pre & ntbt-pre & ntbt-pre & nt(bt-pre) & unit_spike_times<(bt+post))-bt; + + % make sure ts_to_append is a row vector + if iscolumn(ts_to_append) + ts_to_append = ts_to_append'; end - thisH=hist(unitBehavior, -pre:binW:post)./(length(trial_ts)); %control for trial count - pethEntries=[pethEntries; thisH*(1000/binW)]; %adjust to Hz + + % thisN=[thisN, nt(nt>bt-pre & nt Date: Fri, 2 Jun 2023 08:55:46 -0400 Subject: [PATCH 18/19] working on peths --- Helpers/plotSpikeRaster_color.asv | 44 ------------- Helpers/plotSpikeRaster_color.m | 16 ++--- LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m | 66 +++++++++++++++++++ LFPs/Analysis_code_JM/PETHS/ATHpeth.m | 60 +++++++++++++++++ LFPs/Analysis_code_JM/PETHS/test_peths.asv | 58 ---------------- LFPs/Analysis_code_JM/PETHS/test_peths.m | 45 +++++++------ LFPs/calculate_trial_spectrograms.m | 6 +- ...e_trial_spectrograms_from_saved_bipolars.m | 34 +++++----- LFPs/script_extract_bipolar_LFPs_DL.m | 6 +- 9 files changed, 183 insertions(+), 152 deletions(-) delete mode 100644 Helpers/plotSpikeRaster_color.asv create mode 100644 LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m create mode 100644 LFPs/Analysis_code_JM/PETHS/ATHpeth.m delete mode 100644 LFPs/Analysis_code_JM/PETHS/test_peths.asv diff --git a/Helpers/plotSpikeRaster_color.asv b/Helpers/plotSpikeRaster_color.asv deleted file mode 100644 index 223fc74e..00000000 --- a/Helpers/plotSpikeRaster_color.asv +++ /dev/null @@ -1,44 +0,0 @@ -function plotSpikeRaster_color(xPoints,yPoints,groups,colors,figPos,markerSize) -% INPUTS -% xPoints - vector of x coordinates at which to put a raster mark -% (timestamps relative to a behavioral event for an entire session) -% yPoints - vector of y coordinates at which to put a raster mark -% xPoints and yPoints should have the same length, and xPoints(1) -% goes with yPoints(1), xPoints(2)-->yPoints(2), etc. -% the unique values of yPoints indicates a single trial, so all -% indicates of yPoints with the same value can be used to find -% xPoints that go with them, and plot them all the same color along -% the same row -% yPoints should be integers representing trial #'s (i.e., 1, 2, 3, -% ...) -% groups - vector containing num_trials (number of unique yPoints) list -% integers, with each integer representing a different group (for -% example, maybe 1 - leftward movement, 2-rightward movement, then -% they will show up as different colors in the raster -% colors - vector of colors corresponding to groups (i.e., colors(1) is -% the color that all members of group 1 will be plotted) -% markerSize - size of the marker to use for each raster point - - -% % if numel(xPoints) ~= numel(yPoints) || numel(unique(yPoints)) ~= numel(groups) ||... -% % numel(unique(groups)) ~= size(colors,1) -% % error('check input dimensions'); -% % end - -yPoints_unique = unique(yPoints); - -if ~isempty(figPos) - figure('position',figPos); -end -for iTrial = 1:numel(unique(yPoints)) - cur_y = yPoints_unique(iTrial); - pointIdxs = find(yPoints == cur_y); - plot(xPoints(pointIdxs),yPoints(pointIdxs),'.','color',colors(groups(iTrial) == unique(groups),:),'markerSize',markerSize); - hold on; -end -ylim([1 numel(unique(yPoints))]); -set(gca,'ydir','reverse'); -if ~isempty(figPos) - xlabel('time (s)'); - ylabel('trials'); -end \ No newline at end of file diff --git a/Helpers/plotSpikeRaster_color.m b/Helpers/plotSpikeRaster_color.m index 4a334cda..ddb22692 100644 --- a/Helpers/plotSpikeRaster_color.m +++ b/Helpers/plotSpikeRaster_color.m @@ -1,8 +1,8 @@ -function plotSpikeRaster_color(xPoints,yPoints,groups,colors,figPos,markerSize) +function plotSpikeRaster_color(unitBehavior,event_idx,groups,colors,figPos,markerSize) % INPUTS -% xPoints - vector of x coordinates at which to put a raster mark +% xPoints (unitBehavior) - vector of x coordinates at which to put a raster mark % (timestamps relative to a behavioral event for an entire session) -% yPoints - vector of y coordinates at which to put a raster mark +% yPoints (event_idx) - vector of y coordinates at which to put a raster mark % xPoints and yPoints should have the same length, and xPoints(1) % goes with yPoints(1), xPoints(2)-->yPoints(2), etc. % the unique values of yPoints indicates a single trial, so all @@ -26,18 +26,18 @@ function plotSpikeRaster_color(xPoints,yPoints,groups,colors,figPos,markerSize) % % error('check input dimensions'); % % end -yPoints_unique = unique(yPoints); +yPoints_unique = unique(event_idx); if ~isempty(figPos) figure('position',figPos); end -for iTrial = 1:numel(unique(yPoints)) +for iTrial = 1:numel(unique(event_idx)) cur_y = yPoints_unique(iTrial); - pointIdxs = find(yPoints == cur_y); - plot(xPoints(pointIdxs),yPoints(pointIdxs),'.','color',colors(groups(iTrial) == unique(groups),:),'markerSize',markerSize); + pointIdxs = find(event_idx == cur_y); + plot(unitBehavior(pointIdxs),event_idx(pointIdxs),'.','color',colors(groups(iTrial) == unique(groups),:),'markerSize',markerSize); hold on; end -ylim([1 numel(unique(yPoints))]); +ylim([1 numel(unique(event_idx))]); set(gca,'ydir','reverse'); if ~isempty(figPos) xlabel('time (s)'); diff --git a/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m b/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m new file mode 100644 index 00000000..b6736545 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m @@ -0,0 +1,66 @@ +function [unitBehavior, event_idx, pethEntries] = ATH_JM_peths(unit_struct, trial_ts) +% creating Alex's as a function + +% INPUTS +% unit_struct - matrix for each neuron, could be for each channel +% trial_ts - trial_ts is an m x n array where m is num_trials and n is +% samples. This is generated looking for a specific time of the trial +% structure (e.g. correct trials). Units should be seconds +% +% OUTPUTS +% unitBehavior - vector containing peri-event timestamps +% event_idx = cell array of vectors containing the index of the event +% around which unitBehavior is calculated (for example, if +% unitBehavior is [-0.5, 0.1, 0.5, -0.6] and event_idx is [1, 1, 1, +% 2], that would mean the first 3 timestamps are around the first +% event in the recording and the last timestamp (-0.6) is from the +% second event. unitBehavior and event_idx can be input to +% plotSpikeRaster_color as xPoints and yPoints, respectively + + +pre=3; +post=3; +binW=0.050; +pethEntries=[]; +% unitBehavior = cell(num_units, 1); % Jen you added this in +byUnit_Spikes4raster=struct('trial',[],'spike_times',[]); +num_units = length(unit_struct); +event_idx = cell(num_units, 1); +for iUnit=1:length(unit_struct) % matrix for each neuron, could be for each channel + unit_spike_times = unit_struct(iUnit).ts;% spike times for each unit + unitBehavior=[]; % matrix of this unit's behavior-related activity + %unitBehavior=nan(length(-pre:binW:post),length(trial_ts)); + %yPoints=[]; + i_event=1; + byUnit_Spikes4raster(iUnit).trial=[]; + byUnit_Spikes4raster(iUnit).spike_times=[]; + for bt=trial_ts %for each behavior instance; I think trial_ts is an m x n array where m is num_trials and n is samples. Is this relative to trial start or each event? + ts_to_append = unit_spike_times(unit_spike_times>(bt-pre) & unit_spike_times<(bt+post))-bt; + % thisN=[thisN, nt(nt>bt-pre & nt(bt-pre) & unit_spike_times<(bt+post))-bt; + % thisN=[thisN, nt(nt>bt-pre & nt(bt-pre) & unit_spike_times<(bt+post))-bt; - - % make sure ts_to_append is a row vector - if iscolumn(ts_to_append) - ts_to_append = ts_to_append'; - end - - % thisN=[thisN, nt(nt>bt-pre & nt Date: Fri, 2 Jun 2023 21:28:27 -0400 Subject: [PATCH 19/19] updating peths --- LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m | 28 +-- .../PETHS/{ATHpeth.m => ATHpeth_example.m} | 0 ...eths_generate_clust_timestamps_structure.m | 199 ++++++++++++++++++ .../peths_plots/plot_testing_file_peths.m | 13 ++ .../create_cluster_timestamps_data_folder.m | 10 + LFPs/Analysis_code_JM/extract_trial_ts.m | 49 +++-- ...cript_generate_trials_structure_bad_data.m | 2 +- 7 files changed, 261 insertions(+), 40 deletions(-) rename LFPs/Analysis_code_JM/PETHS/{ATHpeth.m => ATHpeth_example.m} (100%) create mode 100644 LFPs/Analysis_code_JM/PETHS/peths_generate_clust_timestamps_structure.m create mode 100644 LFPs/Analysis_code_JM/PETHS/peths_plots/plot_testing_file_peths.m create mode 100644 LFPs/Analysis_code_JM/PETHS/utils/create_cluster_timestamps_data_folder.m diff --git a/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m b/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m index b6736545..260c7e02 100644 --- a/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m +++ b/LFPs/Analysis_code_JM/PETHS/ATH_JM_peths.m @@ -43,7 +43,7 @@ byUnit_Spikes4raster(iUnit).trial=[byUnit_Spikes4raster(iUnit).trial;i_event];%This is totally unneccessary, but it's there for you %The line below creates Bst (binary spike times) based on pre and %post with 1ms resolution. This is what you can use to make rasters - Bst=ismember(-pre:post, ts_to_append); + Bst=ismember(-pre*1000:post*1000, round(ts_to_append*1000)); byUnit_Spikes4raster(iUnit).spike_times=[byUnit_Spikes4raster(iUnit).spike_times;Bst]; i_event=i_event+1; event_idx{iUnit} = [event_idx{iUnit}, ones(1, num_points) * i_event]; @@ -51,16 +51,16 @@ thisH=hist(unitBehavior, -pre:binW:post)./(length(trial_ts)); % vector that holds a trial averaged histogram, trial_ts is controlling for trial count pethEntries=[pethEntries; thisH*(1000/binW)]; % matrix that holds the trial-averaged histograms for each unit, adjusted to Hz end -%Heatmap -figure;imagesc(zscore(pethEntries')');colorbar; -%individual unit peths -figure; -for iUnit=1:size(pethEntries,1) - subplot(5,8,iUnit),plot(pethEntries(iUnit,:));ylabel('Fr (Hz)');xlabel('Time (bins)');title(['Unit ',char(string(iUnit))]); -end -%rasters -figure; -for iUnit=1:length(byUnit_Spikes4raster) - subplot(5,8,iUnit),imagesc(abs(1-byUnit_Spikes4raster(iUnit).spike_times));colormap('bone'); - ylabel('trial');xlabel('Time (3001=event)');title(['Unit ',char(string(iUnit))]); -end \ No newline at end of file +% %Heatmap +% figure;imagesc(zscore(pethEntries')');colorbar; +% %individual unit peths +% figure; +% for iUnit=1:size(pethEntries,1) +% subplot(5,8,iUnit),plot(pethEntries(iUnit,:));ylabel('Fr (Hz)');xlabel('Time (bins)');title(['Unit ',char(string(iUnit))]); +% end +% %rasters +% figure; +% for iUnit=1:length(byUnit_Spikes4raster) +% subplot(5,8,iUnit),imagesc(abs(1-byUnit_Spikes4raster(iUnit).spike_times));colormap('bone'); +% ylabel('trial');xlabel('Time (3001=event)');title(['Unit ',char(string(iUnit))]); +% end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/PETHS/ATHpeth.m b/LFPs/Analysis_code_JM/PETHS/ATHpeth_example.m similarity index 100% rename from LFPs/Analysis_code_JM/PETHS/ATHpeth.m rename to LFPs/Analysis_code_JM/PETHS/ATHpeth_example.m diff --git a/LFPs/Analysis_code_JM/PETHS/peths_generate_clust_timestamps_structure.m b/LFPs/Analysis_code_JM/PETHS/peths_generate_clust_timestamps_structure.m new file mode 100644 index 00000000..ca8c1929 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/peths_generate_clust_timestamps_structure.m @@ -0,0 +1,199 @@ +%% +% This wrapper was started on 20230602 by JM and is NOT complete as of +% 20230602 + +intan_parent_directory = 'X:\Neuro-Leventhal\data\ChoiceTask'; +rats_with_intan_sessions = find_rawdata_folders(intan_parent_directory); % kilosort output .npy files are saved in the individual rawdata folder sessions with all ephys data +%% + +% Use make_PETHs_required_variables.m as an example of what variables are +% needed in the workspace +% need the trial structure for that session +% run this analysis, generating an array that has the timestamps for +% correct trials for all eventFieldnames + +trialType = ('correctgo'); % to pull out trIdx of the trials structure (all trials) + +switch lower(trialType) + case 'allgo' + eventFieldnames = {'centerIn'}; + case 'correctgo' + eventFieldnames = {'cueOn', 'centerIn', 'centerOut', 'tone', 'sideIn', 'sideOut', 'foodClick', 'foodRetrievel'}; +end + + % eventlist = {'centerin','cueon','centerout', 'sidein', 'sideout', + % 'foodretrievel'}; This is the full eventlist for a correctGo trial. + +num_events = length(eventFieldnames); +t_win = [-2.5, 5]; % need this line for the event_triggered_lfps to select the correct +Fs = 20000; + +% lists for ratID probe_type +NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type +ASSY156 = ["R0411", "R0419"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457", "R0456", "R0459", "R0460", "R0463", "R0465", "R0466", "R0467", "R0477"]; + +sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; +sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'}; +sessions_to_ignore2 = {'R0427_20220908a', 'R0427_20220909a', 'R0427_20220912a','R0427_20220913a', 'R0427_20220914a', 'R0427_20220915a', 'R0427_20220916a'}; +% Trying this as a workaround. Code wouldn't skip these two trials. R0425 - 15 hour session and R0427 no data (files didn't save correctly)? + +% choiceTask difficulty levels +choiceRTdifficulty = cell(1, 10); +choiceRTdifficulty{1} = 'poke any'; +choiceRTdifficulty{2} = 'very easy'; +choiceRTdifficulty{3} = 'easy'; +choiceRTdifficulty{4} = 'standard'; +choiceRTdifficulty{5} = 'advanced'; +choiceRTdifficulty{6} = 'choice VE'; +choiceRTdifficulty{7} = 'choice easy'; +choiceRTdifficulty{8} = 'choice standard'; +choiceRTdifficulty{9} = 'choice advanced'; +choiceRTdifficulty{10} = 'testing'; + +%% +for i_rat = 1 : length(rats_with_intan_sessions) + + intan_folders = rats_with_intan_sessions(i_rat).intan_folders; + + for i_sessionfolder = 1 : length(intan_folders) + % extract the ratID and session name from the LFP file + session_path = intan_folders{i_sessionfolder}; + rd_metadata = parse_rawdata_folder(intan_folders{i_sessionfolder}); + session_clust_timestamps_folder = create_cluster_timestamps_data_folder(rd_metadata, intan_parent_directory); + ratID = rd_metadata.ratID; + intan_session_name = rd_metadata.session_name; + session_name = rd_metadata.session_name; + +% if any(strcmp(session_path, sessions_to_ignore)) % shouldn't need +% % this on this analysis for now +% continue; +% end + + + parentFolder = fullfile(intan_parent_directory, ... + ratID, ... + [ratID '-processed']); + + if contains(ratID, NN8x8) % if the ratID is in the list, it'll assign it the correct probe_type for ordering the LFP data correctly + probe_type = 'NN8x8'; + elseif contains(ratID, ASSY156) + probe_type = 'ASSY156'; + elseif contains(ratID, ASSY236) + probe_type = 'ASSY236'; + end + + + trials_structure_plots = [parentFolder(1:end-9) 'LFP-trials-structures-graphs']; + if ~exist(trials_structure_plots, 'dir') + mkdir(trials_structure_plots); + end + + [session_folder, ~, ~] = fileparts(intan_folders{i_sessionfolder}); + session_log = find_session_log(session_folder); + + if isempty(session_log) + sprintf('no log file found for %s', session_folder) + end + + logData = readLogData(session_log); %gathersing logData information + + % calculate nexData, need digital input and analog input files + digin_fname = fullfile(intan_folders{i_sessionfolder}, 'digitalin.dat'); + analogin_fname = fullfile(intan_folders{i_sessionfolder}, 'analogin.dat'); + rhd_fname = fullfile(intan_folders{i_sessionfolder}, 'info.rhd'); + spike_clusters_fname = fullfile(intan_folders{i_sessionfolder}, 'spike_clusters.npy'); % need this line if we're reading in kilosort files and reading in .npy information from phy + spike_times_fname = fullfile(intan_folders{i_sessionfolder}, 'spike_times.npy'); % need this line if we're reading in kilosort files and reading in .npy information from phy + + if ~exist(digin_fname, 'file') + sprintf('no digital input file for %s', session_folder); + continue + end + + if ~exist(analogin_fname, 'file') + sprintf('no analog input file for %s', session_folder); + continue + end + + if ~exist(rhd_fname, 'file') + sprintf('no rhd info file for %s', session_folder); + continue + end + + if ~exist(spike_clusters_fname, 'file') % need this line if we're reading in kilosort files and reading in .npy information from phy + sprintf('no spike_clusters input file for %s', session_folder); + continue + end + + if ~exist(spike_times_fname, 'file') % need this line if we're reading in kilosort files and reading in .npy information from phy + sprintf('no spike_times input file for %s', session_folder); + continue + end + + % read in rhd info; requires 'info.rhd' file. + rhd_info = read_Intan_RHD2000_file_DL(rhd_fname); + + % read digital input file + dig_data = readIntanDigitalFile(digin_fname); + if ~isfield(rhd_info, 'board_adc_channels') + sprintf('board_adc_channels field not found in rhd_info for %s', session_folder) + continue + end + + analog_data = readIntanAnalogFile(analogin_fname, rhd_info.board_adc_channels); + nexData = intan2nex(dig_data, analog_data, rhd_info); + + % read in spike_clusters + spike_clusters = readNPY('spike_clusters.npy'); + % read in spike_times + spike_times = readNPY('spike_times.npy'); + % concatenate spike clusters and spike times + cluster_times = [spike_clusters spike_times]; + + try + sprintf('attempting to create trials structure for %s', session_folder) + trials = createTrialsStruct_simpleChoice_Intan( logData, nexData ); + catch + sprintf('could not generate trials structure for %s', session_folder) + continue + end + + % extract Trial Type (e.g. correctGo) + % Set trialType at beginning of file + [ trialEventParams ] = getTrialEventParams(trialType); % start with correctgo + trIdx = extractTrials(trials, trialEventParams); + num_trials = length(trIdx); + + % UP THROUGH THIS POINT WE NEED FOR PETHS DATA - including trials + % structure, read in spike_clusters and spike_times. + + + % AS OF 20230602 TRYING TO DETERMINE IF WE NEED THIS OR HOW TO EDIT + % FOR GENERATING A STRUCTURE ARRAY OF SESSION DATA + + % THIS WAS WRITTEN FOR EVENT TRIGGERED LFPS BUT MAY BE ABLE TO EDIT FOR GENERATING A STRUCTURE + % FOR event triggered peths - working here + for i_event = 1 : num_events + % edit code here for getting event_triggered_peths + % for each separate event + + % create a filename to save the trials_structure + peths_fname_to_save = char(strcat(session_name, '_', eventFieldnames{i_event}, '_', trialType, '_', 'event_triggered_peths', '.mat')); % add in ''_', sprintf('trial%u.pdf', trial_idx)' should you want to save files individually + peths_full_name = fullfile(session_clust_timestamps_folder, peths_fname_to_save); + + if exist(peths_full_name, 'file') + continue + end + + % Catch for troubleshooting the data to NOT run through all of the folders and + % create the data if the files are already made. This will not create 5 pages of 5 different random trials. + + % this function adds 2 fields to the trials structure to identify bad sites + trial_ts = extract_trial_ts(trials(trIdx), eventFieldnames(i_event)); % This is actually pulled in from the extract_event_related_LFPs script so do we need it here? + + unit_struct = sort_ts_to_units(spike_clusters, spike_times, Fs); + save(peths_full_name, 'unit_struct', 'trial_ts', '-mat'); + + end + end +end diff --git a/LFPs/Analysis_code_JM/PETHS/peths_plots/plot_testing_file_peths.m b/LFPs/Analysis_code_JM/PETHS/peths_plots/plot_testing_file_peths.m new file mode 100644 index 00000000..ea6aa410 --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/peths_plots/plot_testing_file_peths.m @@ -0,0 +1,13 @@ +%Heatmap +figure;imagesc(zscore(pethEntries')');colorbar; +%individual unit peths +figure; +for iUnit=1:size(pethEntries,1) + subplot(5,8,iUnit),plot(pethEntries(iUnit,:));ylabel('Fr (Hz)');xlabel('Time (bins)');title(['Unit ',char(string(iUnit))]); +end +%rasters +figure; +for iUnit=1:length(byUnit_Spikes4raster) + subplot(5,8,iUnit),imagesc(abs(1-byUnit_Spikes4raster(iUnit).spike_times));colormap('bone'); + ylabel('trial');xlabel('Time (3001=event)');title(['Unit ',char(string(iUnit))]); +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/PETHS/utils/create_cluster_timestamps_data_folder.m b/LFPs/Analysis_code_JM/PETHS/utils/create_cluster_timestamps_data_folder.m new file mode 100644 index 00000000..74ea036e --- /dev/null +++ b/LFPs/Analysis_code_JM/PETHS/utils/create_cluster_timestamps_data_folder.m @@ -0,0 +1,10 @@ +function session_cluster_timestamps = create_cluster_timestamps_data_folder(rd_metadata, parent_directory) + +session_clust_timestamps_folder= strcat(rd_metadata.ratID, '-cluster-timestamps'); % cluster_timestamps_data_folder +session_cluster_timestamps = fullfile(parent_directory, rd_metadata.ratID, session_clust_timestamps_folder, rd_metadata.session_name); + +if ~isfolder(session_cluster_timestamps) + + mkdir(session_cluster_timestamps) + +end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/extract_trial_ts.m b/LFPs/Analysis_code_JM/extract_trial_ts.m index 99afc6de..0b11b806 100644 --- a/LFPs/Analysis_code_JM/extract_trial_ts.m +++ b/LFPs/Analysis_code_JM/extract_trial_ts.m @@ -1,36 +1,35 @@ -function trial_ts = extract_trial_ts(trials, eventFieldnames) -% +function trial_ts = extract_trial_ts(trials, eventFieldname) % % INPUTS % trials - trials structure - -% % tWindow - two-element array containing length of time (in seconds) -% % before and after each event to extract. Note that both elements of -% % tWindow will be added to the reference event (so usually the first -% % number will be negative, second will be positive) - -% WHY DOES THIS FILE NEED TWINDOW?? DOES NOT MAKE SENSE. - -% eventFieldnames - event fields for which to extract time -% windows +% eventFieldname - name of the event we're interested in % For a correct trial, eventFieldnames are as follows: % cueOn, centerIn, tone, centerOut, sideIn, sideOut, foodClick, foodRetrieval % - to find eventFieldnames for non-correct trials, check the % timestamps column in the trials structure. % % OUTPUTS -% trialRanges - m x n x 2 array, where m is the number of fields being -% analyzed, n is the number of trials, and the last two elements -% contain the start and end time for each window +% trial_ts - vector of timestamps for the given event in this trials +% structure -trial_ts = NaN(numel(eventFieldnames),numel(trials)); -for iField = 1:numel(eventFieldnames) - for iTrial = 1:numel(trials) - try - ts = getfield(trials(iTrial).timestamps,eventFieldnames{iField}); - trial_ts(iField, iTrial) = ts; - catch - % do nothing, filled with NaN - end +trial_ts = NaN(1,numel(trials)); +for iTrial = 1:numel(trials) + try + ts = getfield(trials(iTrial).timestamps, eventFieldname); + trial_ts(iTrial) = ts; + catch end -end \ No newline at end of file +end + + +% trial_ts = NaN(numel(eventFieldnames),numel(trials)); +% for iField = 1:numel(eventFieldnames) +% for iTrial = 1:numel(trials) +% try +% ts = getfield(trials(iTrial).timestamps,eventFieldnames{iField}); +% trial_ts(iField, iTrial) = ts; +% catch +% % do nothing, filled with NaN +% end +% end +% end \ No newline at end of file diff --git a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m index 6ac8b316..a0269ef9 100644 --- a/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m +++ b/LFPs/Analysis_code_JM/script_generate_trials_structure_bad_data.m @@ -32,7 +32,7 @@ % lists for ratID probe_type NN8x8 = ["R0326", "R0327", "R0372", "R0379", "R0374", "R0376", "R0378", "R0394", "R0395", "R0396", "R0412", "R0413"]; % Specify list of ratID associated with each probe_type ASSY156 = ["R0411", "R0419"]; -ASSY236 = ["R0420", "R0425", "R0427", "R0457"]; +ASSY236 = ["R0420", "R0425", "R0427", "R0457", "R0456", "R0459", "R0460", "R0463", "R0465", "R0466", "R0467", "R0477"]; sessions_to_ignore = {'R0378_20210507a', 'R0326_20191107a', 'R0425_20220728a', 'R0425_20220816b', 'R0427_20220920a', 'R0427_20220920a', 'R0427_20220919a'}; sessions_to_ignore1 = {'R0425_20220728_ChVE_220728_112601', 'R0427_20220920_Testing_220920_150255'};