Is there some way to delete only the variables generated in a matlab script at the end of the script and not any other variables of the workspace which are not generated in the script?
Note : The script is not a function.
Basically I want to do the following in one line
save abc.mat % saves the whole workspace
some_script % call the script
clear % deletes the variables created by the script along with the whole workspace
load abc.mat % again loads the whole earlier workspace
Use who before the script, then after the script; compare the results (setdiff) to detect variables created in the script, and then clear only those.
Variable names varsbefore, varsafter and varsnew in the following code should be guaranteed not to be used before the script or within the script.
varsbefore = who; %// get names of current variables (note 1)
some_script
varsafter = []; %// initiallize so that this variable is seen by next 'who'
varsnew = []; %// initiallize too.
varsafter = who; %// get names of all variables in 'varsbefore' plus variables
%// defined in the script, plus 'varsbefore', 'varsafter' and 'varsnew'
varsnew = setdiff(varsafter, varsbefore); %// variables defined in the script
%// plus 'varsbefore', 'varsafter' and 'varsnew'
clear(varsnew{:}) %// (note 2)
Notes about the code:
who used with an output argument returns a cell array of strings containing the names of all variables.
The functional form of clear is used, with input arguments in the form of a comma-separated list generated from a cell array.
You can create structures of variables in this way:
FOO_STRUCT.foo_var = var_from_abc.mat + rand(1);
FOO_STRUCT.foo_var2 = 10*log10(FOO_STRUCT.foo_var);
FOO_STRUCT.foo_var3 = FOO_STRUCT.foo_var2 + var_from_abc.mat;
The upper case part is the structure name. The lower case part is the variable.
You can use variables from the workspace in your script, make your work and at the end of the script you delete the entire structure
clear FOO_STRUCT
Related
new MATLAB user here so apologies if this seems like a silly question. I have the following list of variables (doubles) in my workspace:
E1_01Strain E1_06Strain E1_07Strain E1_08Strain E1_09Strain E1_10Strain
E1_01Stress E1_06Stress E1_07Stress E1_08Stress E1_09Stress E1_10Stress
These are lists of numbers. I would like to remove the last n elements from each variable. I can do it with the command
E1_01Strain = E1_01Strain(1:end-100)
but it's impractical because later I'm going to have to do it on many, many more similar variables. Therefore I wanted to write a function that accepts as inputs a list of the workspace variables (as in, I highlight the variables I want and drag and drop into the function input) and removes from each one n elements.
I understand that I can write a function like this:
function [X1, X2, X3, X4] = Remove_n_elements[n, X1, X2, X3, X4]
X1 = X1(1:end-100);
X2 = X2(1:end-100);
X3 = X3(1:end-100);
X4= X4(1:end-100);
end
but that would mean that I would have to change the number of inputs, outputs, and the lines of code in the function every time. I'm sure there's a better way to do it but I can't figure it out.
I keep thinking that there might be a way to do it by looping over all the inputs but I can't get it to work since (as far as I know) I need to create a list of the inputs and then the operation is performed only on the elements of that list, not the inputs themselves.
I was looking at Passing A Variable Number of Arguments into a Function and from that using inputParser from https://www.mathworks.com/help/matlab/matlab_prog/parse-function-inputs.html but since I'm new to MATLAB I'm not sure how to use it for my case.
I used the code provided by il_raffa for a bit but followed his advice and went back and reconsidered how the script functions. After some more digging I wrote the following script that does exactly what I need. This script extracts the columns des_cols from all .csv files in a folder and plots them together. It then makes another plot of the averages.
files = dir('*.csv'); % navigate to the folder that you want to run the script on in MATLAB
avgStress = [];
avgStrain = [];
set(groot, 'DefaultLegendInterpreter', 'none') % the names of my .csv files have underscores that I want to see in the legend, if you don't want this then comment this line
hold on; %comment this and hold off further down if you want separate plots for every .csv
for file = files'
csv = xlsread(file.name);
[n,s,r] = xlsread(file.name);
des_cols = {'Stress','Ext.1(Strain)'}; % type here the names of the columns you want to extract
colhdrs = s(2,:);
[~,ia] = intersect(colhdrs, des_cols);
colnrs = flipud(ia);
file.name = n(:, colnrs);
file.name = file.name(1:end-600,:); % I wanted to remove the last 600 rows but if you want them all, remove the -600
plot(file.name(:,2),file.name(:,1),'DisplayName',s{1,1});
avgStress = [avgStress file.name(1:1500,1)]; % calculates the average stress for the first 1500 points, you can change it to whatever you want
avgStrain = [avgStrain file.name(1:1500,2)];
end
ylabel({'Stress (MPa)'}); % y-axis label
xlabel({'Strain (%)'}); %x-axis label
title({'E_2'}); % title of the plot
legend('show');
hold off; % commment this if you want different plots for all .csv files
avgStress = mean(avgStress,2);
avgStrain = mean(avgStrain,2);
plot(avgStrain,avgStress);
This creates two plots, one with all the raw data and another with just the averages. I hope this helps anyone that might have a similar issue.
The best thing you can do is to review the architecture of your SW in order to avoid the needs to perform such operations on the Workspace variables.
That is: how those variables are created? Are these variables loaded from a ".mat" file? etc.
Anyway, in order to avoid using the eval function and given your situation, a possible approach could be:
identify the names of the varailbes by using the function who. You can specify in the call to who the root name of the varaibles and use the * as, for example, who('E1*'). Make sure it fit wiht the desired variables. You can also use regexp to better refine the selection of the variables
save these varaibles in a temporary .mat file: the name (including the path of the temporary file can be created with the function tempname
load the temporary .mat file: this will create a struct in the Workspace whose fields are the variables you want to midify
call the function to remove the undesired elements form the fields of the struct. The function have to return the updated struct
save the updated struct in the temporary file
load again the temporary file by specifying the option -struct which allows loading the content of the file as single varaibles
The function to remove the undesired elements can be made as follows:
get the nams of the struct's fields by using the function fieldnames
loop over the filed of the struct by using the dynamic field names property
remove the undesired elements form the fields
return the updated struct
A possible implementatin could be:
Code "before" the call to the function
% Get the names of the variables
list_var=who('E1*')
% Define the name of a temporary ".mat" file
tmp_file=tempname
% Save the variables in the temporary ".mat" file
save(tmp_file,list_var{:});
% Load the variables in a struct
sel_vars=load(tmp_file);
% Call the function to remove the elements
out_str=Remove_n_elements(8,sel_vars)
Function to remove the undesired elements
function sel_vars=Remove_n_elements(n,sel_vars)
% Get the names of the fields of the struct
var_names=fieldnames(sel_vars)
% Loop over the fields and remove the undesired elements
for i=1:length(var_names)
sel_vars.(var_names{i})=sel_vars.(var_names{i})(1:end-n)
end
Code "after" the call to the function
% Save the updated struct in the temporary ".mat" file
save(tmp_file,'-struct','out_str')
% Load the updated struct as separate variables
load(tmp_file)
I have three m files using the same variables and carrying out calculations on these variables. I have made an index m file in which i have declared all the variables and I can share the variables to the remaining m files using the variable names. My problem is that the variable names change too often and then I have to change the variable names in all these files manually. How can I make a Matlab script which can automatically get the variable names and value from the index m file and put these to the remaining m files.
I feel like you just need a little example from where you could go on so here we go:
First calling each value with a different variable name. if you have a lot of values of the same type a array is easier like:
A0=0; A1=6; A2=12 %each one with its own name
B=zeros(16,1); %create an array of 16 numbers
B(1)= 0; %1 is the first element of an array so care for A0
B(2)= 6;
B(8)= 12;
disp(B); % a lot of numbers and you can each address individually
disp(B(8)); %-> 12
you can put all that in your script and try it. Now to the function part. Your function can have input, output, neither or both. If you just want to create data you wont need an input but an output.
save this as myfile1.m:
function output = myfile1()
number=[3;5;6]; %same as number(1)=3;number(2)=5;number(3)=6
%all the names just stay in this function and the variable name is chosen in the script
output = number; %output is what the file will be
end
and this as myfile2.m
function output = myfile2(input)
input=input*2;%double all the numbers
%This will make an error if "input" is not an array with at least 3
%elements
input(3)=input(3)+2; %only input(3) + 2;
output = input;
end
and now try
B=myfile1() %B will become the output of myfile1
C=myfile2(B) %B is the input of myfile2 and C will become the output
save('exp.mat','C')
I hope this will get you started.
I have a "data.m" file that contains a handful of large arrays that I do not want in my main file. For all intents and purposes, they are in the form
a1 = [1,2,3]
a2 = [3,4,5]
How can I access a1 and a2 from another script? Or should I be putting these in a .mat file? If so, how do I do that?
Heres an easy way:
Inside data.m, output your arrays:
function [a1, a2] = data( )
...
end
You can access these arrays from your "main" function (e.g thefunc.m) like this:
function [ ] = thefunc( )
//say you want to store array a1 into a variable X, and array a2 into variable Y
[X, ~] = data;
[~, Y] = data;
end
Of course, thefunc.m and data.m should be in the same working directory.
If the values of the variables are constant, it would be better to store these in MAT files. Also, try to use functions instead of scripts unless it is necessary to use scripts. Scripts define global variables which could lead to inadvertently overwriting variables among many other issues.
Say we have data.m of Yours and a function foo.m that is about to use variables from there.
Turn the data.m into this form:
function[]=data() % defines a function with no output nor input
a1=[1 2 3];
b2='string';
%Your definitions and other code
save('DataFile.mat'); % save EVERY varible used in the code with it's name
Then in foo.m
function[]=foo()
load('DataFile.mat'); % Load all variables saved in DataFile.mat
disp(b2);
You can also prevent temporary variables to be saved with the mandatory ones by deleting them just before save command by clear temp1 temp2
If you want to save some variables, say a1 in one file and other in different file You can use save('DataFile.mat','a1')
If you want to load specific variables You can use load('DataFile.mat','b1')
I have a mat file, named save.mat, which has two variables. I want to clear the variables and add some other variables. How could I clear/add variables inside a mat file?
Best
You can do this two ways, either through the Matlab GUI or through a script.
To do this within Matlab itself, simply navigate to the .mat file's directory, run 'clear' within your command window (make sure to save your current workspace if you need that data!), the double-click the .mat file to load it. From here you can use the workspace to delete and add variables to your heart's content.
If you want to do this in a script, set up something like this:
clear
load('save'); % load the .mat file
clear foo bar % removes the variables 'foo' and 'bar'
baz = 3; % adds the variable 'baz'
save('save'); % save over the old .mat file
To add one o more variables to an existing .mat file, you can use the save function by specifying the option -append.
To remove one or more variables from an existing .mat file you can:
load the .mat file into a struct using the load function: each read variable will be stored in a field of the struct
remove from that struct the the field corresponding to the varaible you want to delete from the original mat file by using the rmfield function
save the struct using the save function by specifying the option -struct: this will allow save the fields of a structure as individual variables
This is an example of the implementation:
% Define some varaible to be saved
a=1
b=2
c=3
% Save the varaibles
save('add_del.mat','a','b','c')
% Define an additional variable
d=4
% Add the new varaible to the ".mat" file
save('add_del.mat','d','-append')
% Load the ".mat" file into a struct
str=load('add_del.mat')
% Delete the field corresponding to the varaible to delete
str=rmfield(str,'b')
% Save the fields of a structure as individual variables
save('add_del.mat','-struct','str')
Hope this helps.
Qapla'
#excaza has made a good recommendation, I think. To verify that the matfile command works as suggested, try the following:
filename = ('file.mat');
m = matfile(filename,'Writable',true);
y = 23;
m.y = y;
clear y
load(filename);
display(y);
y = 24;
m.y = y;
clear y
load(filename);
display(y);
Is it possible to create a wrapper around a function that has the exact same name as the original function?
This would be very useful in circumstances where the user wants to do some additional checks on input variables before they are passed on to the built in function How to interrupt MATLAB IDE when it hangs on displaying very large array?
Actually alternatively to slayton's answer you don't need to use openvar. If you define a function with the same name as a matlab function, it will shadow that function (i.e. be called instead).
To then avoid recursively calling your own function, you can call the original function from within the wrapper by using builtin.
e.g.
outputs = builtin(funcname, inputs..);
Simple example, named rand.m and in the matlab path:
function out = main(varargin)
disp('Test wrapping rand... calling rand now...');
out = builtin('rand', varargin{:});
Note that this only works for functions that are found by builtin. For those that are not, slayton's approach is likely necessary.
Yes this is possible but it requires a bit of hacking. It requires that you copy around some function handles.
Using the example provided in the question I will show how to wrap the function openvar in a user defined function that checks the size of the input variable and then allows the user to cancel any open operation for variables that are too large.
Additionally, this should work when the user double clicks a variable in the Workspace pane of the Matlab IDE.
We need to do three things.
Get a handle to the original openvar function
Define the wrapper function that calls openvar
Redirect the original openvar name to our new function.
Example Function
function openVarWrapper(x, vector)
maxVarSize = 10000;
%declare the global variable
persistent openVarHandle;
%if the variable is empty then make the link to the original openvar
if isempty(openVarHandle)
openVarHandle = #openvar;
end
%no variable name passed, call was to setup connection
if narargin==0
return;
end
%get a copy of the original variable to check its size
tmpVar = evalin('base', x);
%if the variable is big and the user doesn't click yes then return
if prod( size( tmpVar)) > maxVarSize
resp = questdlg(sprintf('Variable %s is very large, open anyway?', x));
if ~strcmp(resp, 'Yes')
return;
end
end
if ischar(x) && ~isempty(openVarHandle);
openVarHandle(x);
end
end
Once this function is defined then you simply need to execute a script that
Clears any variables named openvar
run the openVarWrapper script to setup the connection
point the original openVar to openVarWrapper
Example Script:
clear openvar;
openVarWrapper;
openvar = #openVarWrapper;
Finally when you want to clean everything up you can simply call:
clear openvar;
I prefer jmetz's approach using builtin() when it can be applied, because it is clean and to the point. Unfortunately, many many functions are not found by builtin().
I found that I was able to wrap a function using a combination of the which -all and cd commands. I suspect that this approach can be adapted to a wide variety of applications.
In my example case, I wanted to (temporarily) wrap the interp1 function so that I could check for NaN output values. (The interp1 function will, by default, return a NaN under some conditions, such as if a query point is larger than the largest sample point.) Here's what I came up with:
function Vq = interp1(varargin)
persistent interp1_builtin;
if (isempty(interp1_builtin)) % first call: handle not set
toolbox = 'polyfun';
% get a list of all known instances of the function, and then
% select the first such instance that contains the toolbox name
% in its path
which_list = which('interp1','-all');
for ii = 1:length(which_list)
if (strfind(which_list{ii}, [filesep, toolbox, filesep]))
base_path = fileparts(which_list{ii}); % path to the original function
current_path = pwd;
cd(base_path); % go to the original function's directory
interp1_builtin = #interp1; % create a function handle to the original function
cd(current_path); % go back to the working directory
break
end
end
end
Vq = interp1_builtin(varargin{:}); % call the original function
% test if the output was NaN, and print a message
if (any(isnan(Vq)))
dbstack;
disp('ERROR: interp1 returned a NaN');
keyboard
end
end
See also: How to use MATLAB toolbox function which has the same name of a user defined function