Use of cellfun and save functions to export specific variables fails - matlab

I have a strange error. The following is a Minimal, Complete, and Verifiable example of my problem:
ba = 1;
bb = 2;
bc = 3;
whos
% Get variable names
varnames = who('b*')
% Definition of the filename
filename = 'bVariables';
cellfun(#(x) display( x ), varnames);
cellfun(#(x) save( filename, x, '-append' ), varnames);
First I declare variables starting with letter b. Then I use the who command to get the variable names that start with letter b (assume that I don't know them before running the script). The names are returned as a cell array of strings (char vectors).
I then try to save each variable individually to the given filename with save defined as an anonymous function used by cellfun.
Here is the output I get from the above MCV:
varnames =
'ba'
'bb'
'bc'
x =
ba
x =
bb
x =
bc
Error using save
Variable 'ba' not found.
Error in #(x)save(filename,x,'-append')
This is really strange as the variables really do exist in workspace.
Am I using cellfun wrong?
Is it probably related to the use of an anonymous function and the visibility of variables?

It seems that it is because of the anonymous function and the scope of the variables. I can reproduce the error simply with eval function:
ba = 1;
bb = 2;
bc = 3;
whos
% Get variable names
varnames = who('b*')
cellfun(#(x) eval( x ), varnames);
However you can simply do it by doing this:
save(filename,varnames{:})
This outputs the content of the cell as a comma separated list handled by the save function. You can also add the '-append' at the end to make it append to that file: save(filename,varnames{:},'-append')

Related

set 'help' for matlab anonymous functions

I have a long anonymous function, and I wondered whether the help output can be modified (easily):
>> myfunc=#(x) x; %example anonymous function
>> help myfunc
myfunc is a variable of type function_handle.
I know long anonymous functions might be a rather unusual thing- nevertheless: can this be achieved, maybe with undocumented functions, for only as long as the function handle exists?
Edit: commenter asked for a use-case: I read up on anoynmous functions with muiltiple outputs (here Lorem on the art of matlab) such as
fmeanVar = #(x) deal(mean(x), var(x));
%a long example function to split a cell array containing 3D matrices into two cell arrays
myfunc=#(x,c) deal(cellfun(#(d) d(:,:,1:c:end),x),cellfun(#(d) d(:,:,setxor(1:c:end,1:end)),x));
And I want to make sure I remember what the second output argument is, later in time, you know... because humans forget stuff
You can create your own anonymous function handling class which would mimic this functionality, shadowing the help function for this object type only.
I've written the class below, but will show usage first, it simply requires having the class on your path and slightly adapting the way you declare anonymous functions:
We can override the subsref function for this class type also, then you can call the function handle directly using () syntax, rather than indexing into a structure as suggested by Nicky's answer.
Note that you have to pass the handle in, not the function name (i.e. help(f) or f.help, not help f or help('f')). You'd have to fully shadow the help function to get around this limitation, which I wouldn't really endorse!
Usage
>> f = anon( #() disp( 'Hi!' ), 'This function displays "Hi!"' );
>> help( f )
Input is a value of type function_handle.
This function displays "Hi!"
>> f()
Hi!
>> f = anon( #(x) x + 10, 'Adds 10 to the input' );
>> help( f )
Input is a value of type function_handle.
Adds 10 to the input
>> f(15:17)
ans =
[ 25, 26, 27 ]
>> f.func = #(x) x + 15;
>> f.helpStr = 'Adds 15 to the input'
>> f(15:17)
ans =
[ 30 31 32 ]
Default function handle help is preserved if not specified
>> f = anon( #(x) x + 10 );
>> help( f )
Input is a value of type function_handle.
Class code
The class could use some extra input checking etc, but works in principle!
classdef anon < handle
properties ( Access = public )
helpStr % String to display on help( obj )
func % Function handle (meant for anonymouse functions
end
methods
function obj = anon( func, helpStr )
assert( isa( func, 'function_handle' ) ); % Input check
obj.func = func;
if nargin > 1
obj.helpStr = helpStr; % Set help string
end
end
function help( obj )
h = help( obj.func ); % Normal behaviour.
if ~isempty( obj.helpStr )
% Custom string (does nothing if empty)
fprintf( '%s%s\n', h, obj.helpStr );
else
disp( h );
end
end
function varargout = subsref( obj, s )
% Need to override the subsref behaviour to enable default
% function calling behaviour!
switch s(1).type
case '()'
[varargout{1:nargout}] = obj.func( s(1).subs{:} );
otherwise
[varargout{1:nargout}] = builtin('subsref', obj, s);
end
end
end
end
The problem is that when you invoke help it re-reads the file. When you create an anonymous function with
f = #(x) x %Sample text
then it ignores %Sample text and is thus gone. One solution is to turn it into a struct, where one field is the function and the other the help. E.g. something like
fMeanVar.fct = #(x) [mean(x), var(x)];
fMeanVar.help = "Second output is the variance"
thus when you want to use the function you call
fMeanVar.fct([1,2,3,4])
and if you forget the usage you can simply call
fMeanVar.help
According to Matlab documentation for help, it's not possible:
help name displays the help text for the functionality specified by name, such as a function, method, class, toolbox, or variable.
Not for handle nor symbolic.

Printing current code line and specific variables' names, types and dimensions

To debug my Octave/MATLAB code, I want to be able to do something like:
A = magic(3);
b = 42;
describe(#A, #b);
and get output like:
filename.m line 3: "A" is a 3x3 matrix
filename.m line 3: "b" is a scalar of value: 42
For multiple variables, how can I print the:
Calling function's file and line
Name
Type
Dimensions
Overview
In this answer I list 3 subtly different versions of the function describe.
Takes any number of variables and creates an output string and displays it using fpritnf
Takes any number of variables and creates an output cell array and displays it using disp
Takes any number of variable names and creates an output string as in 1. This has the advantage of being able to deal with indexing like describe('myvar{1}').
Main functionality description and version 1.
You can use various standard functions to get the info you want:
varargin to accept variable number of input variables
dbstack to get the file name / current line
inputname to get the names of inputs as they are passed into describe
fprintf to display with new line characters
varargout to optionally return or display the result
So create your describe function like so:
function varargout = describe(varargin)
% varargin used to accomodate variable number of inputs
% By default, at least get functions stack (even if no variables are passed in)
st = dbstack;
% Convert cell output to string (excluding describe.m itself)
outstring = '';
% Loop backwards for more logical order (most recent last)
for ii = size(st, 1):-1:2
% new line character at end only works with fprintf, not disp
outstring = [outstring, st(ii).file, ' > ', st(ii).name, ...
', line ', num2str(st(ii).line), '\n'];
end
% Loop over variables and get info
for n = 1:nargin
% Use inputname to get name of input variables
outstring = [outstring, '"', inputname(n), '" is a ', ...
class(varargin{n}), ' of size ', mat2str(size(varargin{n})), '\n'];
end
% If output variable is requested then assign to output variable
% If not, just display output string to command window
if nargout
varargout{1} = outstring;
else
fprintf(outstring)
end
end
The only tweaking required here really is formatting, all of your requested functionality is here and hopefully enough flexibility is built in to handle your needs.
Example output:
% In myMainFunction.m, in the subfunction mySubFunction
% Could store output using 'd = describe(A,B);' and use 'fprintf' later
describe(A, B);
% In the command window
myMainFunction.m > myMainFunction, line 3
myMainFunction.m > mySubFunction, line 39
"A" is a double of size [1 3]
"B" is a double of size [1 5 9 7]
Tested in Matlab R2015b, all functions listed above existed since before R2006a according to documentation so I assume it's likely that they have Octave equivalents.
Version 2.
Cell instead of string with line separators.
This has a less pretty output but is also perhaps a less clunky method, assigning the strings to a cell array rather than having to rely on fprintf for new lines. It can be done easily using the following (uncommented for brevity) version.
function varargout = describe(varargin)
st = dbstack; outcell = {};
for ii = size(st, 1):-1:2
outcell{end+1} = [st(ii).file, ' > ', st(ii).name, ', line ', num2str(st(ii).line)];
end
for n = 1:nargin
outcell{end+1} = ['"', inputname(n), '" is a ', class(varargin{n}), ' of size [', size(varargin{n}), ']'];
end
outcell = outcell.'; % Transpose to make it a column cell array
disp(outcell)
end
Version 3.
Passing variable names as strings, so things like 'myvar(1)' are displayed.
This uses evalin to evaluate the variables in the caller workspace (where describe was called from). NOTE: This could be more memory intensive as you are recreating the variables in this describe function to get their attributes.
function varargout = describe(varargin)
% varargin used to accomodate variable number of input names
st = dbstack;
outstring = '';
for ii = size(st, 1):-1:2
outstring = [outstring, st(ii).file, ' > ', st(ii).name, ', line ', num2str(st(ii).line), '\n'];
end
% Loop over variables and get info
for n = 1:nargin
% Variables are passed by name, so check if they exist
try v = evalin('caller', varargin{n});
outstring = [outstring, '"', varargin{n}, '" is a ', class(v), ' of size ', mat2str(size(v)), '\n'];
catch
outstring = [outstring, 'Variable "', varargin{n}, '" not found!\n'];
end
end
fprintf(outstring)
end
Example use:
% This can be used with indexed variables too. MUST PASS STRINGS!
describe('C{1}', 'B(1:2, :)')
% In the command window
myMainFunction.m > myMainFunction, line 3
myMainFunction.m > mySubFunction, line 39
"C{1}" is a double of size [1 3]
"B(1:2, :)" is a double of size [2 5]
% Because you're passing strings, you can use command syntax if you want
% Gives same result but don't have to pass strings
% as that's how inputs are interpreted anyway for command syntax.
describe C{1} B(1:2, :)
I use something similar myself. Here's mine:
function describe(A)
fprintf(' Class : %s\n',class(A));
fprintf(' Num. Elems : %s\n',num2str(numel(A)));
fprintf(' Size : %s\n',num2str(size(A)));
fprintf(' Total Min : %s\n',num2str(min (A(:))));
fprintf(' Total Max : %s\n',num2str(max (A(:))));
fprintf(' Total Sum : %s\n',num2str(sum (A(:))));
fprintf(' Total Mean : %s\n',num2str(mean(A(:))));
fprintf('Total St.Dev : %s\n',num2str(std (A(:), 1)));
fprintf(' Unique vals : %s\n',num2str(length(unique(A))));
end
Edit: I'm aware this isn't a literal answer to what you ask, but I use this all the time and thought it might be useful to share. :)
PS. Having said that, it has never occurred to me that I might ever want to use such a function in a non-interactive way: if I need to inspect variables in this manner, I just put a breakpoint (or keyboard instruction) in the code and then inspect stuff in the terminal at the point where it's most relevant, so reporting a filename and a linenumber manually has never occurred to me! What is your use-case that you need to perform non-interactive debugging like this? If it's for post-mortem "testing" purposes, you really should be writing proper tests and sanity checks instead anyway!
Also, this is only for single variables, but I find that preferable; it's an extremely simple one-liner loop if you wanted more anyway.
You can use size to have the size of your variable, for the type use class and for the name use inputname.
For example:
function describe(a)
s = size(a); % Return the size of a
t = class(a); % Return the type of a
name = inputname(1); % Return the name of a
printf(['filename.m line 3: ''''' name ''''' size:' s(1) 'x' s(2) ' and type: ' t]);
end
I don't know how to use the name of file and the line, and if you want another way to display this you can can use if condition to seperate scalar from vector from matrix.

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.

Assigning dynamic values to variables in base workspace in MATLAB

load( lapFileSource, 'UntitledMeta_Data' );%My MetaData
universal={'TestType';'TestApparatus';'TestSystem Location';
'Configuration';'Wire condition';'Wire Type';'Circuit';};
u=11;
for o=drange(1:u)
if strcmp('',MetaData{o})
universal{o}='Null';
else
universal{o}=MetaData{o};
end
assignin('base','universal{o}',MetaData{o})
end
I am getting error to assignin the variable in workplace.
You need to read the documentation for the functions you use. From the documentation for assignin:
% The var input must be the array name only; it cannot contain array indices.
And, even more explicitly:
% assignin does not assign to specific elements of an array.
% The following statement generates an error:
X = 1:8;
assignin('base', 'X(3:5)', -1);
You can either shift your assignin call outside of the for loop and pass your full array to the base workspace, or you can follow the advice of the documentation and utilize evalin.
For example:
function trialcode
n = 5;
myarray = cell(1, 5);
for ii = 1:n;
if mod(ii,2)
myarray{ii} = 'odd';
else
myarray{ii} = 'even';
end
mycmd = sprintf('evalinarray{%u} = ''%s'';', ii, myarray{ii});
evalin('base', mycmd);
end
assignin('base','assigninarray', myarray)
end
The resulting arrays, evalinarray and assigninarray, are equivalent. Of the two, I would recommend using assignin as it is a lot more robust and explicit than the evalin approach.

Determine the most recently evaluated variable and save it to .mat-file

Is there a way to find the most recently evaluated variable in Matlab? who or whos don't seem to time stamp the variables in the workspace.
Here is a use case. I would like to have a generic function 'probe()' that can be called anywhere in a Matlab script/code. I would like to save the most recently evaluated variable to a .mat-file without having to pass any custom parameter relating to the variable being saved. Is this possible?
ans comes close to what I am trying to achieve, but it will not be available as my code has variables on the left hand side in the assignments.
If you are doing this in the Command Prompt, what you can do is use this post by gnovice to retrieve the entire command history since you opened MATLAB to a text array. Once you do that, you simply search the second last row for the variable before the equals sign.... assuming you did a lhs statement. You also want to take into account that you are echoing the variable in the Command Prompt without a left-hand side statement. We can easily find this through regexp.
You need to search at the second last row of the text array because gnovice's code to capture the history requires an additional line of code. This code gets captured in the history and that's not what you want. As such, you need to look at the second last row / entry.
Therefore, do this:
history = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory; %// From gnovice's post
historyText = char(history);
lne = historyText(end-1,:); %// Get second last line
%// Do a regexp and retrieve the text with or without the equals sign
var = regexp(lne, '\w*', 'match');
%// Get first match which is the variable before any symbols or just the word
var = var{1};
Here's a quick example. This was my complete command history before trying the above code:
>> A = rand(10,10);
>> B = A + 2;
>> D = B * 3;
After I run the above code, I get for var:
var =
D
Similarly, if we just evaluate the answer without assigning anything to the left-hand side:
>> A = rand(10,10);
>> B = A + 3;
>> A
Running the above code, I get:
var =
A
To finally end it all, if you want to save this variable to disk, you can use an eval statement to facilitate this:
>> name_of_file = 'file.mat';
>> eval(['save ' name_of_file ' ' var]);
The above code will take a file name that you specify... so in this case it'll be test.mat, then invoke the save command with var as the variable from the Workspace you would like to save.
This is a basic sketch how you can do it, using the function dbstack:
function probe
%// get filename of caller file and line where probe was called
lineANDfile = dbstack;
file = lineANDfile(end).file;
linenum = lineANDfile(end).line;
%// read caller m-file
mLines = textread(file, '%s','delimiter', '\n');
%// get line previous of the line where probe was called
mLinesUntilProbeCall = mLines(1:linenum - 1);
%// last non empty line before probe call -> line of interest
mLine = mLines{ find( ~cellfun(#isempty,mLinesUntilProbeCall),1,'last') };
%// get string (variable name) left of =
varnameCell = textscan(mLine,'%s');
%// isolate varnames
getFouts = regexp(varnameCell{1}{1},'(?<=\[).+?(?=\])','match');
if isempty(getFouts)
varnames = varnameCell{1}(1);
else
varnames = strsplit( getFouts{1},',');
end
%// create struct with varnames as fields
for ii= 1:numel(varnames)
probeOut.(varnames{ii}) = evalin('base',varnames{ii});
end
save('probeOut.mat','probeOut');
end
which you can call in a script like:
y = 5;
xz = 42;
probe %// empty lines before call allowed!
it will create a .mat-file with a struct probeOutand the field xz.
After loading the .mat-file again:
>> probeOut.xz
ans =
42
It will also work, if you have multiple output arguments:
y = 5;
[xz,z] = deal(42,5);
probe
your .mat-file will then look like:
The case
y = 5;
[xz] = deal(42,5);
probe
is also covered.