https://github.com/harvardschoolofmouse/HSOMbehaviorSuite
Raw File
Tip revision: 5a9b981afb658cfc05277b1a257e1733f274c9a2 authored by Allison E Hamilos, PhD on 08 January 2022, 22:04:01 UTC
Update README.md
Tip revision: 5a9b981
MouseBehaviorInterface.m
%% MouseBehaviorInterface: construct graphical user interface to interact with arduino
% 
% 	Created:	6-1-16 		Lingfeng Hou and Ofer Mazor
%   Modified: 	11-2-17 	Allison Hamilos ahamilos{at}g.harvard.edu
% 
% Update log:
%   11-2-17: updated histogram tab to allow UI of numBins (AH)
% 
% 
% -------------------------------------------------------
% 	
% 	Creates a Matlab serial GUI interface for controlling the Harvard School of Mouse Arduino State System Controller
% 
% 	GUI and Behavior Interface developed by Lingfeng Hou
% 	Custom Attachments for HSOM: 		Allison Hamilos
% 	Original Matlab Serial Interface: 	Ofer Mazor
% 
% 	HSOM Logo: Allison Hamilos
% 

classdef MouseBehaviorInterface < handle
	properties
		Arduino
		Nidaq
		UserData
	end
	properties (Transient)
		Rsc
	end

	%----------------------------------------------------
	%		Methods
	%----------------------------------------------------
	methods
		function obj = MouseBehaviorInterface()
			% Find arduino port
			arduinoPortName = MouseBehaviorInterface.QueryPort();

			% Splash
			if ~strcmp(arduinoPortName, '/offline')
				obj.CreateDialog_Splash()
			end

			% Establish arduino connection
			obj.Arduino = ArduinoConnection(arduinoPortName);

			% Creata Experiment Control window with all the knobs and buttons you need to set up an experiment. 
			obj.CreateDialog_ExperimentControl()

			% Create Monitor window with all thr trial results and plots and stuff so the Grad Student is ON TOP OF THE SITUATION AT ALL TIMES.
			obj.CreateDialog_Monitor()

			% Kill splash
			if ~strcmp(arduinoPortName, '/offline')
				obj.CloseDialog_Splash()
			end
		end

		function CreateDialog_ExperimentControl(obj)
			% If object already exists, show window
			if isfield(obj.Rsc, 'ExperimentControl')
				if isvalid(obj.Rsc.ExperimentControl)
					figure(obj.Rsc.ExperimentControl)
					return
				end
			end

			% Size and position of controls
			buttonWidth = 50; % Width of buttons
			buttonHeight = 20; % Height of 
			ctrlSpacing = 10; % Spacing between ui elements

			% Create the dialog
			if isempty(obj.Arduino.SerialConnection)
				port = 'OFFLINE';
			else
				port = obj.Arduino.SerialConnection.Port;
			end
			dlg = dialog(...
				'Name', sprintf('Experiment Control (%s)', port),...
				'WindowStyle', 'normal',...
				'Resize', 'on',...
				'Visible', 'off'... % Hide until all controls created
			);
			% Store the dialog handle
			obj.Rsc.ExperimentControl = dlg;

			% Close serial port when you close the window
			dlg.CloseRequestFcn = {@MouseBehaviorInterface.ArduinoClose, obj};

			% Create a uitable for parameters
			table_params = uitable(...
				'Parent', dlg,...
				'Data', obj.Arduino.ParamValues',...
				'RowName', obj.Arduino.ParamNames,...
				'ColumnName', {'Value'},...
				'ColumnFormat', {'long'},...
				'ColumnEditable', [true],...
				'CellEditCallback', {@MouseBehaviorInterface.OnParamChangedViaGUI, obj.Arduino}...
			);
			dlg.UserData.Ctrl.Table_Params = table_params;

			% Add listener for parameter change via non-GUI methods, in which case we'll update table_params
			obj.Arduino.Listeners.ParamChanged = addlistener(obj.Arduino, 'ParamValues', 'PostSet', @obj.OnParamChanged);

			% Set width and height
			table_params.Position(3:4) = table_params.Extent(3:4);

			% Start button - start experiment from IDLE
			ctrlPosBase = table_params.Position;
			ctrlPos = [...
				ctrlPosBase(1) + ctrlPosBase(3) + ctrlSpacing,...
				ctrlPosBase(2) + ctrlPosBase(4) - buttonHeight - ctrlSpacing,...
				buttonWidth,...	
				buttonHeight...
			];
			button_start = uicontrol(...
				'Parent', dlg,...
				'Style', 'pushbutton',...
				'Position', ctrlPos,...
				'String', 'Start',...
				'TooltipString', 'Tell Arduino to start the experiment. Breaks out of IDLE state.',...
				'Callback', {@MouseBehaviorInterface.ArduinoStart, obj.Arduino}...
			);

			% Stop button - abort current trial and return to IDLE
			ctrlPosBase = button_start.Position;
			ctrlPos = [...
				ctrlPosBase(1),...
				ctrlPosBase(2) - buttonHeight - ctrlSpacing,...
				buttonWidth,...	
				buttonHeight...
			];
			button_stop = uicontrol(...
				'Parent', dlg,...
				'Style', 'pushbutton',...
				'Position', ctrlPos,...
				'String', 'Stop',...
				'TooltipString', 'Puts Arduino into IDLE state. Resume using the "Start" button.',...
				'Callback', {@MouseBehaviorInterface.ArduinoStop, obj.Arduino}...
			);

			% Reset button - software reset for arduino
			ctrlPosBase = button_stop.Position;
			ctrlPos = [...
				ctrlPosBase(1),...
				ctrlPosBase(2) - buttonHeight - ctrlSpacing,...
				buttonWidth,...	
				buttonHeight...
			];
			button_reset = uicontrol(...
				'Parent', dlg,...
				'Style', 'pushbutton',...
				'Position', ctrlPos,...
				'String', 'Reset',...
				'TooltipString', 'Reset Arduino (parameters will not be changed).',...
				'Callback', {@MouseBehaviorInterface.ArduinoReset, obj.Arduino}...
			);

			% Resize dialog so it fits all controls
			dlg.Position(1:2) = [10, 50];
			dlg.Position(3) = table_params.Position(3) + buttonWidth + 4*ctrlSpacing;
			dlg.Position(4) = table_params.Position(4) + 3*ctrlSpacing;

			% Menus
			menu_file = uimenu(dlg, 'Label', '&File');
			uimenu(menu_file, 'Label', 'Save Experiment ...', 'Callback', {@MouseBehaviorInterface.ArduinoSaveExperiment, obj.Arduino}, 'Accelerator', 's');
			uimenu(menu_file, 'Label', 'Save Experiment As ...', 'Callback', {@MouseBehaviorInterface.ArduinoSaveAsExperiment, obj.Arduino});
			uimenu(menu_file, 'Label', 'Load Experiment ...', 'Callback', {@MouseBehaviorInterface.ArduinoLoadExperiment, obj.Arduino}, 'Accelerator', 'l');
			uimenu(menu_file, 'Label', 'Save Parameters ...', 'Callback', {@MouseBehaviorInterface.ArduinoSaveParameters, obj.Arduino}, 'Separator', 'on');
			uimenu(menu_file, 'Label', 'Load Parameters ...', 'Callback', {@MouseBehaviorInterface.ArduinoLoadParameters, obj.Arduino, table_params});
			uimenu(menu_file, 'Label', 'Quit', 'Callback', {@MouseBehaviorInterface.ArduinoClose, obj}, 'Separator', 'on');

			menu_arduino = uimenu(dlg, 'Label', '&Arduino');
			uimenu(menu_arduino, 'Label', 'Start', 'Callback', {@MouseBehaviorInterface.ArduinoStart, obj.Arduino});
			uimenu(menu_arduino, 'Label', 'Stop', 'Callback', {@MouseBehaviorInterface.ArduinoStop, obj.Arduino}, 'Accelerator', 'q');
			uimenu(menu_arduino, 'Label', 'Reset', 'Callback', {@MouseBehaviorInterface.ArduinoReset, obj.Arduino}, 'Separator', 'on');
			uimenu(menu_arduino, 'Label', 'Reconnect', 'Callback', {@MouseBehaviorInterface.ArduinoReconnect, obj.Arduino});

			menu_window = uimenu(dlg, 'Label', '&Window');
			uimenu(menu_window, 'Label', 'Experiment Control', 'Callback', @(~, ~) @obj.CreateDialog_ExperimentControl);
			uimenu(menu_window, 'Label', 'Monitor', 'Callback', @(~, ~) obj.CreateDialog_Monitor);

			% Unhide dialog now that all controls have been created
			dlg.Visible = 'on';
		end

		function CreateDialog_Monitor(obj)
			% If object already exists, show window
			if isfield(obj.Rsc, 'Monitor')
				if isvalid(obj.Rsc.Monitor)
					figure(obj.Rsc.Monitor)
					return
				end
			end
			dlgWidth = 800;
			dlgHeight = 400;

			% Create the dialog
			if isempty(obj.Arduino.SerialConnection)
				port = 'OFFLINE';
			else
				port = obj.Arduino.SerialConnection.Port;
			end
			dlg = dialog(...
				'Name', sprintf('Monitor (%s)', port),...
				'WindowStyle', 'normal',...
				'Position', [350, 50, dlgWidth, dlgHeight],...
				'Units', 'pixels',...
				'Resize', 'on',...
				'Visible', 'off'... % Hide until all controls created
			);
			% Store the dialog handle
			obj.Rsc.Monitor = dlg;

			% Size and position of controls
			dlg.UserData.DlgMargin = 20;
			dlg.UserData.LeftPanelWidthRatio = 0.3;
			dlg.UserData.PanelSpacing = 20;
			dlg.UserData.PanelMargin = 20;
			dlg.UserData.PanelMarginTop = 20;
			dlg.UserData.BarHeight = 75;
			dlg.UserData.TextHeight = 30;

			u = dlg.UserData;

			% % Close serial port when you close the window
			dlg.CloseRequestFcn = @(~, ~) (delete(gcbo));

			%----------------------------------------------------
			%		Left panel
			%----------------------------------------------------
			leftPanel = uipanel(...
				'Parent', dlg,...
				'Title', 'Experiment Summary',...
				'Units', 'pixels'...
			);
			dlg.UserData.Ctrl.LeftPanel = leftPanel;

			% Text: Number of trials completed
			trialCountText = uicontrol(...
				'Parent', leftPanel,...
				'Style', 'text',...
				'String', 'Trials completed: 0',...
				'TooltipString', 'Number of trials completed in this session.',...
				'HorizontalAlignment', 'left',...
				'Units', 'pixels',...
				'FontSize', 13 ...
			);
			dlg.UserData.Ctrl.TrialCountText = trialCountText;

			% Text: Result of last trial
			lastTrialResultText = uicontrol(...
				'Parent', leftPanel,...
				'Style', 'text',...
				'String', 'Last trial: ',...
				'TooltipString', 'Result of previous trial.',...
				'HorizontalAlignment', 'left',...
				'Units', 'pixels',...
				'FontSize', 13 ...
			);
			dlg.UserData.Ctrl.LastTrialResultText = lastTrialResultText;

			%----------------------------------------------------
			%		Right panel
			%----------------------------------------------------
			rightPanel = uitabgroup(...
				'Parent', dlg,...
				'Units', 'pixels'...
			);
			dlg.UserData.Ctrl.RightPanel = rightPanel;

			%----------------------------------------------------
			%		Raster Tab
			%----------------------------------------------------
			tab_raster = uitab(...
				'Parent', rightPanel,...
				'Title', 'Raster Plot'...
			);
			dlg.UserData.Ctrl.Tab_Raster = tab_raster;

			text_eventTrialStart_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'text',...
				'String', 'Trial Start Event',...
				'HorizontalAlignment', 'left'...				
			);
			dlg.UserData.Ctrl.Text_EventTrialStart_Raster = text_eventTrialStart_raster;

			popup_eventTrialStart_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventTrialStart_Raster = popup_eventTrialStart_raster;

			text_eventZero_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'text',...
				'String', 'Reference Event',...
				'HorizontalAlignment', 'left'...				
			);
			dlg.UserData.Ctrl.Text_EventZero_Raster = text_eventZero_raster;

			popup_eventZero_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventZero_Raster = popup_eventZero_raster;

			text_eventOfInterest_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'text',...
				'String', 'Event Of Interest',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_EventOfInterest_Raster = text_eventOfInterest_raster;

			popup_eventOfInterest_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventOfInterest_Raster = popup_eventOfInterest_raster;

			text_figureName_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'text',...
				'String', 'Figure Name',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_FigureName_Raster = text_figureName_raster;

			if isempty(obj.Arduino.SerialConnection)
				figName = 'Raster Plot';
			else
				figName = sprintf('Raster Plot (%s)', obj.Arduino.SerialConnection.Port);
			end
			edit_figureName_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'edit',...
				'String', figName,...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Edit_FigureName_Raster = edit_figureName_raster;

			tabgrp_plot_raster = uitabgroup(...
				'Parent', tab_raster,...
				'Units', 'pixels'...
			);
			dlg.UserData.Ctrl.TabGrp_Plot_Raster = tabgrp_plot_raster;

			tab_params_raster = uitab(...
				'Parent', tabgrp_plot_raster,...
				'Title', 'Add Parameters',...
				'Units', 'pixels'...
			);
			dlg.UserData.Ctrl.Tab_Params_Raster = tab_params_raster;			

			tab_events_raster = uitab(...
				'Parent', tabgrp_plot_raster,...
				'Title', 'Add Events',...
				'Units', 'pixels'...
			);
			dlg.UserData.Ctrl.Tab_Events_Raster = tab_events_raster;			

			paramNames = [obj.Arduino.ParamNames'; repmat({'Enter Custom Value'}, 4, 1)];
			numParams = length(paramNames);
			table_params_raster = uitable(...
				'Parent', tab_params_raster,...
				'Data', [paramNames, repmat({false}, [numParams, 1]), repmat({'black'}, [numParams, 1]), repmat({'-'}, [numParams, 1])],...
				'RowName', {},...
				'ColumnName', {'Parameter', 'Plot', 'Color', 'Style'},...
				'ColumnFormat', {'char', 'logical', {'black', 'red', 'blue', 'green', 'yellow', 'magenta', 'cyan'}, {'-', '--', ':', '-.'}},...
				'ColumnEditable', [true, true, true, true]...
			);
			dlg.UserData.Ctrl.Table_Params_Raster = table_params_raster;

			eventNames = obj.Arduino.EventMarkerNames';
			numEvents = length(eventNames);
			table_events_raster = uitable(...
				'Parent', tab_events_raster,...
				'Data', [eventNames, repmat({false}, [numEvents, 1]), repmat({'black'}, [numEvents, 1]), repmat({10}, [numEvents, 1])],...
				'RowName', {},...
				'ColumnName', {'Event', 'Plot', 'Color', 'Size'},...
				'ColumnFormat', {'char', 'logical', {'black', 'red', 'blue', 'green', 'yellow', 'magenta', 'cyan'}, 'numeric'},...
				'ColumnEditable', [false, true, true, true]...
			);
			dlg.UserData.Ctrl.Table_Events_Raster = table_events_raster;

			tab_params_raster.SizeChangedFcn = @(~, ~) MouseBehaviorInterface.OnPlotOptionsTabResized(table_params_raster);
			tab_events_raster.SizeChangedFcn = @(~, ~) MouseBehaviorInterface.OnPlotOptionsTabResized(table_events_raster);

			button_plot_raster = uicontrol(...
				'Parent', tab_raster,...
				'Style', 'pushbutton',...
				'String', 'Plot',...
				'Callback', @obj.Raster_GUI...
			);
			dlg.UserData.Ctrl.Button_Plot_Raster = button_plot_raster;

			%----------------------------------------------------
			%		Hist Tab
			%----------------------------------------------------
			tab_hist = uitab(...
				'Parent', rightPanel,...
				'Title', 'Histogram'...
			);
			dlg.UserData.Ctrl.Tab_Hist = tab_hist;

			text_eventTrialStart_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Trial Start Event',...
				'HorizontalAlignment', 'left'...				
			);
			dlg.UserData.Ctrl.Text_EventTrialStart_Hist = text_eventTrialStart_hist;

			popup_eventTrialStart_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventTrialStart_Hist = popup_eventTrialStart_hist;

			text_eventZero_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Reference Event',...
				'HorizontalAlignment', 'left'...				
			);
			dlg.UserData.Ctrl.Text_EventZero_Hist = text_eventZero_hist;

			popup_eventZero_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventZero_Hist = popup_eventZero_hist;

			text_eventOfInterest_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Event Of Interest',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_EventOfInterest_Hist = text_eventOfInterest_hist;

			popup_eventOfInterest_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventOfInterest_Hist = popup_eventOfInterest_hist;
            
            
            % AH--- 5/14/18
            text_eventSecondary_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Stimulation Event',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_EventSecondary_Hist = text_eventSecondary_hist;

			popup_eventSecondary_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'popupmenu',...
				'String', obj.Arduino.EventMarkerNames...
			);
			dlg.UserData.Ctrl.Popup_EventSecondary_Hist = popup_eventSecondary_hist;
            %----
            

			text_figureName_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Figure Name',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_FigureName_Hist = text_figureName_hist;
            
			if isempty(obj.Arduino.SerialConnection)
				figName = 'Histogram';
			else
				figName = sprintf('Histogram (%s)', obj.Arduino.SerialConnection.Port);
            end
            edit_figureName_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'edit',...
				'String', figName,...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Edit_FigureName_Hist = edit_figureName_hist;
            %----------AH 11-2-17
            text_numBins_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Number of Bins',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_NumBins_Hist = text_numBins_hist;
            numBins = 10;
			edit_numBins_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'edit',...
				'String', numBins,...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Edit_NumBins_Hist = edit_numBins_hist;
            %------------------------------------------------
            

            %----------AH 5-30-17
            text_trialMin_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Trial Min',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_TrialMin_Hist = text_trialMin_hist;
            trialMin = 1;
			edit_trialMin_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'edit',...
				'String', trialMin,...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Edit_TrialMin_Hist = edit_trialMin_hist;

            text_trialMax_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'text',...
				'String', 'Trial Max',...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Text_TrialMax_Hist = text_trialMax_hist;
            trialMax = 'all'; % set 'all' if want to plot all
			edit_trialMax_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'edit',...
				'String', trialMax,...
				'HorizontalAlignment', 'left'...
			);
			dlg.UserData.Ctrl.Edit_TrialMax_Hist = edit_trialMax_hist;
            %------------------------------------------------





			button_plot_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'pushbutton',...
				'String', 'Plot',...
				'Callback', @obj.Hist_GUI...
			);
			dlg.UserData.Ctrl.Button_Plot_Hist = button_plot_hist;


			button_plot_cdf_hist = uicontrol(...
				'Parent', tab_hist,...
				'Style', 'pushbutton',...
				'String', 'Plot CDF',...
				'Callback', @obj.CDF_Hist_GUI...
			);
			dlg.UserData.Ctrl.Button_Plot_CDF_Hist = button_plot_cdf_hist;


			%----------------------------------------------------
			%		Analysis Tab
			%----------------------------------------------------
			tab_analysis = uitab(...
				'Parent', rightPanel,...
				'Title', 'Analysis'...
			);
			dlg.UserData.Ctrl.Tab_Analysis = tab_analysis;


			button_plot_bootstrap_cdf_analysis = uicontrol(...
				'Parent', tab_analysis,...
				'Style', 'pushbutton',...
				'String', 'Bootstrap CDF',...
				'Callback', @obj.Bootstrap_CDF_Analysis_GUI...
			);
			dlg.UserData.Ctrl.Button_Plot_Bootstrap_CDF_Analysis = button_plot_bootstrap_cdf_analysis;

			%----------------------------------------------------
			% 		Stacked bar chart for trial results
			%----------------------------------------------------
			ax = axes(...
				'Parent', dlg,...
				'Units', 'pixels',...
				'XTickLabel', [],...
				'YTickLabel', [],...
				'XTick', [],...
				'YTick', [],...
				'Box', 'on'...
			);
			obj.Rsc.Monitor.UserData.Ctrl.Ax = ax;

			% Update session summary everytime a new trial's results are registered by Arduino
			obj.Arduino.Listeners.TrialRegistered = addlistener(obj.Arduino, 'TrialsCompleted', 'PostSet', @obj.OnTrialRegistered);


			%----------------------------------------------------
			% 		Menus
			%----------------------------------------------------
			menu_file = uimenu(dlg, 'Label', '&File');
			uimenu(menu_file, 'Label', '&Save Plot Settings ...', 'Callback', @(~, ~) obj.SavePlotSettings, 'Accelerator', 's');
			uimenu(menu_file, 'Label', '&Load Plot Settings ...', 'Callback', @(~, ~) obj.LoadPlotSettings, 'Accelerator', 'l');
			menu_plot = uimenu(menu_file, 'Label', '&Plot Update', 'Separator', 'on');
			menu_plot.UserData.Menu_Enable = uimenu(menu_plot, 'Label', '&Enabled', 'Callback', @(~, ~) obj.EnablePlotUpdate(menu_plot));
			menu_plot.UserData.Menu_Disable = uimenu(menu_plot, 'Label', '&Disabled', 'Callback', @(~, ~) obj.DisablePlotUpdate(menu_plot));

			if isfield(obj.UserData, 'UpdatePlot')
				if obj.UserData.UpdatePlot
					menu_plot.UserData.Menu_Enable.Checked = 'on';
					menu_plot.UserData.Menu_Disable.Checked = 'off';
				else
					menu_plot.UserData.Menu_Enable.Checked = 'off';
					menu_plot.UserData.Menu_Disable.Checked = 'on';
				end
			else
				menu_plot.UserData.Menu_Enable.Checked = 'on';
				menu_plot.UserData.Menu_Disable.Checked = 'off';
				obj.UserData.UpdatePlot = true;
			end

			menu_window = uimenu(dlg, 'Label', '&Window');
			uimenu(menu_window, 'Label', 'Experiment Control', 'Callback', @(~, ~) @obj.CreateDialog_ExperimentControl);
			uimenu(menu_window, 'Label', 'Monitor', 'Callback', @(~, ~) obj.CreateDialog_Monitor);

			% Stretch barchart When dialog window is resized
			dlg.SizeChangedFcn = @MouseBehaviorInterface.OnMonitorDialogResized; 

			% Unhide dialog now that all controls have been created
			dlg.Visible = 'on';
		end

		function CreateDialog_Nidaq(obj)
			% If object already exists, show window
			if isfield(obj.Rsc, 'Nidaq')
				if isvalid(obj.Rsc.Nidaq)
					figure(obj.Rsc.Nidaq)
					return
				end
			end

			% Create the dialog
			if isempty(obj.Arduino.SerialConnection)
				port = 'OFFLINE';
			else
				port = obj.Arduino.SerialConnection.Port;
			end
			dlg = dialog(...
				'Name', sprintf('NIDAQ (%s)', port),...
				'WindowStyle', 'normal',...
				'Position', [350, 450, 400, 200],...
				'Units', 'pixels',...
				'Resize', 'on',...
				'Visible', 'off'... % Hide until all controls created
			);

			% Store the dialog handle
			obj.Rsc.Nidaq = dlg;

			% Size and position of controls
			dlg.UserData.Spacing = 20;
			dlg.UserData.TextHeight = 30;

			u = dlg.UserData;

			% delete object when you close the window
			dlg.CloseRequestFcn = @(~, ~) (delete(gcbo));


			%----------------------------------------------------
			% 		Stacked bar chart for trial results
			%----------------------------------------------------
			ax = axes(...
				'Parent', dlg,...
				'Units', 'pixels',...
				'XTickLabel', [],...
				'YTickLabel', [],...
				'XTick', [],...
				'YTick', [],...
				'Box', 'on'...
			);
			obj.Rsc.Monitor.UserData.Ctrl.Ax = ax;

			% Update session summary everytime a new trial's results are registered by Arduino
			obj.Arduino.Listeners.TrialRegistered = addlistener(obj.Arduino, 'TrialsCompleted', 'PostSet', @obj.OnTrialRegistered);


			%----------------------------------------------------
			% 		Menus
			%----------------------------------------------------
			menu_file = uimenu(dlg, 'Label', '&File');
			uimenu(menu_file, 'Label', '&Save Plot Settings ...', 'Callback', @(~, ~) obj.SavePlotSettings, 'Accelerator', 's');
			uimenu(menu_file, 'Label', '&Load Plot Settings ...', 'Callback', @(~, ~) obj.LoadPlotSettings, 'Accelerator', 'l');
			menu_plot = uimenu(menu_file, 'Label', '&Plot Update', 'Separator', 'on');
			menu_plot.UserData.Menu_Enable = uimenu(menu_plot, 'Label', '&Enabled', 'Callback', @(~, ~) obj.EnablePlotUpdate(menu_plot));
			menu_plot.UserData.Menu_Disable = uimenu(menu_plot, 'Label', '&Disabled', 'Callback', @(~, ~) obj.DisablePlotUpdate(menu_plot));

			if isfield(obj.UserData, 'UpdatePlot')
				if obj.UserData.UpdatePlot
					menu_plot.UserData.Menu_Enable.Checked = 'on';
					menu_plot.UserData.Menu_Disable.Checked = 'off';
				else
					menu_plot.UserData.Menu_Enable.Checked = 'off';
					menu_plot.UserData.Menu_Disable.Checked = 'on';
				end
			else
				menu_plot.UserData.Menu_Enable.Checked = 'on';
				menu_plot.UserData.Menu_Disable.Checked = 'off';
				obj.UserData.UpdatePlot = true;
			end

			menu_window = uimenu(dlg, 'Label', '&Window');
			uimenu(menu_window, 'Label', 'Experiment Control', 'Callback', @(~, ~) @obj.CreateDialog_ExperimentControl);
			uimenu(menu_window, 'Label', 'Monitor', 'Callback', @(~, ~) obj.CreateDialog_Monitor);

			% Stretch barchart When dialog window is resized
			% dlg.SizeChangedFcn = @MouseBehaviorInterface.OnNiDaqDialogResized; 

			% Unhide dialog now that all controls have been created
			dlg.Visible = 'on';
		end

		function CreateDialog_Splash(obj)
			% Load image
			[fncpath, ~, ~] = fileparts(which('MouseBehaviorInterface'));
			img = imread([fncpath, '\logo.png']);

			% Create java window object
			splashImage = im2java(img);
			win = javax.swing.JWindow;
			obj.Rsc.Splash = win;
			icon = javax.swing.ImageIcon(splashImage);
			label = javax.swing.JLabel(icon);
			win.getContentPane.add(label);
			win.setAlwaysOnTop(true);
			win.pack;

			% Set the splash image to the center of the screen
			screenSize = win.getToolkit.getScreenSize;
			screenHeight = screenSize.height;
			screenWidth = screenSize.width;
			% Get the actual splashImage size
			imgHeight = icon.getIconHeight;
			imgWidth = icon.getIconWidth;
			win.setLocation((screenWidth-imgWidth)/2,(screenHeight-imgHeight)/2);

			% Show the splash screen
			win.show

			% Hide in 10 seconds
			t = timer;
			obj.Rsc.SplashTimer = t;
			t.StartDelay = 10;
			t.TimerFcn = @(~, ~) win.dispose;
			start(t)
		end

		function CloseDialog_Splash(obj)
			stop(obj.Rsc.SplashTimer);
			obj.Rsc.Splash.dispose;
		end

		function OnTrialRegistered(obj, ~, ~)
		% Executed when a new trial is completed
			% Autosave if a savepath is defined
			if (~isempty(obj.Arduino.ExperimentFileName) && obj.Arduino.AutosaveEnabled)
				MouseBehaviorInterface.ArduinoSaveExperiment([], [], obj.Arduino);
			end

			% Updated monitor window
			if isvalid(obj.Rsc.Monitor)
				% Count how many trials have been completed
				iTrial = obj.Arduino.TrialsCompleted;

				% Update the "Trials Completed" counter.
				t = obj.Rsc.Monitor.UserData.Ctrl.TrialCountText;
				t.String = sprintf('Trials completed: %d', iTrial);

				% Show result of last trial
				t = obj.Rsc.Monitor.UserData.Ctrl.LastTrialResultText;
				t.String = sprintf('Last trial: %s', obj.Arduino.Trials(iTrial).CodeName);

				% When a new trial is completed
				ax = obj.Rsc.Monitor.UserData.Ctrl.Ax;
				% Get a list of currently recorded result codes
				resultCodes = reshape([obj.Arduino.Trials.Code], [], 1);
				resultCodeNames = obj.Arduino.ResultCodeNames;
				allResultCodes = 1:(length(resultCodeNames) + 1);
				resultCodeCounts = histcounts(resultCodes, allResultCodes);

				MouseBehaviorInterface.StackedBar(ax, resultCodeCounts, resultCodeNames);
			end

			drawnow
		end

		%----------------------------------------------------
		%		Plot - Raster plot events for each trial
		%----------------------------------------------------
		function Raster_GUI(obj, ~, ~)
			ctrl = obj.Rsc.Monitor.UserData.Ctrl;

			eventCodeTrialStart = ctrl.Popup_EventTrialStart_Raster.Value;
			eventCodeZero 		= ctrl.Popup_EventZero_Raster.Value;
			eventCodeOfInterest = ctrl.Popup_EventOfInterest_Raster.Value;
			figName 			= ctrl.Edit_FigureName_Raster.String;
			paramPlotOptions 	= ctrl.Table_Params_Raster.Data;
			eventPlotOptions	= ctrl.Table_Events_Raster.Data;

			obj.Raster(eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, figName, paramPlotOptions, eventPlotOptions)
		end
		function Raster(obj, eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, figName, paramPlotOptions, eventPlotOptions)
			% First column in data is eventCode, second column is timestamp (since trial start)
			if nargin < 5
				figName = '';
			end
			if nargin < 6
				paramPlotOptions = struct([]);
			end

			% Create axes object
			f = figure('Name', figName, 'NumberTitle', 'off');

			% Store the axes object
			if ~isfield(obj.Rsc, 'LooseFigures')
				figId = 1;
			else
				figId = length(obj.Rsc.LooseFigures) + 1;
			end
			obj.Rsc.LooseFigures(figId).Ax = gca;
			ax = obj.Rsc.LooseFigures(figId).Ax;

			% Store plot settings into axes object
			ax.UserData.EventCodeTrialStart = eventCodeTrialStart;
			ax.UserData.EventCodeZero 		= eventCodeZero;
			ax.UserData.EventCodeOfInterest = eventCodeOfInterest;
			ax.UserData.FigName				= figName;
			ax.UserData.ParamPlotOptions 	= paramPlotOptions;
			ax.UserData.EventPlotOptions 	= eventPlotOptions;

			% Plot it for the first time
			obj.Raster_Execute(figId);

			% Plot again everytime an event of interest occurs
			ax.UserData.Listener = addlistener(obj.Arduino, 'TrialsCompleted', 'PostSet', @(~, ~) obj.Raster_Execute(figId));
			f.CloseRequestFcn = {@MouseBehaviorInterface.OnLooseFigureClosed, ax.UserData.Listener};
		end
		function Raster_Execute(obj, figId)
			% Do not plot if the Grad Student decides we should stop plotting stuff.
			if isfield(obj.UserData, 'UpdatePlot') && (~obj.UserData.UpdatePlot)
				return
			end

			data 				= obj.Arduino.EventMarkers;
			ax 					= obj.Rsc.LooseFigures(figId).Ax;

			eventCodeTrialStart = ax.UserData.EventCodeTrialStart;
			eventCodeOfInterest = ax.UserData.EventCodeOfInterest;
			eventCodeZero 		= ax.UserData.EventCodeZero;
			figName 			= ax.UserData.FigName;
			paramPlotOptions	= ax.UserData.ParamPlotOptions;
			eventPlotOptions	= ax.UserData.EventPlotOptions;

			% If events did not occur at all, do not plot
			if (isempty(data))
				return
			end

			% Plot events
			hold(ax, 'on')
			obj.Raster_Execute_Events(ax, data, eventCodeTrialStart, eventCodeOfInterest, eventCodeZero, eventPlotOptions);

			% Plot parameters
			obj.Raster_Execute_Params(ax, paramPlotOptions);
			hold(ax, 'off')

			% Annotations
			lgd = legend(ax, 'Location', 'northoutside');
			lgd.Interpreter = 'none';
			lgd.Orientation = 'horizontal';

			ax.XLimMode 		= 'auto';
			ax.XLim 			= [max([-5000, ax.XLim(1) - 100]), ax.XLim(2) + 100];
			ax.YLim 			= [0, obj.Arduino.TrialsCompleted + 1];
			ax.YDir				= 'reverse';
			ax.XLabel.String 	= 'Time (ms)';
			ax.YLabel.String 	= 'Trial';

			% Set ytick labels
			tickInterval 	= max([1, round(ceil(obj.Arduino.TrialsCompleted/10)/5)*5]);
			ticks 			= tickInterval:tickInterval:obj.Arduino.TrialsCompleted;
			if (tickInterval > 1)
				ticks = [1, ticks];
			end
			if (obj.Arduino.TrialsCompleted) > ticks(end)
				ticks = [ticks, obj.Arduino.TrialsCompleted];
			end
			ax.YTick 		= ticks;
			ax.YTickLabel 	= ticks;

			title(ax, figName)

			% Store plot options cause for some reason it's lost unless we do this.
			ax.UserData.EventCodeTrialStart = eventCodeTrialStart;
			ax.UserData.EventCodeZero 		= eventCodeZero;
			ax.UserData.EventCodeOfInterest = eventCodeOfInterest;
			ax.UserData.FigName 			= figName;
			ax.UserData.ParamPlotOptions 	= paramPlotOptions;
			ax.UserData.EventPlotOptions 	= eventPlotOptions;
		end
		function Raster_Execute_Events(obj, ax, data, eventCodeTrialStart, eventCodeOfInterest, eventCodeZero, eventPlotOptions)
			% Plot primary event of interest
			obj.Raster_Execute_Single(ax, data, eventCodeTrialStart, eventCodeOfInterest, eventCodeZero, 'cyan', 10)

			% Filter out events the Grad Student does not want to plot
			eventsToPlot = find([eventPlotOptions{:, 2}]);

			if ~isempty(eventsToPlot)
				for iEvent = eventsToPlot
					if iEvent == eventCodeOfInterest
						continue
					end
					obj.Raster_Execute_Single(ax, data, eventCodeTrialStart, iEvent, eventCodeZero, eventPlotOptions{iEvent, 3}, eventPlotOptions{iEvent, 4})					
				end
			end	
		end
		function Raster_Execute_Single(obj, ax, data, eventCodeTrialStart, eventCodeOfInterest, eventCodeZero, markerColor, markerSize)
			% Separate eventsOfInterest into trials, divided by eventsZero
			eventsTrialStart	= find(data(:, 1) == eventCodeTrialStart);
			eventsZero 			= find(data(:, 1) == eventCodeZero);
			eventsOfInterest 	= find(data(:, 1) == eventCodeOfInterest);

			% If events did not occur at all, do not plot
			if (isempty(eventsTrialStart) || isempty(eventsZero) || isempty(eventsOfInterest))
				return
			end

			if eventsOfInterest(end) > eventsTrialStart(end) || eventsZero(end) > eventsTrialStart(end)
				edges = [eventsTrialStart; max([eventsZero(end), eventsOfInterest(end)]) + 1];
			else
				edges = [eventsTrialStart; eventsTrialStart(end) + 1];
			end

			% Filter out 'orphan' eventsOfInterest that do not have an eventZero in the same trial 
			[~, ~, trialsOfInterest] = histcounts(eventsOfInterest, edges);
			[~, ~, trialsZero] = histcounts(eventsZero, edges);

			ism = ismember(trialsOfInterest, trialsZero);
			if (sum(ism) == 0)
				return
			end
			trialsOfInterest = trialsOfInterest(ism);
			eventsOfInterest = eventsOfInterest(ism);

			% Events of interest timestamps
			eventTimesOfInterest = data(eventsOfInterest, 2); 

			% Reference events timestamps
			if trialsOfInterest(end) > trialsZero(end)
				edges = [trialsZero; trialsOfInterest(end) + 1];
			else
				edges = [trialsZero; trialsZero(end) + 1];
			end
			[~, ~, bins] = histcounts(trialsOfInterest, edges);
			eventTimesZero = data(eventsZero(bins), 2);

			% Plot histogram of selected event times
			eventTimesRelative = eventTimesOfInterest - eventTimesZero;

			if ischar(markerColor)
				switch markerColor
					case 'black'
						markerColor = [.1, .1, .1];
					case 'red'
						markerColor = [.9, .1, .1];
					case 'blue'
						markerColor = [.1, .1, .9];
					case 'green'
						markerColor = [.1, .9, .1];
					case 'cyan'
						markerColor = [0, .5, .5];
				end
			end

			plot(ax, eventTimesRelative, trialsOfInterest, '.',...
				'MarkerSize', markerSize,...
				'MarkerEdgeColor', markerColor,...
				'MarkerFaceColor', markerColor,...
				'LineWidth', 1.5,...
				'DisplayName', obj.Arduino.EventMarkerNames{eventCodeOfInterest}...
			)
		end
		function Raster_Execute_Params(obj, ax, paramPlotOptions)
			% Plot parameters
			% Filter out parameters the Grad Student does not want to plot
			paramsToPlot = find([paramPlotOptions{:, 2}]);

			if ~isempty(paramsToPlot)
				params = ctranspose(reshape([obj.Arduino.Trials.Parameters], [], size(obj.Arduino.Trials, 2)));			
				for iParam = paramsToPlot
					% Arduino parameter
					if iParam <= length(obj.Arduino.ParamNames)
						paramValues = params(:, iParam);
					% Plot custom parameter unless the Grad Student changes its default name to a number
					elseif ~isempty(str2num(paramPlotOptions{iParam, 1}))
						paramValues = repmat(str2num(paramPlotOptions{iParam, 1}), size(params, 1), 1);
					else
						continue
					end
					plot(ax, paramValues, 1:length(obj.Arduino.Trials),...
						'DisplayName', num2str(paramPlotOptions{iParam, 1}),...
						'Color', paramPlotOptions{iParam, 3},...
						'LineStyle', paramPlotOptions{iParam, 4},...
						'LineWidth', 1.2 ...
					);
				end
			end			
		end

		%----------------------------------------------------
		%		Plot - Histogram of first licks/press duration
		%----------------------------------------------------
		function Hist_GUI(obj, ~, ~)
			ctrl = obj.Rsc.Monitor.UserData.Ctrl;

			eventCodeTrialStart = ctrl.Popup_EventTrialStart_Hist.Value;
			eventCodeZero 		= ctrl.Popup_EventZero_Hist.Value;
			eventCodeOfInterest = ctrl.Popup_EventOfInterest_Hist.Value;
            %--------- AH 5-14-18
            eventCodeSecondaryType = ctrl.Popup_EventSecondary_Hist.Value;
            %---------
			figName 			= ctrl.Edit_FigureName_Hist.String;
               %--------AH 11-2-17
            numBins             = ctrl.Edit_NumBins_Hist.String;


            % AH 5/30/18--------------------
            if strcmp(ctrl.Edit_TrialMax_Hist.String, 'all')
            	trialMax = obj.Arduino.TrialsCompleted;
        	elseif str2num(ctrl.Edit_TrialMax_Hist.String) > obj.Arduino.TrialsCompleted
        		trialMax = obj.Arduino.TrialsCompleted;
        		warning('TrialMax requested was too big! Setting to TrialsCompleted');
    		elseif str2num(ctrl.Edit_TrialMax_Hist.String) < 1 || str2num(ctrl.Edit_TrialMax_Hist.String) < str2num(ctrl.Edit_TrialMin_Hist.String)
    			trialMax = obj.Arduino.TrialsCompleted;
    			warning('TrialMax requested was too small! Setting to TrialsCompleted');
            else
                trialMax = str2num(ctrl.Edit_TrialMax_Hist.String);
			end

			if trialMax < 1
				trialMax = 1;
			end

			trialMin = str2num(ctrl.Edit_TrialMin_Hist.String);
            %----------------------------------------------


			obj.Hist(eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, eventCodeSecondaryType, figName, numBins, trialMin, trialMax)
                %-----------------
        end
        %----------AH 11-2-17
		function Hist(obj, eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, eventCodeSecondaryType, figName, numBins, trialMin, trialMax)
            %---------------
			% First column in data is eventCode, second column is timestamp (since trial start)
			if nargin < 6
				figName = '';
			%------------- AH 5/29/18
				numBins = 10;
				trialMin = 1;
				trialMax = obj.Arduino.TrialsCompleted;
			%------------- end AH 5/29/18				
            end
            %------------AH 11-2-17
			if nargin < 7
				numBins = 10;
				trialMin = 1;
				trialMax = obj.Arduino.TrialsCompleted;
            end
            
			if nargin < 8
				trialMin = 1;
				trialMax = obj.Arduino.TrialsCompleted;
            end

			if nargin < 9
				trialMax = obj.Arduino.TrialsCompleted;
            end
            
            %-----------------------
			% Create axes object
			f = figure('Name', figName, 'NumberTitle', 'off');

			% Store the axes object
			if ~isfield(obj.Rsc, 'LooseFigures')
				figId = 1;
			else
				figId = length(obj.Rsc.LooseFigures) + 1;
			end
			obj.Rsc.LooseFigures(figId).Ax = gca;
			ax = obj.Rsc.LooseFigures(figId).Ax;

			% Store plot settings into axes object
			ax.UserData.EventCodeTrialStart = eventCodeTrialStart;
			ax.UserData.EventCodeZero 		= eventCodeZero;
			ax.UserData.EventCodeOfInterest = eventCodeOfInterest;
            %------ AH 5/14/18
            ax.UserData.EventCodeSecondary      = eventCodeSecondaryType;
            %------
			ax.UserData.FigName				= figName;

			% Plot it for the first time
            %-------------AH 11/2
			obj.Hist_Execute(figId, numBins, trialMin, trialMax);
            %----------------------

			% Plot again everytime an event of interest occurs
			ax.UserData.Listener = addlistener(obj.Arduino, 'TrialsCompleted', 'PostSet', @(~, ~) obj.Hist_Execute(figId, numBins, trialMin, trialMax));
			f.CloseRequestFcn = {@MouseBehaviorInterface.OnLooseFigureClosed, ax.UserData.Listener};
		end
		function Hist_Execute(obj, figId, numBins, trialMin, trialMax)
			% Do not plot if the Grad Student decides we should stop plotting stuff.
			if isfield(obj.UserData, 'UpdatePlot') && (~obj.UserData.UpdatePlot)
				return
			end

			data 				= obj.Arduino.EventMarkers;
			ax 					= obj.Rsc.LooseFigures(figId).Ax;

			eventCodeTrialStart = ax.UserData.EventCodeTrialStart;
			eventCodeOfInterest = ax.UserData.EventCodeOfInterest;
			eventCodeZero 		= ax.UserData.EventCodeZero;
            % ----- AH 5/14/18
            eventCodeSecondaryType = ax.UserData.EventCodeSecondary;
            % -----
			figName 			= ax.UserData.FigName;

% 
% 			trialMin = 1;
% 			if obj.Arduino.TrialsCompleted >= 1
% 				trialMax = obj.Arduino.TrialsCompleted;
% 			else
% 				trialMax = 1;
% 			end


			% If events did not occur at all, do not plot
			if (isempty(data))
				return
			end

			% Separate eventsOfInterest into trials, divided by eventsZero
			eventsTrialStart	= find(data(:, 1) == eventCodeTrialStart);
% 			eventsTrialStart    = eventsTrialStart(trialMin:trialMax);

			eventsZero 			= find(data(:, 1) == eventCodeZero);
			eventsOfInterest 	= find(data(:, 1) == eventCodeOfInterest);
            eventsSecondary 	= find(data(:, 1) == eventCodeSecondaryType);

			% If events did not occur at all, do not plot
			if (isempty(eventsTrialStart) || isempty(eventsZero) || isempty(eventsOfInterest))
				return
			end

			if eventsOfInterest(end) > eventsTrialStart(end) || eventsZero(end) > eventsTrialStart(end)
				edges = [eventsTrialStart; max([eventsZero(end), eventsOfInterest(end)]) + 1];
% AH 5/29/18 --- updated so can plot only subsets of trials..........
%                 edges = [eventsTrialStart; eventsTrialStart(end) + 1];
% --------------------------------------------------------------
			else
				edges = [eventsTrialStart; eventsTrialStart(end) + 1];
			end

			% Filter out 'orphan' eventsOfInterest that do not have an eventZero in the same trial 
			[~, ~, trialsOfInterest] = histcounts(eventsOfInterest, edges);
			[~, ~, trialsZero] = histcounts(eventsZero, edges);
            % ---- AH 5/14/18
            [~, ~, trialsStim] = histcounts(eventsSecondary, edges);
            %-----
    
			ism = ismember(trialsOfInterest, trialsZero);
			if (sum(ism) == 0)
				return
            end
			trialsOfInterest = trialsOfInterest(ism);
			eventsOfInterest = eventsOfInterest(ism);
            % ----- AH 5/14/18
            ism2 = ismember(trialsOfInterest, trialsStim);
            trialsStim = trialsOfInterest(ism2);
            % TRIM OFF UNWANTED TRIALS HERE!!!!!!!!!! 5/29/18:
            trialsOfInterest = trialsOfInterest(logical((trialsOfInterest >= trialMin) .* (trialsOfInterest <= trialMax)));
            trialsStim = trialsStim(logical((trialsStim >= trialMin) .* (trialsStim <= trialMax)));
            
            %-------------
            

			% Get timestamps for events of interests and zero events
			[C, ia, ~] 			= unique(trialsOfInterest);
			eventsZero  		= eventsZero(C);

% 5/29/18 AH ----  fixed this for trialMin and trialMax -- this will work
% if only one event per trial, but will fail if there's more than one event
% per trial
            if trialMin == 1
     			eventsOfInterest 	= eventsOfInterest(ia);
                % so if you plot all trials, then can plot events for which
                % multiple events occur on a trial. Otherwise, should only
                % use trial min/trial max with events like FIRST_LICK
            elseif trialMin ~= 1
                eventsOfInterest 	= eventsOfInterest(C);
            end
            

			eventTimesOfInterest 	= data(eventsOfInterest, 2);
			eventTimesZero 			= data(eventsZero, 2);
			
			% Substract two sets of timestamps to get relative times 
			eventTimesOfInterest 	= eventTimesOfInterest - eventTimesZero;
            
            % ---- AH 5/14/18: peel off the trials with the secondary event
            % and plot separately
            eventTimesOfInterest_noSecondary = nan(size(eventTimesOfInterest));
            eventTimesOfInterest_Secondary = nan(size(eventTimesOfInterest));
            
            stim_index = find(ismember(trialsOfInterest,trialsStim));
            no_stim_index = find(~ismember(trialsOfInterest,trialsStim));
            eventTimesOfInterest_Secondary = eventTimesOfInterest(stim_index);
            eventTimesOfInterest_noSecondary = eventTimesOfInterest(no_stim_index);
            obj.Rsc.Monitor.UserData.eventTimesOfInterest_Secondary = eventTimesOfInterest_Secondary;
            obj.Rsc.Monitor.UserData.eventTimesOfInterest_noSecondary = eventTimesOfInterest_noSecondary;
            
            median_Secondary = nanmedian(eventTimesOfInterest_Secondary(find(eventTimesOfInterest_Secondary > 700)));
            [obj.Rsc.Monitor.UserData.cdf_stim.f, obj.Rsc.Monitor.UserData.cdf_stim.x] = ecdf(eventTimesOfInterest_Secondary(find(eventTimesOfInterest_Secondary > 700)));
            median_noSecondary = nanmedian(eventTimesOfInterest_noSecondary(find(eventTimesOfInterest_noSecondary > 700)));
            [obj.Rsc.Monitor.UserData.cdf_nostim.f, obj.Rsc.Monitor.UserData.cdf_nostim.x] = ecdf(eventTimesOfInterest_noSecondary(find(eventTimesOfInterest_noSecondary > 700)));
            
			% Plot histogram of selected event times
            %----------- AH 11-2-17
%             disp(numBins)
%             disp(class(numBins))
% 			histogram(ax, eventTimesOfInterest, str2double(numBins), 'DisplayName', obj.Arduino.EventMarkerNames{eventCodeOfInterest})
			% disp('here')
			cla(ax)
            histogram(ax, eventTimesOfInterest_noSecondary, str2double(numBins), 'DisplayName', [obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' no stim'])
            hold on
            plot([median_noSecondary, median_noSecondary], [0,15], 'b-', 'LineWidth', 3, 'DisplayName', 'Median (>700ms) No Stim');
            histogram(ax, eventTimesOfInterest_Secondary, str2double(numBins), 'DisplayName', [obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' stim'])
            plot([median_Secondary, median_Secondary], [0,15], 'm-', 'LineWidth', 3, 'DisplayName', 'Median (>700ms) + Stim');

            % hold off
            %----------------
			lgd = legend(ax, 'Location', 'northoutside');
			lgd.Interpreter = 'none';
			lgd.Orientation = 'horizontal';
			ax.XLabel.String 	= 'Time (ms)';
			ax.YLabel.String 	= 'Occurance';
			title(ax, figName)

			% Store plot options cause for some reason it's lost unless we do this.
			ax.UserData.EventCodeTrialStart = eventCodeTrialStart;
			ax.UserData.EventCodeZero 		= eventCodeZero;
			ax.UserData.EventCodeOfInterest = eventCodeOfInterest;
			ax.UserData.EventCodeSecondary  = eventCodeSecondaryType;
			ax.UserData.FigName 			= figName;
		end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
		%----------------------------------------------------
		%		Plot - CDF first licks/press duration
		%----------------------------------------------------
		function CDF_Hist_GUI(obj, ~, ~)
			ctrl = obj.Rsc.Monitor.UserData.Ctrl;

			eventCodeTrialStart = ctrl.Popup_EventTrialStart_Hist.Value;
			eventCodeZero 		= ctrl.Popup_EventZero_Hist.Value;
			eventCodeOfInterest = ctrl.Popup_EventOfInterest_Hist.Value;
            eventCodeSecondaryType = ctrl.Popup_EventSecondary_Hist.Value;
			figName 			= ['CDF'];
            % numBins             = ctrl.Edit_NumBins_Hist.String;
			
			% run the hist gui to make sure we have CDFs to plot
			% obj.Hist_GUI(obj)
			obj.CDF(figName, eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, eventCodeSecondaryType)
        end
        %----------AH 11-2-17
		function CDF(obj, figName, eventCodeTrialStart, eventCodeZero, eventCodeOfInterest, eventCodeSecondaryType)
			% Create axes object
			f = figure('Name', figName, 'NumberTitle', 'off');

			% Store the axes object
			if ~isfield(obj.Rsc, 'LooseFigures')
				figId = 1;
			else
				figId = length(obj.Rsc.LooseFigures) + 1;
			end
			obj.Rsc.LooseFigures(figId).Ax = gca;
			ax = obj.Rsc.LooseFigures(figId).Ax;

			% Store plot settings into axes object
% 			ax.UserData.EventCodeTrialStart 	= eventCodeTrialStart;
% 			ax.UserData.EventCodeZero 			= eventCodeZero;
			ax.UserData.EventCodeOfInterest 	= eventCodeOfInterest;
%             ax.UserData.EventCodeSecondary      = eventCodeSecondaryType;

			if isfield(obj.Rsc.Monitor.UserData, 'cdf_stim') && isfield(obj.Rsc.Monitor.UserData, 'cdf_nostim')
				ax.UserData.cdf_stim.f 		= obj.Rsc.Monitor.UserData.cdf_stim.f;
				ax.UserData.cdf_stim.x 		= obj.Rsc.Monitor.UserData.cdf_stim.x;
				ax.UserData.cdf_nostim.f 	= obj.Rsc.Monitor.UserData.cdf_nostim.f;
				ax.UserData.cdf_nostim.x 	= obj.Rsc.Monitor.UserData.cdf_nostim.x;
			else
				obj.Hist_GUI()
				ax.UserData.cdf_stim.f 		= obj.Rsc.Monitor.UserData.cdf_stim.f;
				ax.UserData.cdf_stim.x 		= obj.Rsc.Monitor.UserData.cdf_stim.x;
				ax.UserData.cdf_nostim.f 	= obj.Rsc.Monitor.UserData.cdf_nostim.f;
				ax.UserData.cdf_nostim.x 	= obj.Rsc.Monitor.UserData.cdf_nostim.x;
			end	
			ax.UserData.FigName			= figName;

			obj.CDF_Execute(figId);
            
			% Plot again everytime an event of interest occurs
			ax.UserData.Listener = addlistener(obj.Arduino, 'TrialsCompleted', 'PostSet', @(~, ~) obj.CDF_Execute(figId));
			f.CloseRequestFcn = {@MouseBehaviorInterface.OnLooseFigureClosed, ax.UserData.Listener};
		end
		function CDF_Execute(obj, figId)
			% Do not plot if the Grad Student decides we should stop plotting stuff.
			if isfield(obj.UserData, 'UpdatePlot') && (~obj.UserData.UpdatePlot)
				return
			end

			ax 				= obj.Rsc.LooseFigures(figId).Ax;
			cdf_stim.f 		= ax.UserData.cdf_stim.f; 
			cdf_stim.x  	= ax.UserData.cdf_stim.x ;
			cdf_nostim.f 	= ax.UserData.cdf_nostim.f; 
			cdf_nostim.x  	= ax.UserData.cdf_nostim.x;

% 			eventCodeTrialStart = ax.UserData.EventCodeTrialStart;
% 			eventCodeZero 		= ax.UserData.EventCodeZero;
			eventCodeOfInterest = ax.UserData.EventCodeOfInterest;
%             eventCodeSecondaryType	= ax.UserData.EventCodeSecondary;

			figName 		= ax.UserData.FigName;

			plot(ax, cdf_nostim.x, cdf_nostim.f, 'LineWidth', 3, 'DisplayName', [obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' no stim'])
			hold on
			plot(ax, cdf_stim.x, cdf_stim.f, 'LineWidth', 3, 'DisplayName', [obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' + stim'])
			
            
            %----------------
			lgd = legend(ax, 'Location', 'northoutside');
			lgd.Interpreter = 'none';
			lgd.Orientation = 'horizontal';
			ax.XLabel.String 	= 'Time (ms)';
			ax.YLabel.String 	= 'cdf';
			title(ax, figName)

			% Store plot options cause for some reason it's lost unless we do this.
			ax.UserData.cdf_stim.f 			= cdf_stim.f;
			ax.UserData.cdf_stim.x 			= cdf_stim.x;
			ax.UserData.cdf_nostim.f 		= cdf_nostim.f;
			ax.UserData.cdf_nostim.x 		= cdf_nostim.x;
			ax.UserData.FigName 			= figName;
		end









		%----------------------------------------------------
		%		Analysis - Plot - Bootstrap CDF first licks/press duration
		%----------------------------------------------------
		function Bootstrap_CDF_Analysis_GUI(obj, ~, ~)
			nboot = 100000;
            ctrl = obj.Rsc.Monitor.UserData.Ctrl;

			if isfield(obj.Rsc.Monitor.UserData, 'cdf_stim')
				eventTimesOfInterest_Secondary = obj.Rsc.Monitor.UserData.eventTimesOfInterest_Secondary;
				eventTimesOfInterest_noSecondary = obj.Rsc.Monitor.UserData.eventTimesOfInterest_noSecondary;
				cdf_stim 	= obj.Rsc.Monitor.UserData.cdf_stim; 
				cdf_nostim 	= obj.Rsc.Monitor.UserData.cdf_nostim;
			else
				obj.Hist_GUI();
				eventTimesOfInterest_Secondary = obj.Rsc.Monitor.UserData.eventTimesOfInterest_Secondary;
				eventTimesOfInterest_noSecondary = obj.Rsc.Monitor.UserData.eventTimesOfInterest_noSecondary;
				cdf_stim 	= obj.Rsc.Monitor.UserData.cdf_stim; 
				cdf_nostim 	= obj.Rsc.Monitor.UserData.cdf_nostim;
			end

			% eventCodeTrialStart = ctrl.Popup_EventTrialStart_Hist.Value;
			% eventCodeZero 		= ctrl.Popup_EventZero_Hist.Value;
			eventCodeOfInterest = ctrl.Popup_EventOfInterest_Hist.Value;
            % eventCodeSecondaryType = ctrl.Popup_EventSecondary_Hist.Value;
			figName 			= 'Bootstrapped CDF';
            
			
			% Create 100 bootstraps without replacement:
			unique_nostim = eventTimesOfInterest_noSecondary(eventTimesOfInterest_noSecondary > 700);
			unique_stim = eventTimesOfInterest_Secondary(eventTimesOfInterest_Secondary > 700);
			totalset = vertcat(unique_stim, unique_nostim);

			bootstraps_stim = nan(nboot, length(unique_stim));
			f_cdfstim = [];
			bootstraps_nostim = nan(nboot, length(unique_nostim));
			f_cdfnostim = [];

			median_stim = nan(1,nboot);
			median_nostim = nan(1,nboot);
            median_diff = nan(1,nboot);

			for iboot = 1:nboot
				idx = randperm(length(totalset));
%                 idx = randsample(length(totalset), length(totalset), 1);
				
				bootstraps_stim(iboot, :) = totalset(idx(1:length(unique_stim)));
				% [f_cdfstim(iboot, :), x_cdfstim] = ecdf(bootstraps_stim(iboot, :));
				median_stim(iboot) = median(bootstraps_stim(iboot, :));
				
				bootstraps_nostim(iboot, :) = totalset(idx(length(unique_stim)+1:end));
				% [f_cdfnostim(iboot, :), x_cdfnostim] = ecdf(bootstraps_nostim(iboot, :));
				median_nostim(iboot) = median(bootstraps_nostim(iboot, :));
                
                median_diff(iboot) = median_nostim(iboot) - median_stim(iboot);
            end

            % Create axes object
			f = figure('Name', figName, 'NumberTitle', 'off');

			% Store the axes object
			if ~isfield(obj.Rsc, 'LooseFigures')
				figId = 1;
			else
				figId = length(obj.Rsc.LooseFigures) + 1;
			end
			obj.Rsc.LooseFigures(figId).Ax = gca;
			ax = obj.Rsc.LooseFigures(figId).Ax;
            
            
			histogram(ax, median_nostim, 'DisplayName', ['Median Bootstrap ',obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' no stim'])
			hold on
            histogram(ax, median_stim, 'DisplayName', ['Median Bootstrap ',obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' + stim'])
			
            
            %----------------
			lgd = legend(ax, 'Location', 'northoutside');
			lgd.Interpreter = 'none';
			lgd.Orientation = 'horizontal';
			ax.XLabel.String 	= 'Time (ms)';
			ax.YLabel.String 	= '# occurrences';
			title(ax, figName)
            
            
            
            
            figName2 = sprintf(['Median Bootstrap Difference, nboot = ', num2str(nboot)]);
            % Create axes object
			f = figure('Name', figName2, 'NumberTitle', 'off');

			% Store the axes object
			if ~isfield(obj.Rsc, 'LooseFigures')
				figId = 1;
			else
				figId = length(obj.Rsc.LooseFigures) + 1;
			end
			obj.Rsc.LooseFigures(figId).Ax = gca;
			ax = obj.Rsc.LooseFigures(figId).Ax;
            
            
			histogram(ax, median_diff, 'DisplayName', ['Median Bootstrap Time Difference ',obj.Arduino.EventMarkerNames{eventCodeOfInterest}, ' no stim'])
			
            
            %----------------
			lgd = legend(ax, 'Location', 'northoutside');
			lgd.Interpreter = 'none';
			lgd.Orientation = 'horizontal';
			ax.XLabel.String 	= 'Time (ms)';
			ax.YLabel.String 	= '# occurrences';
			title(ax, figName2)
%%            
            % get p value:
            
            real_diff = median(unique_nostim) - median(unique_stim);
            
            num_below = sum(median_diff < real_diff);
            num_above = sum(median_diff >= real_diff);
            
            p = num_above/(num_above + num_below)



        end





	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%








		function OnParamChanged(obj, ~, ~)
			obj.Rsc.ExperimentControl.UserData.Ctrl.Table_Params.Data = obj.Arduino.ParamValues';
		end

		function EnablePlotUpdate(obj, menu_plot)
			menu_plot.UserData.Menu_Enable.Checked = 'on';
			menu_plot.UserData.Menu_Disable.Checked = 'off';

			obj.UserData.UpdatePlot = true;
		end

		function DisablePlotUpdate(obj, menu_plot)
			menu_plot.UserData.Menu_Enable.Checked = 'off';
			menu_plot.UserData.Menu_Disable.Checked = 'on';

			obj.UserData.UpdatePlot = false;
		end

		function SavePlotSettings(obj)
			[filename, filepath] = uiputfile('plot_parameters.mat', 'Save plot settings to file');
			% Exit if no file selected
			if ~(ischar(filename) && ischar(filepath))
				return
			end

			ctrl = obj.Rsc.Monitor.UserData.Ctrl;

			plotSettings = {...
				ctrl.Table_Params_Raster.Data,...
				ctrl.Table_Events_Raster.Data,...
				ctrl.Popup_EventTrialStart_Raster.Value,...
				ctrl.Popup_EventZero_Raster.Value,...
				ctrl.Popup_EventOfInterest_Raster.Value,...
				ctrl.Popup_EventTrialStart_Hist.Value,...
				ctrl.Popup_EventZero_Hist.Value,...
				ctrl.Popup_EventOfInterest_Hist.Value,... % --- AH 5/14/18
                ctrl.Popup_EventSecondary_Hist.Value...
                % ---
			};

			save([filepath, filename], 'plotSettings')
		end

		function LoadPlotSettings(obj, errorMessage)
			if nargin < 2
				errorMessage = '';
			end
			% Display errorMessage prompt if called for
			if ~isempty(errorMessage)
				selection = questdlg(...
					errorMessage,...
					'Error',...
					'Yes','No','Yes'...
				);
				% Exit if the Grad Student says 'No'
				if strcmp(selection, 'No')
					return
				end
			end

			[filename, filepath] = uigetfile('*.mat', 'Load plot settings from file');
			% Exit if no file selected
			if ~(ischar(filename) && ischar(filepath))
				return
			end
			% Load file
			p = load([filepath, filename]);
			% If loaded file does not contain parameters
			if ~isfield(p, 'plotSettings')
				% Ask the Grad Student if he wants to select another file instead
				obj.LoadPlotSettings('The file you selected was not loaded because it does not contain plot settings. Select another file instead?')
			else
				% If all checks are good then do the deed
				ctrl = obj.Rsc.Monitor.UserData.Ctrl;
				ctrl.Table_Params_Raster.Data = p.plotSettings{1};
				ctrl.Table_Events_Raster.Data = p.plotSettings{2};
				ctrl.Popup_EventTrialStart_Raster.Value = p.plotSettings{3};
				ctrl.Popup_EventZero_Raster.Value = p.plotSettings{4};
				ctrl.Popup_EventOfInterest_Raster.Value = p.plotSettings{5};
				ctrl.Popup_EventTrialStart_Hist.Value = p.plotSettings{6};
				ctrl.Popup_EventZero_Hist.Value = p.plotSettings{7};
				ctrl.Popup_EventOfInterest_Hist.Value = p.plotSettings{8};
                % AH 5/14/18
                ctrl.Popup_EventSecondary_Hist.Value = p.plotSettings{9};
                %
			end
		end
	end

	%----------------------------------------------------
	%		Static methods
	%----------------------------------------------------
	methods (Static)
		%----------------------------------------------------
		%		Commmunicating with Arduino
		%----------------------------------------------------
		function arduinoPortName = QueryPort()
			
			serialInfo = instrhwinfo('serial');

			if isempty(serialInfo.AvailableSerialPorts)
				serialPorts = {'Nothing connected'};
			else
				serialPorts = serialInfo.AvailableSerialPorts;
			end

			[selection, online] = listdlg(...
				'ListString', serialPorts,...
				'SelectionMode', 'single',...
				'ListSize', [100, 75],...
				'PromptString', 'Select COM port',...
				'CancelString', 'Offline'...
			);

			if isempty(serialInfo.AvailableSerialPorts)
				arduinoPortName = '/offline';
				return
			end

			if online
				arduinoPortName = serialInfo.AvailableSerialPorts{selection};
			else
				arduinoPortName = '/offline';
			end	
		end

		function OnParamChangedViaGUI(~, evnt, arduino)
			% evnt (event data contains infomation on which elements were changed to what)
			changedParam = evnt.Indices(1);
			newValue = evnt.NewData;
			
			% Add new parameter to update queue
			arduino.UpdateParams_AddToQueue(changedParam, newValue)
			% Attempt to execute update queue now, if current state does not allow param update, the queue will be executed when we enter an appropriate state
			arduino.UpdateParams_Execute()
		end
		function ArduinoStart(~, ~, arduino)
			if ((~arduino.AutosaveEnabled) || isempty(arduino.ExperimentFileName))
				selection = questdlg(...
					'Autosave is disabled. Start experiment anyway?',...
					'Autosave',...
					'Save', 'Start Anyway', 'Cancel' ,'Save'...
				);
				switch selection
					case 'Save'
						arduino.SaveAsExperiment()
					case 'Start Anyway'
						warning('Autosave not enabled. Starting experiment anyway.')
					otherwise
						return
				end 
			end
			arduino.Start()
			fprintf('Started.\n')			
		end
		function ArduinoStop(~, ~, arduino)
			arduino.Stop()
			fprintf('Stopped.\n')
		end
		function ArduinoReset(~, ~, arduino)
			arduino.Reset()
			fprintf('Reset.\n')
		end
		function ArduinoClose(~, ~, obj)
			selection = questdlg(...
				'Close all windows and terminate connection with Arduino?',...
				'Close Window',...
				'Yes','No','Yes'...
			);
			switch selection
				case 'Yes'
					obj.Arduino.Close()
					delete(obj.Rsc.Monitor)
					delete(obj.Rsc.ExperimentControl)
					fprintf('Connection closed.\n')
				case 'No'
					return
			end
		end
		function ArduinoReconnect(~, ~, arduino)
			arduino.Reconnect()
		end
		function ArduinoSaveParameters(~, ~, arduino)
			arduino.SaveParameters()
		end
		function ArduinoLoadParameters(~, ~, arduino, table_params)
			if nargin < 4
				table_params = [];
			end
			arduino.LoadParameters(table_params, '')
		end
		function ArduinoSaveExperiment(~, ~, arduino)
			if isempty(arduino.ExperimentFileName)
				arduino.SaveAsExperiment()
			else
				arduino.SaveExperiment()
			end
		end
		function ArduinoSaveAsExperiment(~, ~, arduino)
			arduino.SaveAsExperiment()
		end
		function ArduinoLoadExperiment(~, ~, arduino)
			arduino.LoadExperiment()
		end

		%----------------------------------------------------
		%		Commmunicating with DAQ
		%----------------------------------------------------
		function NidaqStart(~, ~, nidaq)
			nidaq.Start()
		end

		function NidaqStop(~, ~, nidaq)
			nidaq.Stop()
		end


		%----------------------------------------------------
		%		Dialog Resize callbacks
		%----------------------------------------------------
		function OnMonitorDialogResized(~, ~)
			% Retrieve dialog object and axes to resize
			dlg = gcbo;
			ax = dlg.UserData.Ctrl.Ax;
			leftPanel = dlg.UserData.Ctrl.LeftPanel;
			rightPanel = dlg.UserData.Ctrl.RightPanel;
			trialCountText = dlg.UserData.Ctrl.TrialCountText;
			lastTrialResultText = dlg.UserData.Ctrl.LastTrialResultText;


			text_eventTrialStart_raster = dlg.UserData.Ctrl.Text_EventTrialStart_Raster;
			popup_eventTrialStart_raster = dlg.UserData.Ctrl.Popup_EventTrialStart_Raster;
			text_eventZero_raster = dlg.UserData.Ctrl.Text_EventZero_Raster;
			popup_eventZero_raster = dlg.UserData.Ctrl.Popup_EventZero_Raster;
			text_eventOfInterest_raster = dlg.UserData.Ctrl.Text_EventOfInterest_Raster;
			popup_eventOfInterest_raster = dlg.UserData.Ctrl.Popup_EventOfInterest_Raster;
			text_figureName_raster = dlg.UserData.Ctrl.Text_FigureName_Raster;
			edit_figureName_raster = dlg.UserData.Ctrl.Edit_FigureName_Raster;
			tabgrp_plot_raster = dlg.UserData.Ctrl.TabGrp_Plot_Raster;
			button_plot_raster = dlg.UserData.Ctrl.Button_Plot_Raster;

			text_eventTrialStart_hist = dlg.UserData.Ctrl.Text_EventTrialStart_Hist;
			popup_eventTrialStart_hist = dlg.UserData.Ctrl.Popup_EventTrialStart_Hist;
			text_eventZero_hist = dlg.UserData.Ctrl.Text_EventZero_Hist;
			popup_eventZero_hist = dlg.UserData.Ctrl.Popup_EventZero_Hist;
			text_eventOfInterest_hist = dlg.UserData.Ctrl.Text_EventOfInterest_Hist;
			popup_eventOfInterest_hist = dlg.UserData.Ctrl.Popup_EventOfInterest_Hist;
            % ----- AH 5/14/18
            text_eventSecondary_hist = dlg.UserData.Ctrl.Text_EventSecondary_Hist;
			popup_eventSecondary_hist = dlg.UserData.Ctrl.Popup_EventSecondary_Hist;
            % -----
            
			text_figureName_hist = dlg.UserData.Ctrl.Text_FigureName_Hist;
            %-----AH 11-2-17
            text_numBins_hist = dlg.UserData.Ctrl.Text_NumBins_Hist;
            edit_numBins_hist = dlg.UserData.Ctrl.Edit_NumBins_Hist;
            button_plot_cdf_hist = dlg.UserData.Ctrl.Button_Plot_CDF_Hist;

			%-----AH 5-30-18
			text_trialMin_hist = dlg.UserData.Ctrl.Text_TrialMin_Hist;
			edit_trialMin_hist = dlg.UserData.Ctrl.Edit_TrialMin_Hist;
			text_trialMax_hist = dlg.UserData.Ctrl.Text_TrialMax_Hist;
			edit_trialMax_hist = dlg.UserData.Ctrl.Edit_TrialMax_Hist;
            %-----------------------------------
			edit_figureName_hist = dlg.UserData.Ctrl.Edit_FigureName_Hist;
			button_plot_hist = dlg.UserData.Ctrl.Button_Plot_Hist;


			button_plot_bootstrap_cdf_analysis = dlg.UserData.Ctrl.Button_Plot_Bootstrap_CDF_Analysis;


			u = dlg.UserData;
			
			% Bar plot axes should have constant height.
			ax.Position = [...
				u.DlgMargin,...
				u.DlgMargin,...
				dlg.Position(3) - 2*u.DlgMargin,...
				u.BarHeight...
			];

			% Left and right panels extends in width and height to fill dialog.
			leftPanel.Position = [...
				u.DlgMargin,...
				u.DlgMargin + u.BarHeight + u.PanelSpacing,...
				max([0, u.LeftPanelWidthRatio*(dlg.Position(3) - 2*u.DlgMargin - u.PanelSpacing)]),...
				max([0, dlg.Position(4) - 2*u.DlgMargin - u.PanelSpacing - u.BarHeight])...
			];				
			rightPanel.Position = [...
				u.DlgMargin + leftPanel.Position(3) + u.PanelSpacing,...
				u.DlgMargin + u.BarHeight + u.PanelSpacing,...
				max([1, (1 - u.LeftPanelWidthRatio)*(dlg.Position(3) - 2*u.DlgMargin - u.PanelSpacing)]),...
				leftPanel.Position(4)...
			];

			% Trial count text should stay on top left of leftPanel
			trialCountText.Position = [...
				u.PanelMargin,...
				leftPanel.Position(4) - u.PanelMargin - 1.2*u.TextHeight,...
				max([0, leftPanel.Position(3) - 2*u.PanelMargin]),...
				u.TextHeight...
			];

			lastTrialResultText.Position = trialCountText.Position;
			lastTrialResultText.Position(2) = trialCountText.Position(2) - 2.4*u.TextHeight;
			lastTrialResultText.Position(4) = 2.4*trialCountText.Position(4);

			% Raster plot tab
			plotOptionWidth = (rightPanel.Position(3) - 4*u.PanelMargin)/3;
			text_eventTrialStart_raster.Position = [...
				u.PanelMargin,...
				rightPanel.Position(4) - u.PanelMargin - u.PanelMarginTop - text_eventTrialStart_raster.Extent(4),...
				plotOptionWidth,...
				text_eventTrialStart_raster.Extent(4)...
			];

			popup_eventTrialStart_raster.Position = text_eventTrialStart_raster.Position;
			popup_eventTrialStart_raster.Position(2) =...
				text_eventTrialStart_raster.Position(2) - text_eventTrialStart_raster.Position(4);

			text_eventZero_raster.Position = text_eventTrialStart_raster.Position;
			text_eventZero_raster.Position(1) =...
				text_eventTrialStart_raster.Position(1) + text_eventTrialStart_raster.Position(3) + u.PanelMargin;

			popup_eventZero_raster.Position = text_eventZero_raster.Position;
			popup_eventZero_raster.Position(2) =...
				text_eventZero_raster.Position(2) - text_eventZero_raster.Position(4);

			text_eventOfInterest_raster.Position = text_eventZero_raster.Position;
			text_eventOfInterest_raster.Position(1) =...
				text_eventZero_raster.Position(1) + text_eventZero_raster.Position(3) + u.PanelMargin;

			popup_eventOfInterest_raster.Position = text_eventOfInterest_raster.Position;
			popup_eventOfInterest_raster.Position(2) =...
				text_eventOfInterest_raster.Position(2) - text_eventOfInterest_raster.Position(4);

			tabgrp_plot_raster.Position = popup_eventTrialStart_raster.Position;
			tabgrp_plot_raster.Position(2:4) = [...
				u.PanelMargin,...
				max([1, 2*plotOptionWidth + u.PanelMargin]),...
				max([1, popup_eventTrialStart_raster.Position(2) - 2*u.PanelMargin]),...
			];

			text_figureName_raster.Position = popup_eventOfInterest_raster.Position;
			text_figureName_raster.Position(2) = popup_eventOfInterest_raster.Position(2) - u.PanelMargin - text_figureName_raster.Position(4);

			edit_figureName_raster.Position = text_figureName_raster.Position;
			edit_figureName_raster.Position(2) =...
				text_figureName_raster.Position(2) - text_figureName_raster.Position(4);

			button_plot_raster.Position = edit_figureName_raster.Position;
			button_plot_raster.Position([2, 4]) = [...
				tabgrp_plot_raster.Position(2),...
				2*text_eventZero_raster.Position(4)...
			];

			% Histogram tab Popup_EventSecondary_Hist
			text_eventTrialStart_hist.Position = text_eventTrialStart_raster.Position;
			popup_eventTrialStart_hist.Position = popup_eventTrialStart_raster.Position;
			text_eventZero_hist.Position = text_eventZero_raster.Position;
			popup_eventZero_hist.Position = popup_eventZero_raster.Position;
			text_eventOfInterest_hist.Position = text_eventOfInterest_raster.Position;
			popup_eventOfInterest_hist.Position = popup_eventOfInterest_raster.Position;
            
            
            text_figureName_hist.Position = text_figureName_raster.Position;
			edit_figureName_hist.Position = edit_figureName_raster.Position;
            % --- AH 5/14/18
            text_eventSecondary_hist.Position = text_figureName_hist.Position;
            text_eventSecondary_hist.Position(1) = text_figureName_hist.Position(1) - 2*text_figureName_hist.Position(3) - 2*u.PanelMargin;
			popup_eventSecondary_hist.Position = edit_figureName_raster.Position;
            popup_eventSecondary_hist.Position(1) = edit_figureName_raster.Position(1) - 2*edit_figureName_raster.Position(3) - 2*u.PanelMargin;
            % ---

            %---------AH 11-2-17
            text_numBins_hist.Position = text_figureName_hist.Position;
            text_numBins_hist.Position(1) = text_figureName_hist.Position(1) - text_figureName_hist.Position(3) - u.PanelMargin;
            edit_numBins_hist.Position = edit_figureName_raster.Position;
            edit_numBins_hist.Position(1) = edit_figureName_raster.Position(1) - edit_figureName_raster.Position(3) - u.PanelMargin;
%             text_numBins_hist.Position = text_figureName_raster.Position - [200,0,0,0];
% 			edit_numBins_hist.Position = edit_figureName_raster.Position - [200, 0,0,0];



			text_trialMin_hist.Position = text_figureName_hist.Position;
            edit_trialMin_hist.Position = edit_figureName_hist.Position;
            text_trialMin_hist.Position(1) = text_figureName_hist.Position(1) - text_figureName_hist.Position(3) - u.PanelMargin;
            edit_trialMin_hist.Position(1) = edit_figureName_hist.Position(1) - edit_figureName_hist.Position(3) - u.PanelMargin;
            text_trialMin_hist.Position(2) = text_trialMin_hist.Position(2) - 2*u.PanelMargin - edit_figureName_hist.Position(4);
            edit_trialMin_hist.Position(2) = edit_trialMin_hist.Position(2) - 2*u.PanelMargin - edit_figureName_hist.Position(4);
            
			text_trialMax_hist.Position = text_figureName_hist.Position;
            edit_trialMax_hist.Position = edit_figureName_hist.Position;
			text_trialMax_hist.Position(2) = text_trialMax_hist.Position(2) - 2*u.PanelMargin - edit_figureName_hist.Position(4);
            edit_trialMax_hist.Position(2) = edit_trialMax_hist.Position(2) - 2*u.PanelMargin - edit_figureName_hist.Position(4);



            %---------------------------
			button_plot_hist.Position = button_plot_raster.Position;
			button_plot_cdf_hist.Position = button_plot_raster.Position;
			button_plot_cdf_hist.Position(1) = button_plot_hist.Position(1) - button_plot_hist.Position(3) - u.PanelMargin;


			%------------------------------------- ANALYSIS TAB ------------------------------------
			button_plot_bootstrap_cdf_analysis.Position = text_eventTrialStart_raster.Position;
			
			

		end

		function OnPlotOptionsTabResized(table)
			tab = gcbo;
			table.Position = tab.Position;
			table.ColumnWidth = num2cell((table.Position(3) - 17)*[0.5, 0.5/3, 0.5/3, 0.5/3]);
		end

		%----------------------------------------------------
		%		Loose figure closed callback
		%----------------------------------------------------
		% Stop updating figure when we close it
		function OnLooseFigureClosed(src, ~, lh)
			delete(lh)
			delete(src)
		end

		%----------------------------------------------------
		%		Plot - Stacked Bar
		%----------------------------------------------------
		function bars = StackedBar(ax, data, names, colors)
			% Default params
			if nargin < 4
				colors = {[.2, .8, .2], [1 .2 .2], [.9 .2 .2], [.8 .2 .2], [.7 .2 .2]};
			end

			% Create a stacked horizontal bar plot
			data = reshape(data, 1, []);
			bars = barh(ax, [data; nan(size(data))], 'stack');
			
			% Remove whitespace and axis ticks
			ax.XLim = [0, sum(data)];
			ax.YLim = [1 - 0.5*bars(1).BarWidth, 1 + 0.5*bars(1).BarWidth];
			ax.XTickLabel = [];
			ax.YTickLabel = [];
			ax.XTick = [];
			ax.YTick = [];

			% Add labels and set color
			edges = [0, cumsum(data)];
			
			for iData = 1:length(data)
				percentage = round(data(iData)/sum(data) * 100);
				labelLong = sprintf('%s \n%dx\n(%d%%)', names{iData}, data(iData), percentage);
				labelMed = sprintf('''%d''\n%dx', iData, data(iData));
				labelShort = sprintf('''%d''', iData);
				center = (edges(iData) + edges(iData + 1))/2;

				t = text(ax, center, 1, labelLong,...
					'HorizontalAlignment', 'center',...
					'VerticalAlignment', 'middle',...
					'Interpreter', 'none'...
				);
				bars(iData).UserData.tLong = t;

				% Hide parts of the label if it's wider than the bar
				if (t.Extent(3) > data(iData))
					t.Visible = 'off';
					t = text(ax, center, 1, labelMed,...
						'HorizontalAlignment', 'center',...
						'VerticalAlignment', 'middle',...
						'Interpreter', 'none'...
					);
					bars(iData).UserData.tMed = t;
					if (t.Extent(3) > data(iData))
						t.Visible = 'off';
						t = text(ax, center, 1, labelShort,...
							'HorizontalAlignment', 'center',...
							'VerticalAlignment', 'middle',...
							'Interpreter', 'none'...
						);
						bars(iData).UserData.tShort = t;
						if (t.Extent(3) > data(iData))
							t.Visible = 'off';
						end						
					end
				end

				% Show bar text when clicked
				bars(iData).ButtonDownFcn = @MouseBehaviorInterface.OnStackedBarSingleClick;

				% Set bar color
				if iData <= length(colors)
					thisColor = colors{iData};
					bars(iData).FaceColor = thisColor;
				else
					% If color not defined, fade "R" from .7 to .2
					iOverflow = iData - length(colors);
					totalOverflow = length(data) - length(colors);

					decrement = 0.5/totalOverflow;
					r = 0.7 - decrement*iOverflow;
					bars(iData).FaceColor = [r .2 .2];
				end
			end
		end

		function OnStackedBarSingleClick(h, ~)
			% If text from another bar is force shown, hide it first
			t = findobj(gca, 'Tag', 'ForceShown');
			if ~isempty(t)
				t.Tag = '';
				t.Visible = 'off';
				t.BackgroundColor = 'none';
				t.EdgeColor = 'none';
			end

			% Force show text associated with bar clicked, unless it's already shown, in which case clicking again will hide it
			tLong = h.UserData.tLong;
			if strcmp(tLong.Visible, 'off')
				if ~isempty(t)
					if t == tLong
						return
					end
				end
				tLong.Tag = 'ForceShown';
				tLong.Visible = 'on';
				tLong.BackgroundColor = [1 1 .73];
				tLong.EdgeColor = 'k';
				uistack(tLong, 'top') % Bring to top
			end
		end
	end
end
back to top