Run callback to change to current directory when opening files - matlab

When I open MATLAB, it defaults to open to /home/myUser. Whenever I open a file interactively (say I run Simulink and click "Open...") the dialog will start in /home/myUser. Then I might go into /home/myUser/myDir1/myDir2/ before clicking on myModel.mdl.
If I open a different Simulink file with the "Open..." dialog again, it'll kick me back to /home/myUser. Note that this is regardless of file, I'm just using Simulink as an example. I would like to keep it in /home/myUser/myDir1/myDir2, meaning I should be in the same directory as the last file I just opened (or saved).
Programatically, I would set up a callback to cd into whatever directory the file I chose was in after selecting the file using uigetfile. Is this possible to do just with MATLAB's own "Open" or "Save As" commands?

There is a wrapper for uigetfile that remembers the last director on the file exchange. You can get wrappers for the other file dialogs as well from the same author.
EDIT
How to overload the built-in uigetdir etc.
(1) Rename uigetdir2 to uigetdir, and make sure it's in a path that has precedence over the path for the built-in function (this should be the case by default).
(2) Use BUILTIN to ensure that the new function doesn't call itself.
(2) Since uigetdir is implemented as a .m-file, as opposed to being compiled (like sum), the builtin command doesn't work for it. Thus, open uigetdir, find the private function uigetdir_helper (which is private, so we can't call it), and finally uncover the java method (that turns out to have changed from R2011a to R2011b. Yay.). This allows us to finally overload uigetdir at the cost of having to parse the input ourselves.
Here's lines 37 to 67 from the modified uigetdir
%% Check passed arguments and load saved directory
% if start path is specified and not empty call uigetdir with arguments
% from user, if no arguments are passed or start path is empty load saved
% directory from mat file
% parse inputs
parserObj = inputParser;
parserObj.FunctionName = 'uigetdir';
parserObj.addOptional('startPath',[],#(x)exist(x,'dir'));
parserObj.addOptional('dialogTitle','Please choose directory',#ischar);
parserObj.parse(varargin{:});
inputList = parserObj.Results;
% create directory dialog instance - this has changed from 2011a to 2011b
if verLessThan('matlab','7.13')
dirdlg = UiDialog.UiDirDialog();
else
dirdlg = matlab.ui.internal.dialog.FolderChooser();
end
dirdlg.InitialPathName = inputList.startPath;
dirdlg.Title = inputList.dialogTitle;
if nargin > 0 && ~isempty(inputList.startPath)
% call dirdlg instead of uigetdir to avoid infinite recursion
dirdlg.show();
% if dirname empty, return 0 for uigetdir.
directory_name = dirdlg.SelectedFolder;
else
% set default dialog open directory to the present working directory
lastDir = pwd;
% load last data directory
if exist(lastDirMat, 'file') ~= 0
% lastDirMat mat file exists, load it
load('-mat', lastDirMat)
% check if lastDataDir variable exists and contains a valid path
if (exist('lastUsedDir', 'var') == 1) && ...
(exist(lastUsedDir, 'dir') == 7)
% set default dialog open directory
lastDir = lastUsedDir;
end
end
dirdlg.InitialPathName = lastDir;
% call dirdlg instead of uigetdir to avoid infinite recursion
dirdlg.show();
% if dirname empty, return 0 for uigetdir.
directory_name = dirdlg.SelectedFolder;
end

Related

Pausing MATLAB script until file is generated in directory

I have written a script which does the following: first it writes a text file to a specified directory, this text file is then called for a Post Processor via a PowerShell command which I also call in MATLAB in order to generate a result *.csv file. Lastly, the script formats the data in this generated *.csv file and plots the results.
The problem is that the script can only proceed once the given files have been placed in the directory - especially in the case of the *.csv file this may take 10-15 seconds. Currently I have simply added a sort of break point which prompts the user to wait, as follows:
fprintf("Check if *.csv is present in directory - then click 'Continue' \n")
keyboard;
I'm guessing there's a much better way to do this - ideally to run the script, automatically wait at a given point until a specified file is present in the directory, and then continue running the code.
How can I automate the check for existence of the *.csv file?
You can check if the file filename exist using isfile (post R2017b) like this:
if isfile(filename)
% File exists.
else
% File does not exist.
end
Pre R2017b you may use if exist(filename, 'file') == 2.
You may combine this with a loop the following way:
t_Start = tic; % Start stopwatch timer (to set a maximum time)
dt = 2; % Check every dt seconds (example dt = 2)
while isfile(filename) == false && toc(t_Start) < 60 % maximum 60 seconds
pause(dt);
time_counter = time_counter + dt;
end
% Continue with your code here.
I'm using a while lopp to check if the file exist, and wait 2 seconds between each check. There is no reason to check every millisecond, unless you're in a hurry. You can of course change this.
t_Start = tic; and toc(t_start) < 60 is a stopwatch that stops the loop after 60 seconds. Just using tic and toc < 60 works too, but that would reset a tic/toc call outside of the loop, if there are any.
Note that isfile(filename) == false is the same as ~isfile(filename), but can be easier to read for beginners.
You can use exist(). This function checks for the existence of a variable, function, file, folder etc. Putting this in an if statement should do the trick:
if exist('your_file.csv')
% Run your code
end

While running Compiled MatLab from console window, prompt returns immediately while app is still running

I have compiled my simple MatLab function so I can run it from a Windows console as a command line app. After I enter the command and its single argument, the prompt returns immediately even though the command is still running, as if running in the background.
Can someone tell me why this happens and how do I stop it? I'd like it to behave like a normal application and not return to the prompt until complete.
EDIT: Sorry I didn't post the code previously, I figured I was making a common mistake and would get a quick answer. Anyway, here it is.
It translates a .mat file to a .csv file and then runs another console command via "system" to perform a quick edit on the resulting .csv file. Several minutes of IO but not much else.
I've never compiled MatLab before so probably something simple, I hope.
function WriteMatToCSV( inFile, overWrite )
if ~exist(inFile, 'file')
fprintf('Error File not found: %s\n',inFile);
return;
end
overWriteExisting = 1;
if exist('overWrite','var')
overWriteExisting = overWrite;
end
% Change file extension
outFile = strrep( inFile, '.mat','.csv');
fprintf('In : %s\n',inFile);
fprintf('Out: %s\n',outFile);
% Overwrite if exists?
if exist(outFile, 'file')
if ~overWriteExisting
fprintf('Error File exists: %s\n',outFile);
return;
end
end
% Get variable name in the file
matObj = matfile(inFile);
info = whos(matObj);
name = info.name;
fprintf('Found variable: %s\n',name);
% Load the variable from the file
fprintf('Loading mat...\n');
load(inFile);
% Write the variable to .csv file
fprintf('Writing csv...\n');
export(eval(name),'File',outFile','Delimiter',',');
fprintf('Rewriting to remove MatLab bits...\n');
command = 'RewriteMatLabCSV';
command = [command ' ' outFile];
[status,cmdout] = system(command,'-echo');
fprintf(cmdout);
fprintf('Done\n');
end

Shortcut for saving file in current directory with correct name?

Is there any shortcut for saving an open file into the current directory with the current name? If I download multiple files with the same name they go into my Downloads folder and they end up with names like function (1).m instead of function.m.
At this point it's easy to open the file and see the contents by opening the file from my web browser- MATLAB sees the file extension and opens it. However, if it's a function, I have to Save As and move/rename the file before I'm able to use the code.
Edit: Since MATLAB insists that the file name be the same as the function name I'm hoping that there's a shortcut that saves an open file directly to the current MATLAB path and names it appropriately.
Since MATLAB convention is that the file name is the same as the function name I'm hoping that there's a shortcut that saves an open file directly to the current MATLAB path and names it according to the function name specified in the file.
You will need a directory which is always on the Matlab path. This can be achieved by adding one in the startup.m script.
Then you should save the below function savefunc.m to that directory, so you can always call it.
function savefunc(FuncName, Directory)
% Set directory if not given, default is working directory
if nargin < 2; Directory = pwd; end
% Get active document
ActiveDoc = matlab.desktop.editor.getActive;
% Set FuncName if not given, or if FuncName was empty string
if nargin < 1 || strcmp(FuncName, '');
% Get function name
FuncName = ActiveDoc.Text; % Entire text of document
% Could use indexing to only take first n characters,
% and not load entire string of long function into variable.
% FuncName = ActiveDoc.Text(1:min(numel(ActiveDoc.Text), n));
FuncName = strsplit(FuncName, '('); % Split on parenthesis
FuncName = FuncName{1}; % First item is "function [a,b,c] = myFunc"
FuncName = strsplit(FuncName, ' '); % Split on space (functions don't always have equals)
FuncName = strtrim(FuncName{end}); % Last item (without whitespace) is "myFunc"
end
% Save the file
saveAs(ActiveDoc, fullfile(Directory, [FuncName, '.m']));
end
Now, say you have just created the following Untitled.m:
function [a,b,c] = mytest()
a = 1; b = 1; c = 1;
end
The shortcut: just have Untitled.m open, and type into the Command Window
savefunc()
Untitled.m will be saved as mytest.m in the current working directory. Notice you can also pass a different function name and save-as directory if you wish, making this useful for other occasions.
You can pass an empty string as the FuncName if you want to specify the directory but use the auto-naming.
You could extend this using matlab.desktop.editor.getAll to get all open documents, then loop through them for saving.
For more info, type help matlab.desktop.editor in the Command Window, online documentation seems lacking.
matlab.desktop.editor: Programmatically access the MATLAB Editor to open, change, save, or close
documents.
Finally, note there is no need for a "Save successful" type message, since you will see the file name change, and also receive an error if it fails (from the saveAs docs):
If any error occurs during the saveAs operation, MATLAB throws a MATLAB:Editor:Document:SaveAsFailed exception. If the operation returns without an exception being thrown, assume that the operation succeeded.

Run Matlab function (*.m) in subdir / path of file stands in variable

I want to run a function "folder/test.m". This path stands in a variable "var_path". How do I run the function with parameters?
You can use system command.
For example:
sys_com = ['C:\path\to\matlab.exe ', var_path, ' ', parameter1, ' ', parameter2];
system(sys_com);
First line creates a command as a string (parameters should be strings). Second line executes that string.
you can either change dir to var_path and then run test as a regular funciton.
Alternatively, you can add var_path to your path and run test.
Matlab does not allow including function files (like in C/C++, for example). There are two possbilities to achieve something similar:
Change the folder during script execution
Change the search path to make the function file visible to the Matlab interpreter
Example for 1:
cur_dir = pwd; % save current directory
cd(var_path); % change to directory containing the function
test(a, b);
cd(pwd); % change back to original directory
This can have unwanted side effects of course, e.g. if your script relies on other files in the current directory or if you write to files.
Example for 2:
cur_path = path(); % save current path variable
addpath(var_path); % add function path to Matlab path
test(a, b);
setpath(cur_path); % restore original path variable

Launch a Matlab script based on a file extension

Hi I'm trying to create a matlab script in a way that it reads all files in a directory and launches a different command for every file extension.
I have:
teqc1.azi
teqc1.ele
teqc1.sn1
teqc2.azi
teqc****
what i need is that script reads the files and launches recursively the command:
`teqc1.azi -> plot_compact_2(teqc1.azi)`
`teqc1.ele -> plot_compact_2(teqc1.ele)`
`teqc1.sn1 -> plot_compact_2(teqc1.sn1)`
`teqc**** -> plot_compact_2(teqc****)`
This is what I've come up to right now:
function plot_teqc
d=dir('*'); % <- retrieve all names: file(s) and folder(s)
d=d(~[d.isdir]); % <- keep file name(s), only
d={d.name}.'; % <- file name(s)
nf=name(d);
for i=1:nf
plot_compact_2(d,'gps');
% type(d{i});
end
Thanks
Then you'll need the dir function to list the folder contents and the fileparts function to get the extensions.
You can also have a look at this question to see how to get a list of all files in a directory that match a certain mask.
So:
% get folder contents
filelist = dir('/path/to/directory');
% keep only files, subdirectories will be removed
filelist = {filelist([filelist.isdir] == 0).name};
% loop through files
for i=1:numel(filelist)
% call your function, give the full file path as parameter
plot_compact_2(fullfile('/path/to/directory', filelist{i}));
end