% Launch the MATLAB EASY console % Updated 240727 Bryan C Roessler to improve file operations and portability function varargout = EASYconsole(varargin) global easyDir global easySuffix global scansDir global easyResultsDir global easyResultsDirName global fotosResultsDir global figsResultsDir global pointMapsResultsDir global pointMapsFile global printResultsDir global matDir global matFile global drugMediaFile global masterPlateFile global mpdmFile global userName global srchRange global searchRangeFile % Initialize some variables from matlab easyPath=which(mfilename); [easyDir,easyFileName]=fileparts(easyPath); easyDir=fullfile(easyDir); [parentDir, ~]=fileparts(easyDir); parentDir=fullfile(parentDir); % ../easy/apps userName=getenv('USER'); dt=datetime; todayStr=char(dt, 'yyyyMMdd'); % This should match the parent workflow script demo=1; if demo disp('Running in demo mode'); disp('Initialized variables:'); whos; end fprintf('This script name: %s\n', easyFileName); % Set scansDir (project scans directory) intelligently if exist('PROJECT', 'var') && ~isempty(getenv('PROJECT')) scansDir=getenv('PROJECT'); fprintf('Using project path: %s from environment variable PROJECT\n', scansDir); disp('This usually indicates that we are in standalone mode'); elseif exist('PROJECT_SCANS_DIR', 'var') && ~isempty(getenv('PROJECT_SCANS_DIR')) scansDir=getenv('PROJECT_SCANS_DIR'); fprintf('Using scans directory: %s from environment variable PROJECT_SCANS_DIR\n', scansDir); disp('This usually indicates that we are in module mode'); else % TODO Lots of this is hardcoded logic, this TODO is just a reminder to change this block % when changing EASY and other variables in the parent script fprintf('Beginning parent scans directory search\n'); fprintf('This usually indicates that we are in stand-alone mode without PROJECT or PROJECT_SCANS_DIR environment variables\n'); dirsToScan={ fullfile(parentDir,'..', '..', 'scans'), fullfile(parentDir, '..', '..', 'ExpJobs'), fullfile('/mnt/data/scans'), fullfile('/mnt/data/ExpJobs'), fullfile(parentDir, '..', '..', 'templates', 'scans-demo') }; for d=dirsToScan if exist(d, 'dir') subDirs=dir(d); if ~isempty(subDirs) fprintf('Found a non-empty parent scans directory in our list: %s\n', d); fprintf('Scanning inside for a project scan directory\n'); [~, sortedIndices]=sort(datenum({dirs.date}), 'descend'); % sort by newest first sortedDirs=dirs{sortedIndices}; scansDir=sortedDirs{1}; fprintf('Selected newest project scans directory: %s\n', scansDir); end end end end % Sanity check and warning if exist('PROJECT_USER', 'var') && ~isempty(getenv('PROJECT_USER')) if ~equal(getenv('PROJECT_USER'), userName) disp("WARNING: PROJECT_USER does not match the current namespace"); end end % Allow module to override hardcoded default EASY directory if exist('EASY_DIR','var') && ~isempty(getenv('EASY_DIR')) EASY_DIR=fullfile(getenv('EASY_DIR')); if ~strcmp(easyDir, EASY_DIR) % sanity check disp("WARNING: EASY_DIR does not match this script's hardcoded EASY location"); disp("This is probably OK but if strange beahvior arises, we'll need to fix it in code"); easyDir=EASY_DIR; end fprintf('Using EASY script directory: %s from environment variable EASY_DIR\n', easyDir); else fprintf('Using EASY script directory: %s from hardcoded default\n', easyDir); end % If we don't have tan EASY_SUFFIX from the module, generate it from scansDir if exist('EASY_SUFFIX', 'var') && ~isempty(getenv('EASY_SUFFIX')) easySuffix=getenv('EASY_SUFFIX'); else % The following is a way to parse the project name from the scansDir [ ~, dirName]=fileparts(scansDir); parts=strsplit(dirName, '_'); scansDate=parts{1}; scansUserName=parts{2}; easySuffix=strjoin(parts(3:end), '_'); % Might as well check this too for fun if ~strcmp(userName, scansUserName) disp('WARNING: userName does not match scansUserName'); disp("This usually means that you are attempting to run an EASY analysis on another user's project data scans"); end % For happiness if strcmp(todayStr, scansDate) disp("Early bird gets the worm"); end end if (exist('EASY_RESULTS_DIR', 'var') && ~isempty(getenv('EASY_RESULTS_DIR'))) easyResultsDir=fullfile(getenv('EASY_RESULTS_DIR')); if exist(easyResultsDir, 'dir') fprintf('WARNING: EASY results dir %s already exists\n', easyResultsDir); disp('Files in this directory may be overwritten'); end fprintf('Using output directory: %s from environment variable EASY_RESULTS_DIR\n', easyResultsDir); else easyResultsDirName=strcat('Results_',todayStr,'_',userName,'_',easySuffix); easyResultsDir=fullfile(scansDir,easyResultsDirName); if exist(easyResultsDir, 'dir') fprintf('WARNING: EASY results dir %s already exists\n', easyResultsDir); disp('Files in this directory may be overwritten') fprintf('Using output directory: %s\n', easyResultsDir); end end if exist('MASTER_PLATE_FILE', 'var') && ~isempty(getenv('MASTER_PLATE_FILE')) masterPlateFile=fullfile(getenv('MASTER_PLATE_FILE')); fprintf('Using drug media file: %s from environment variable MASTER_PLATE_FILE\n', masterPlateFile); else % Try to find MasterPlate_ file on our own mp=fullfile(scansDir,'MasterPlateFiles',strcat('MasterPlate_', easySuffix,'.xlsx')); if exist(mp, 'file') masterPlateFile=mp; fprintf('Using drug media file: %s from internal logic\n', masterPlateFile); else fprintf('WARNING: Have you created a MasterPlate_ file in %s/MasterPlateFiles/?\n', scansDir); end end if exist('DRUG_MEDIA_FILE', 'var') && ~isempty(getenv('DRUG_MEDIA_FILE')) drugMediaFile=fullfile(getenv('DRUG_MEDIA_FILE')); fprintf('Using drug media file: %s from environment variable DRUG_MEDIA_FILE\n', drugMediaFile); else % Try to find MasterPlate_ file on our own dm=fullfile(scansDir,'MasterPlateFiles',strcat('DrugMedia_', easySuffix,'.xlsx')); if exist(mp, 'file') drugMediaFile=dm; fprintf('Using drug media file: %s from internal logic\n', drugMediaFile); else fprintf('WARNING: Have you created a DrugMedia_ file in %s/MasterPlateFiles/?\n', scansDir); end end matDir=fullfile(easyResultsDir,'matResults'); if ~exist(matDir, 'dir') mkdir(matDir); end matFile=fullfile(matDir,strcat(easyResultsDirName,'.mat')); % Pulled these out of par4GblFnc8c printResultsDir=fullfile(easyResultsDir,'PrintResults'); fotosResultsDir=fullfile(easyResultsDir,'Fotos'); figsResultsDir=fullfile(easyResultsDir,'figs'); pointMapsResultsDir=fullfile(easyResultsDir,'PTmats'); pointMapsFile=fullfile(pointMapsResultsDir,'NImParameters.mat'); oldPointMapsFile=fullfile(pointMapsResultsDir,'ImParameters.mat'); searchRangeFile=fullfile(fotosResultsDir,'CSearchRange.mat'); mpdmFile=fullfile(matDir,'MPDM.mat'); % Decent time to print some helpful vars if demo disp('Vars at end of main loop:') whos; end % This can be removed, I think it should add the previous search range? % Might be nice feature but can remove if it causes issues % We are using searchRangeNum to hold old CSrchRange value(s) if exist(searchRangeFile, 'file') searchRangeNum=load(searchRangeFile); end % Add easyDir to the MATLAB path % I have not idea if this is necessary or works but theoretically should % reduce directory scoping issues when calling scripts w/o a path addpath(easyDir); % GUI interface design gui_Singleton=1; gui_State=struct( 'gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @EASYconsole_OpeningFcn, ... 'gui_OutputFcn', @EASYconsole_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback=str2func(varargin{1}); end if nargout [varargout{1:nargout}]=gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end end % GUI % Easyconcole_OpeningFcn executes just before the EASYconsole GUI is made visible. % This function has no output args, see OutputFcn. % hObject--handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles--structure with handles and user data (see GUIDATA) % varargin--input arguments to EASYconsole (see VARARGIN) function EASYconsole_OpeningFcn(hObject, ~, handles, varargin) global fhconsole global scansDir % Choose default command line output for EASYconsole handles.output=hObject; % Update handles structure guidata(hObject, handles); %Figure header, Toolbar, etc. Setup fhconsole=gcf; set(fhconsole,'Toolbar','none'); fhconsole=gcf; % Pulled this out of the opening function % Seems better to wait until we have our vars set though? if exist('scansDir','var') && ~isempty(scansDir) set(fhconsole,'Name', sprintf('EASYconsole - %s', scansDir)); else set(fhconsole,'Name','EASYconsole - No Active Experiment.') end end % EASYconsole output % Outputs from this function are returned to the command line. % varargout--cell array for returning output args (see VARARGOUT); % hObject--handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles--structure with handles and user data (see GUIDATA) function varargout = EASYconsole_OutputFcn(~, ~, handles) % Get default command line output from handles structure varargout{1}=handles.output; end %% CONSOLE BUTTON INTERFACES %% % File Button Interface function FileMenu_Callback(~, ~, ~) %returnStartDir end % Load Experiment Button Interface function LoadExp_Callback(~, ~, ~) %returnStartDir end % New Experiment Button Interface function NewExpDat_Callback(~, ~, ~) global matDir global matFile global easyResultsDir global easyResultsDirName global fhconsole global scan global userName % Create a new experiment try questdlg('\fontsize{20} NAME the file and NAVIGATE to the directory with the image folders.','File Creation','OK', struct('Default','OK','Interpreter','tex')); [inputFile,inputPath]=uiputfile('.mat'); inputFileName=strrep(inputFile,'.mat',''); easyResultsDirName=strcat('Results_',todayStr,'_',userName,'_',inputFileName); % Set paths scansDir=fullfile(inputPath); easyResultsDir=fullfile(scansDir,easyResultsDirName); matDir=fullfile(easyResultsDir,'matResults'); matFile=fullfile(matDir,strcat(todayStr,'_',userName,'_',inputFile)); %***Added for 'parfor global' to preallocate 'scan' structure 20-0123***** nlist=dir(fullfile(scansDir,'*')); nnn=0; for n=1:size(nlist,1) if (~isempty(str2num(nlist(n).name))) nnn=nnn+1; PnumLst(nnn)= (str2num(nlist(n).name)); sl(nnn,1)={(nlist(n).name)}; end end scanSize=size(sl,1); scanMax=max(str2double(sl)); clear scan; scan(scanMax)=struct(); % changed for parfor global 20_0118 save(matFile,'scan') % create supporting dirs % this is also in the workflow script but here for standalone mode dirs={'PrintResults', 'CFfigs', 'Fotos', 'Fotos/BkUp'}; for i=1:length(dirs) d=dirs{i}; if ~exist(fullfile(easyResultsDir, d), 'dir') mkdir(fullfile(easyResultsDir, d)); end end % templateDirs are stored in the easy template directory templates={'figs', 'PTmats'}; for i=1:length(templates) d=dirs{i}; if ~exist(fullfile(easyResultsDir, d), 'dir') copyfile((fullfile(easyDir,d)), (fullfile(easyResultsDir,d))); end end clear sbdg % reduce possible retention of a previous job sdbg sbdg= cell(1,scanMax); save((fullfile(easyResultsDir,'Fotos','Nbdg')),'sbdg'); catch ME fprintf('ERROR: %s\n', ME.message); end % set the title for fhconsole depending on existence if exist('easyResultsDir','var')&&~isempty(easyResultsDir) set(fhconsole,'Name',sprintf('EASYconsole - %s', easyResultsDir)); else set(fhconsole,'Name','EASYconsole - Master Plate directory not selected.'); end end % Load a previous experiment function LoadDatFile_Callback(~, ~, ~) global matDir global matFile global easyResultsDir global easyPath global fhconsole try questdlg('Load results .mat from ../ExpJobs/YourJob/Results/matResults/','File Creation','OK', struct('Default','OK','Interpreter','tex')); [inputFile,inputPath]=uigetfile('.mat','Open Experiment folder and data storage .mat file name','MultiSelect','off'); matDir=fullfile(inputPath); matFile=fullfile(inputPath,inputFile); load(matFile); easyResultsDir=fullfile(matDir,'..'); scansDir=fullfile(matDir,'..', '..'); point % TODO this is pretty hacky and needs something more explicit if isfolder(fullfile(matDir, '..','..','1')) % If Inovation Vrobot Then try exist(pointMapsFile, 'file') load(pointMapsFile); catch try load(fullfile(easyPath,'NImParameters.mat')); % hardcoded default catch disp("Could not load the NImParameters.mat file") end end else % If Epson 10Plate Scans Then> if exist(fullfile(pointMapsResultsDir,'ImParameters.mat'), 'file') load(fullfile(pointMapsResultsDir,'ImParameters.mat')); else try load(fullfile(easyPath,'ImParameters.mat')); catch disp("Could not load the ImParameters.mat file"); end end else disp('WARNING: cannot find project scans'); end bkupDir=fullfile(matDir,'BkUp'); if ~exist(bkupDir, 'dir') mkkdir(bkupDir); end % Create supporting dirs dirs={'PrintResults', 'figs', 'CFfigs', 'PTmats', 'Fotos'}; for i=1:length(dirs) d=dirs{i}; if ~exist(fullfile(easyResultsDir, d), 'dir') mkdir(fullfile(easyResultsDir, d)); end end catch end clear scan if exist('easyResultsDir','var') && ~isempty(easyResultsDir) fhconsole=gcf; set(fhconsole,'Name',sprintf('EASYconsole - %s', easyResultsDir)); else set(fhconsole,'Name','EASYconsole - Exp. Analysis NOT selected.'); end end % Callbacks % 'Run' in the dropdown menu function run_Callback(~, ~, ~) end function runPlateMapPintool_Callback(~, ~, ~) try NImapPT catch EASYconsole end end function NImCFcombo_Callback(~, ~, ~) try par4Gbl_Main8c EASYconsole catch EASYconsole end end function runPlateImAnal_Callback(~, ~, ~) try NImStartupOnly catch EASYconsole end end function PlateCFit_Callback(~, ~, ~) % global matFile % TODO BCR not sure if needed try NCstart catch EASYconsole end end function GenPrintouts_Callback(~, ~, ~) end function uploadExcelMP2DB_Callback(~, ~, ~) end function runDMPexcel_Callback(~, ~, ~) try DMPexcel2mat catch EASYconsole end end function runResults_DBcombo_Callback(~, ~, ~) try DgenResults %similar but semicolons removed to restore so cmdLine display info. %Dgen241010qhtcp %par4global -convert 1x1cell of 384cells to be like previous 1x384 cells CFparameter catch ME fprintf('Error in DgenResults: %s\n', ME.message); EASYconsole end end function Tools_Callback(~, ~, ~) end function runOverlayPlots_Callback(~, ~, ~) try DoverlayPlots2 EASYconsole catch EASYconsole end end function runFotoStrip_Callback(~, ~, ~) try F_NImStartup_CentCir EASYconsole catch EASYconsole end end function runDisplayFig_Callback(~, ~, ~) try UfigDisplay catch EASYconsole end end function runViewParameters_Callback(~, ~, ~) try catch EASYconsole end end function QkviewN_Callback(~, ~, ~) try QkviewImages catch EASYconsole end end function CFdisplay_Callback(~, ~, ~) try NCsingleDisplay EASYconsole catch EASYconsole end end