Matlab: renaming workspace elements from command window? - matlab

The GUI of Matlab allows me to rename any element in the workspace by right-clicking on the element and selecting the 'rename' option. Is it possible to do this from the command window as well?

These are things you can easily test for yourself, and you should do so. That is the best way to learn, to discover.
Regardless, the answer is no, you cannot change a variable name in that way from the command window. The command window is mainly for keyboard input only.
Edit: The question was apparently about doing that change by a command in the command window, not to be done via a mouse. (Why not tell us that up front?)
There is no explicit command that does such a rename. However, nothing stops you from writing it yourself. For example...
function renamevar(oldname,newname)
% renames a variable in the base workspace
% usage: renamevar oldname newname
% usage: renamevar('oldname','newname')
%
% renamevar is written to be used as a command, renaming a single
% variable to have a designated new name
%
% arguments: (input)
% oldname - character string - must be the name of an existing
% variable in the base matlab workspace.
%
% newname - character string - the new name of that variable
%
% Example:
% % change the name of a variable named "foo", into a new variable
% % with name "bahr". The original variable named "foo" will no
% % longer be in the matlab workspace.
%
% foo = 1:5;
% renamevar foo bahr
% test for errors
if nargin ~= 2
error('RENAMEVAR:nargin','Exactly two arguments are required')
elseif ~ischar(oldname) || ~ischar(newname)
error('RENAMEVAR:characterinput','Character input required - renamevar is a command')
end
teststr = ['exist(''',oldname,''',''var'')'];
result = evalin('base',teststr);
if result ~= 1
error('RENAMEVAR:doesnotexist', ...
['A variable named ''',oldname,''' does not exist in the base workspace'])
end
% create the new variable
str = [newname,' = ',oldname,';'];
try
evalin('base',str)
catch
error('RENAMEVAR:renamefailed','The rename failed')
end
% clear the original variable
str = ['clear ',oldname];
evalin('base',str)

You can rename variables in the command window as follows:
%# create a variable
a = 3;
%# rename a to b
b = a;clear('a');
EDIT
If you want to rename your variable to another variable stored in a string, you can use ASSIGNIN
a = 3;
newVarName = 'b';
assignin('base',newVarName,a);
clear('a') %# in case you want to get rid of the variable a

Related

Modify Simulink parameters from matlab workspace

I have a program that allows me to transfer all the block parameters from my simulink file to the matlab workspace which is this part :
function TransVar(SimulinkName) %program takes the simulink file name as argument
AE=find_system(SimulinkName); % AE is an array containing in the first cell the name of the
simulink file then the name
% of the blocks in this format : 'SimulinkName/blockName'
for i = 2:length(AE); % i start at 2 because first element of AE is the name of the file
A = strfind(AE{i,1},'/')%find the rank of the / in the string
newName = AE{i,1}(A+1:end);% Gives newName the name of the block
ParList(i-1,1) = {newName}; % Assign the block name to a cell array
assignin('base','ParList',ParList) % Export it to the matlab workspace
newName = regexprep(newName,'\W','');
newName = regexprep(newName,'[éè]','e');
newName = newName(isstrprop(newName,'alphanum'));
ParName(i-1,1) = {newName}; %change the name of the block so that it can be used as a field
assignin('base','ParName',ParName) % export it to the workspace
p = Simulink.Mask.get(AE{i,1});
if isempty(p)
Parametre.(newName) = [];
else
Parametre.(newName)=p.getWorkspaceVariables; %get the variables from the simulink block and
assign it ot the field of it's
%name in the structure parameter
assignin('base','Parametre',Parametre) % Export it to matlab workspace
end
end
Now all the variables have been exported to matlab workspace and can be modified by the user. what i want to do next is once these variables have been changed, I want to be able to change them in the simulink file for that i use this part :
Parametre = evalin('base','Parametre'); %Assign to parameter the struct parameter from the
matlab workspace
ParName = evalin('base','ParName');
ParList = evalin('base','ParList');
%Update the variables in the simulink file
for i = 1:length(fieldnames(Parametre))
if isempty(Parametre.(ParName{i,1})) %if the field has no variables then it will do nothing
and go to the next field
else
for b = 1:length(Parametre.(ParName{i,1}))
if length(Parametre.(ParName{i,1})(b).Value) >= 100 %if one of the variable in the fied has
more than 100 values it won't
% be updated as it is not a usefull one.
else
if isnumeric(get_param([SimulinkName '/' ParList{i,1}],Parametre.(ParName{i,1})(b).Name)) == 0
%if a variables isn't a number
%but a string when imported from simulink then it won't be updated
elseif isempty(Parametre.(ParName{i,1})(b).Value)
set_param([SimulinkName '/' ParList{i,1}],Parametre.(ParName{i,1})(b).Name,'[]')% if variable
is empty it gives the value
% []
save_system([SimulinkName])
else % if the variable in the field has a proper value it will update the one in the simulink
file then save the simulink file
set_param([SimulinkName '/' ParList{i,1}],Parametre.(ParName{i,1})(b).Name,(['['
num2str(Parametre.(ParName{i,1})(b).Value) ']' ]))
save_system([SimulinkName])
end
end
end
end
end
The problem that is faced is that there is no time for the user to actually change the variables in the workspace. And if i try to pause the function with an uiwait the variables cannot be modified in the workspace, you can see them but not acces them.

write wrapper for matlabs save function

I would to write a wrapper for the save function of matlab with predefined options (predefined version in my case to allow saving large files), i.e. something like this
save('parameters.mat', 'some', 'parameters', 'here', '-v.3');
should turn into this
save_large('parameters.mat', 'some', 'parameters', 'here');
where save_large is a wrapper for save with version set to '-v7.3':
function [ ] = save_large( filename, varargin )
%varargin to allow for multiple variable storing?
%what to write here to save all variables (declared as chars) stored in
%the workspace where 'save_large' was called with version set to '-v7.3'?
end
Because the variables won't exist in the scope of the function save_large, you will have to use evalin to get the variable from the "caller" workspace.
Using try we can also ensure that the variable exists in the caller workspace.
To get the correct variable names within your .mat file, we could either use the (discouraged) eval function, or the below method which assigns all of the variables to a struct, and then use the -struct flag in save.
function save_large(filename, varargin)
% Set up struct for saving
savestruct = struct();
for n = 1:numel(varargin)
% Test if variable exists in caller workspace
% Do this by trying to assign to struct
% Use parentheses for creating field equal to string from varargin
try savestruct.(varargin{n}) = evalin('caller', varargin{n});
% Successful assignment to struct, no action needed
catch
warning(['Could not find variable: ', varargin{n}]);
end
end
save(filename, '-struct', 'savestruct', '-v7.3');
end
Example
% Create dummy variables and save them
a = magic(3);
b = 'abc';
save_large test.mat a b;
% Clear workspace to get rid of a and b
clear a b
exist a var % false
exist b var % false
% Load from file
load test.mat
% a and b in workspace
exist a var % true
exist b var % true

Is it possible to change an anonymous function keeping the workspace?

What I would like to be able to do is programmatically change an anonymous function for example by changing all the plus signs to multiplication signs in the function. This example can in many cases this can be done as follows:
function f2 = changefunction(f1)
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = str2func(fs);
end
But consider the example
f = #(x) x+5;
a = 5;
g = #(x) x+a;
Both f and g will be anonymous functions that adds 5 to whatever you plug into it; however only f will be changed correctly by the changefunction function, whereas g will be changed into a function that will err on any input.
So my question is is it possible to extract the workspace from the function handle and retain it in the new function handle created? I need to do it programmatically and preferably without using the built-in function functions!
One naive implementation is to replace str2func with eval so you are not running into str2func's roadblock of not allowing access to local variables. We can use functions to obtain the workspace information for the input function handle.
For example:
a = 5;
f = #(x) x+a;
finfo = functions(f)
Yields:
finfo =
struct with fields:
function: '#(x)x+a'
type: 'anonymous'
file: 'X:\testcode-matlab\testcode.m'
workspace: {[1×1 struct]}
within_file_path: 'testcode'
Where workspace is a cell array containing a structure (come on MathWorks...) containing all of the variables in your function handle's namespace:
>> wspace = finfo.workspace{1}
wspace =
struct with fields:
a: 5
Using this functionality, the naive solution is to loop through the variables in this workspace, assign them in the namespace of changefunction, then use eval to generate the new function handle.
For example:
function f2 = changefunction_new(f1)
tmp = functions(f1);
workspacevars = tmp.workspace{1};
varnames = fieldnames(workspacevars);
for ii = 1:length(varnames)
evalstr = sprintf('%s = %d;', varnames{ii}, workspacevars.(varnames{ii}));
eval(evalstr);
end
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = eval(fs);
end
Here I'm assuming that the variables are going to be strictly numeric. You can add logic to check the class of the data to be generated if this is not always the case.
With this we have:
a = 5;
g = #(x) x+a;
test1 = changefunction(g);
test2 = changefunction_new(g);
>> g(1)
ans =
6
>> test1(1)
Undefined function or variable 'a'.
Error in testcode>#(x)x*a
>> test2(1)
ans =
5
All that being said, the best solution really is to just explicitly define your function handles. It may be a pain but it's much easier to understand and debug.
A few caveats:
Because eval arbitrarily executes all code passed to it, it can be a very dangerous function that must be used with care.
The documentation for functions warns against using it programmatically, so take care to check behavior as MATLAB versions change:
Use the functions function for querying and debugging purposes only.
Note: Do not use functions programmatically because its behavior could change in subsequent MATLAB® releases.
One possible way to do this is to save the function handle to a .mat file (using the -v7.3 flag so that it creates an easily-modifiable HDF5 file), modify the struct within the file that contains the workspace data for the anonymous function (using the HDF5 tools built into MATLAB), and then load the anonymous function again from the file.
Here is a little function which does exactly that (and it works for relatively simple variable types)
function result = modifyfunc(f, varname, value)
% modifyfunc - Modify the workspace of an anonymous function
%
% INPUTS:
% f: Function Handle, Anonymous function to modify
% varname: String, Name of the variable to modify
% value: Data to replace the specified variable
% If the value is a struct, recursively modify the function handle
if isstruct(value)
fields = fieldnames(value);
result = f;
% Modify each field separately
for k = 1:numel(fields)
% Append the fieldname to the variable name and modify
name = [varname, '.', fields{k}];
result = modifyfunc(result, name, value.(fields{k}));
end
return;
end
% Write the anonymous function to an HDF5 file
fname = tempname;
save(fname, 'f', '-mat', '-v7.3');
% Replace any "." in the variable name with "/" to construct the HDF5 path
varname = strrep(varname, '.' , '/');
% Now modify the data in the file
h5write(fname, ['/#refs#/e/' varname], value);
% Load the modified function handle from the file
result = load(fname, '-mat');
result = result.f;
% Remove the temporary file
delete(fname);
end
And you can use it like:
a = 1;
b = struct('field', 2);
f = #(x)disp(a + b.field + x);
f(10)
% 13
f2 = modifyfunc(f, 'a', 2);
f2(10)
% 14
f3 = modifyfunc(f2, 'b.field', 3);
f3(10)
% 15
b.field = 4;
f4 = modifyfunc(f3, 'b', b);
f4(10)
% 16
Some caveats include:
The replacement data must be the same size as the original data
This relies upon the format of the .mat file which for anonymous functions is completely undocumented so it could fail in future releases.
This currently doesn't work for variables in the function workspace that are cell arrays.

Remove first 2 letters from workspace variables

Let's say I have a .mat file and I know that each of the variables in it has XY in front of it (e.g. XYJanuary, XYFebruary, XYMarch and so on...) and I just want to remove the XY.
I have looked at this and tried to copy it but this adds the XY to my variable (XYXYJanuary, XYXYFebruay,...) but I want it to be just (January, Februay,...).
x= load('file.mat'); % Load into structure x
names=fieldnames(x); % names of the variables
for iname=1:length(names) % start the loop
x.(['XY', names{iname}]) = x.(names{iname}); % PROBLEM
x = rmfield(x, names{iname});
end
save ('newfile.mat', '-struct', 'x'); %save
x= load('file.mat'); % Load into structure x
names=fieldnames(x); % names of the variables
for iname=1:length(names) % start the loop
x.([names{iname}(3:end)]) = x.(names{iname}); % No more PROBLEM
x = rmfield(x, names{iname});
end
save ('newfile.mat', '-struct', 'x'); % save
You added the 'XY' to the LHS of your line, that makes it add it to the final solution. What I did is to chop off the first two entries, but keep the rest, hence the (3:end). This now works on a test case I created.

Edit multiple Matlab .m files using Matlab

I have some 50+ m files that worked in a previous driver version but are outdated for the newer driver version. As a result, I need to find and replace various variable or field names, and sometimes edit variable inputs for all these files.
For example, I'd like to find the line
src.aaaa = 100;
and replace it to:
src.bbbb = 100;
another example is to replace:
vid = videoinput('xxxx' ,1, 'yyy')
with:
vid = videoinput('kkkkkk' ,1, 'zzzz')
I've searched and found this discussion, that allows to search in multiple files, but not really edit or replace anything. I can handle matlab so I'm looking for a way to do that in matlab. Any ideas?
You could use the 'Find Files' dialog that you posted (Ctrl-Shift-F) to find each file you are looking for and then 'Find and Replace' (Ctrl+F) the specific lines you want to change.
As an example, find the file with src.aaaa = 100; using Ctrl+Shift+F. Then Ctrl+F and add the src.aaaa = 100; to the upper textbox and src.bbbb = 100; to the lower textbox.
From your post, it is unclear as to whether or not this would be feasible since I do not know how many different lines you would like to change in these m-files. How many are there? Are the m-files similar or are they all different?
If there are specific variables you are searching for, you could write a script to loop search through all the m-files using the dir function. Read the m-file into a string variable using fscanf. Then replace the variable in the string using strrep. And finally using fprintf to write to a new .m file with the corrected variables.
Refer to:
http://www.mathworks.com/help/matlab/ref/dir.html
http://www.mathworks.com/help/matlab/ref/fscanf.html
http://www.mathworks.com/help/matlab/ref/strrep.html
http://www.mathworks.com/help/matlab/ref/fprintf.html
A bit outside the box - but I would use the sed command - it does exactly what you want and is quick on it, but is you need to call it with system and build the command string. If you are on windows you may need to install it through msys or cygwin.
The m-File implementing Sekkou's suggestion:
clear all;
clc;
%% Parameter
directory = 'd:\xxx';
oldString = 'the old text';
newString = 'the new text';
regularExpression = '[\w]+\.m';
%% Determine files to manipulate
cd(directory)
allFilesInDirectory = dir;
%% Manipulieren der verweneten Dateien
disp('Manipulated Files:');
for idx = 1 : length(allFilesInDirectory)
if (~isempty ( regexp(allFilesInDirectory(idx).name, '[\w]+\.m','match') ))
disp(allFilesInDirectory(idx).name);
% Read and manipulate Text
fileIdRead = fopen(allFilesInDirectory(idx).name, 'r');
fileText = fscanf(fileIdRead,'%c');
fileTextNew = strrep(fileText, oldString, newString);
fclose(fileIdRead);
% Write Text
fileIdWrite = fopen(allFilesInDirectory(idx).name, 'w');
fprintf(fileIdWrite, '%c', fileTextNew);
fclose(fileIdWrite);
end
end
Ergodicity replied with some great code, but:
Some comments are in German rather than English
There is a general lack in commenting, which makes it hard to understand
I have attempted to fix these problems with the code below (I can't seem to get the code to display in MATLAB format very well using "language: lang-matlab", so paste it into MATLAB for easier reading):
close all;
clear all;
clc;
%% Parameters
% The directory in which to replace files. Currently this code does not modify files in
% sub-directories
directory = 'C:\Users\Name\Wonderful code folder';
% The string that will be replaced
oldString = sprintf('terrible mistake');
% The replacement string
newString = sprintf('all fixed now');
% The file name condition - what type of files will be examined
% It must contain any of the English character set (letters, numbers or underscore
% character i.e. a-zA-Z_0-9) and ends with a ".m" MATLAB extension (use \.txt for text files)
regularExpression = '[\w]+\.m';
%% Determine files to update, and update them as necessary
% Change the current directory to the user-specified one
cd(directory)
% Put the details of all files and folders in that current directory into a structure
allFilesInDirectory = dir;
% Initialise indexes for files that do and do not contain oldString
filesWithStringIndex = 1;
filesWithoutStringIndex = 1;
% For the number of files and folders in the directory
for idx = 1 : length(allFilesInDirectory)
% If the file name contains any of the English character set (letters, numbers or
% underscore character i.e. a-zA-Z_0-9) and ends with a ".m" filetype...
if (~isempty ( regexp(allFilesInDirectory(idx).name, '[\w]+\.m','match') ))
% Open the file for reading
fileIdRead = fopen(allFilesInDirectory(idx).name, 'r');
% Extract the text
fileText = fscanf(fileIdRead,'%c');
% Close the file
fclose(fileIdRead);
% Search for occurrences of oldString
occurrences = strfind(fileText,oldString);
% If an occurrence is found...
if ~isempty(occurrences)
% Replace any occurrences of oldString with newString
fileTextNew = strrep(fileText, oldString, newString);
% Open the file for writing
fileIdWrite = fopen(allFilesInDirectory(idx).name, 'w');
% Write the modified text
fprintf(fileIdWrite, '%c', fileTextNew);
% Close the file
fclose(fileIdWrite);
% Update the list of files that contained oldString
filesWithString{filesWithStringIndex} = allFilesInDirectory(idx).name;
% Update the index for files that contained oldString
filesWithStringIndex = filesWithStringIndex + 1;
else
% Update the list of files that did not contain oldString
filesWithoutString{filesWithoutStringIndex} = allFilesInDirectory(idx).name;
% Update the index for files that did not contain oldString
filesWithoutStringIndex = filesWithoutStringIndex + 1;
end
end
end
%% Display what files were changed, and what were not
% If the variable filesWithString exists in the workspace
if exist('filesWithString','var')
disp('Files that contained the target string that were updated:');
% Display their names
for i = 1:filesWithStringIndex-1, disp(filesWithString{i}); end
else
disp('No files contained the target string');
end
% Insert a clear line between lists
disp(' ');
% If the variable fileWithoutString exists in the workspace
if exist('filesWithoutString','var')
disp('Files that were not updated:');
% Display their names
for j = 1:filesWithoutStringIndex-1, disp(filesWithoutString{j}); end
else
disp('All files contained the target string.');
end