Matlab: access files relative to working directory - matlab

I've noticed that most Matlab functions that acess files, e.g. load() resolve relative paths by finding some directory on the current path that contains files or directories matching these paths. E.g. calling load('foo/bar.m') will load /home/someuser/dir1/foo/bar.m over /home/someuser/dir2/foo/bar if the current working directory is /home/someuser/dir2 but /home/someuser/dir1 is on the search path.
I find this to be highly irritating and error-prone, how can I access files relative to the current working directory instead?

As you know, Matlab can resolve both relative and absolute paths. But my suggestions to handle your issue with less headaches:
At each (relevant/main) script ensure that your workspace is the scripts location with:
PATH.SCRIPT = fileparts(mfilename('fullpath'))
cd(PATH.SCRIPT)
Then, always call functions with absolute paths using:
load([PATH.SCRIPT, filesep, 'filename'])
or
load([PATH.SCRIPT, filesep, '..' , filesep, 'file_at_upper_dir_name'])
or
load([PATH.SCRIPT, filesep, 'subfolder' , filesep, 'file_at_lower_dir_name'])
If possible, try not messing too much with Matlab's default path, and at initialization of your workspace call restoredefaultpath. This reduces chances that there is a spurious folder in your path where name collisions can happen.
As others have mentioned, ./ or ['.', filesep] also provides with with the current folder.
As #CrisLuengo mentions, instead of filesep one might prefer to compose paths with fullfile, for instance: load(fullfile(PATH.SCRIPT, '..', 'file_at_upper_dir_name'))

Related

Add folder path based on run script matlab

Don't know why this isn't working anymore. Very simple. I have a script with a folder in the same path. The folder contains a series of m files for the script to work.
Originally I simply would use
addpath('.../utilities/);
when the script was first run. but recently I started receiving this error
Warning: Name is nonexistent or not a directory: ...\utilities
In path (line 109)
In addpath (line 88)
In Myrunningcode (line 101)
and I don't know why.
I fixed the problem by running the following code
p = mfilename('fullpath');
[filepath,~,~] = fileparts(p);
addpath([filepath,'/utilities/']);
At least I would like to know why this error occurred.
Here is my directory setup. I use windows 10 and matlab 2016a.
The issue is likely that your current directory (pwd) is not the same as the file location. The relative directory isn't relative to the current script, it's relative to pwd, hence why the mfilename workaround fixes your issue.
The first solution is your own, but you can do it in one line:
addpath( fullfile( fileparts( mfilename('fullpath') ), 'utilities' ) );
Then the quickest way to check if your files are already on the path is using which:
% Assuming that myFile.m is within the utilities folder, and not shadowed elsewhere.
% If utilities is on the path, which('myFile') will not be empty.
if isempty( which( 'myFile' ) )
addpath( fullfile( fileparts( mfilename('fullpath') ), 'utilities' ) );
end
Alternatively, you could pair the above check with a persistent flag variable, so you don't have to repeat the check if you re-enter the function.
Note that addpath isn't particularly slow, it's genpath you want to avoid if you were to add a load of subdirectories too.
Aside: It's good to use fullfile instead of manually concatenating with (OS dependent) file separators. Less room for error (e.g. double slashes) even if you're always using the same OS.
The correct way to include a relative folder is:
addpath('./utilities/');
with a single dot.
This has worked (and works) since the existence of relative folders, AFAIK, so you should be able to use it without fear of deprecation

MATLAB - Get current path and then use it to navigate to a different folder

I have a bunch of codes that are currently stored on my local machine. There are two folders, one called "Resources" and another called "src". There is one main script that needs to be run called "main.m" in "src" which calls files from "Resources".
If I copy this whole thing onto a new computer, the paths will change and MATLAB may not be able to find "Resources" anymore. I know that relative to "main.m", I need to go up one level and then into "Resources".
What is the best way of getting MATLAB to point to "Resources"?
I am currently trying along the lines of
P = mfilename('fullpath')
which gives the path for main.m. Now, I want to navigate from here, one folder up and then into "Resources". Or if there is a better way, please let me know.
Eventually, I want to extend it to work for multiple folders "Resources1", "Resources2" etc. so MATLAB needs to be able to navigate to the right folder.
You can get it like:
fullfile(fileparts(mfilename('fullpath')), '..', 'Resources');
Explanation:
mfilename('fullpath') will return the full path and name of the
M-file in which the call occurs, without the extension
fileparts will return the path of the passed file (only the containing directory)
fullfile will build the full directory specification from the folder names passed (Note: '..' always means the parent directory)
Based on this it is quite simple to write a function that gets the sibling directory of the directory containing the file:
getSiblingOfParentDirectory.m
function siblingDirPath = getSiblingOfParentDirectory(filepath, siblingDirName)
siblingDirPath = fullfile(fileparts(filepath), '..', siblingDirName);
end
then to use it in an M-file:
for i = 1:3
disp(getSiblingOfParentDirectory(mfilename('fullpath'), ['Resources', num2str(i)]));
end
Sample output:
D:\pathtest\Resources1
D:\pathtest\Resources2
D:\pathtest\Resources3
You can try the following:
ResourcesFolder = strrep(mfilename('fullpath'), 'src\main', 'Resources');
addpath(ResourcesFolder);
%%Your code here where you need those files
rmpath(ResourcesFolder);
Which is fully dependant on the names of your folders & files of course. Basically "addpath" enables you to access the files in the mentioned directory by adding it to the search path, and "rmpath" does the exact opposite.
Also, if you literally want to navigate to a folder present on one level up, you can execute the following:
cd ..\Resources
Which goes one level up, searches for the folder 'Resources', then changes the current directory to that folder .

Open multiple subfolders within a loop

I have a folder named "Photos" that is a subfolder of the current directory. Inside that folder, there are four subfolders with names "Order1", "Order2",
"Order3", "Order4". I am trying to open these subfolders using a loop.
The following code is not working.
for i=1:4
current_path=pwd;
cd(current_path');
cd('Photos\Order%d',i);
end
There are a lot issues going on here at the same time.
The primary issue is that you are changing directories each time through the loop but you're also getting the value of the current directory (pwd) each time. The directory doesn't automatically reset to where you were when it goes back to the top of the loop. I think you expect current_path to be the folder you started in and be the same for all iterations.
You need to use sprintf or something similar to create your "OrderN" folder names. cd doesn't know what to do with the format specifier you're trying to use.
You should always use fullfile when concatenating file paths. Period.
You should use absolute paths when possible to remove the dependence upon the current directory.
Do you really need to change the working directory? If you're trying to load files within these folders, please consider using absolute file paths to the files themselves rather than changing folders.
If you are going to do this this way, please be sure to reset the path back to where it was at the end of the loop. There is nothing worse than running code and ending up in a directory that is different than where you were when you called it.
To actually make your code work, we could do something like this. But given all of my points above (specifically, 4-5), I would strongly consider a different approach.
startpath = pwd;
for k = 1:4
folder = fullfile(startpath, 'Photos', sprintf('Order%d', k));
cd(folder)
end
% Set the current directory to what it was before we started
cd(startpath)

temporary remove all of the added paths in matlab

I have added a lot of paths to matlab and now I want to share my code, but I don't know exactly which function (in which path) I should add to my shared code. Each time I need to add a missing function and it is really bothering for me and the users who are using the code.
So, I would like to restore the matlab path to its original case. Is there any way to do this in matlab? I also want to keep a backup of my current added path in a .m file and use it later when I am done.
To restore the path to default value - http://www.mathworks.com/help/matlab/ref/restoredefaultpath.html
restoredefaultpath sets the search path to include only folders for
MathWorks® installed products. Use restoredefaultpath when you are
having problems with the search path.
restoredefaultpath; matlabrc sets the search path to include only
folders for MathWorks installed products and corrects search path
problems encountered during startup.
And to save the current path - http://www.mathworks.com/help/matlab/ref/savepath.html
savepath updates the MATLAB® search path for all users on the system
so that the path can be reused in a future session. savepath saves the
search path to the pathdef.m file that MATLAB located at startup, or
to the current folder if a pathdef.m file exists there.
Or you can just store path in variable p = path; and restore it later path(p);. If the path is saved into pathdef.m the call of pathdef returns the string that can be used to set the saved path.

Access data files from subfolder of current script directory

I have been working on MATLAB scripts.
Basically, I have a lot of functions and data files (collectively known as kernels):
I want to organize it a little bit.
The idea is
to create a subfolder named functions and save all functions in it.
Another kernels and save all data kernel files in it.
Later by adding these paths at runtime, all the scripts should be able to access these functions and kernels without giving the full path to them, i.e. The script should search it in the subfodlers too.
Applying addpath(genpath(pwd)); worked for functions but it couldn't access kernel files
e.g. What if I want to access file named naif0010.tls inside subfolder kernels.
It didn't work. Any suggestions.
Example:
% Add the current script directory and subfolders to search path
addpath(genpath(pwd));
% Load NASA Spice (mice) to the script here
% add MICE reference path to MATLAB
addpath('C:\Program Files\MATLAB\R2012b\extern\mice\src\mice');
addpath('C:\Program Files\MATLAB\R2012b\extern\mice\lib');
% Load leap second kernel
% If the leapsecond kernel is placed in script directory
% This file is present in pwd/kernel/naif0010.tls
cspice_furnsh('naif0010.tls');
There are a couple of things to keep in mind. First, your current working directory (pwd) is in the Matlab path by default, so you don't usually need to explicitly call addpath in order to use scripts, functions, or data files there.
Also, in many cases you can access files by providing a relative path rather than an absolute path. In your case, this would look like
cspice_furnsh('kernels/naif0010.tls')
I solved it with some work around which I know is not the correct answer but for now I can go ahead....
addpath(genpath(pwd));
% Basically just forming full path of the data file
leapSecondsFile = fullfile(pwd,'kernels','naif0010.tls');
cspice_furnsh(leapSecondsFile);
Still waiting for correct answer or suggestions :-)
Update:
Thanks nispio's comment above, The correct way is :
% Load current directory and subfolders
addpath(genpath(pwd)); % This is not necessary
cspice_furnsh('kernels\naif0010.tls');