I have a matlab script, where I would like to dynamically create sections in my matlab publish.
At present, the only way I know to create a section break, is to put code like this in my script:
%% This is a section break
I'd like to run publish on my script, and have the section breaks get added as part of the publish. For instance. Say I had the following script:
breaks(1).name = 'This is section break 1.';
breaks(2).name = 'This is section break 2.';
for ix = 1 : numel(breaks)
functionThatInsertsSectionBreakTitle(breaks(ix).name);
fprintf('Some random processing associated with break %d.\n', ix);
end
I would like to call publish on that script, and end up with a document that looks something like:
This is section break 1.
Some random processing associated with break 1.
This is section break 2.
Some random processing associated with break 2.
Obviously I could do this by writing a script that writes a script that then gets executed by publish. I was hoping for something a bit more direct. Am aware of the report generation toolbox, which I would hope would cleanly handle this type of scenario. Alternatively, if the new (as of R2016a) Live Script handles this use case, that's a fine answer as well.
One way to address this problem is by displaying html code in the command output (documented here).
In your example, the code would look like this:
breaks(1).name = 'This is section break 1.';
breaks(2).name = 'This is section break 2.';
for ix = 1 : numel(breaks)
disp(['<html><h2>' breaks(ix).name '</h2></html>']);
fprintf('Some random processing associated with break %d.\n', ix);
end
This is incredibly useful when you want to get results to be displayed with a custom layout, such as a table. And it avoids the need of having a Matlab Report Generator license...
How to call an m file from another m file in MATLAB without add its folder path?
I don't want to add its folder via
addpath(genpath(''))
Similar to the functionality of MATLAB's built-in run for scripts, you can cd into the secondary path, execute your function, and then return to the previous directory.
A small example:
% testcode.m
function [output] = testcode(fullfunctionpath, A, B)
[pathname, functionName] = fileparts(fullfunctionpath);
olddir = cd(pathname);
output = feval(functionName, A, B);
cd(olddir);
end
% .\test\testing.m
function [output] = testing(A, B)
output = A + B;
end
With the call:
C = testcode('C:\testcode-matlab\test\testing.m', 1, 2);
Will return
C =
3
Note that this approach does not have error handling nor does it check for duplicates that already exist in your path definition. If the called function is not present in the target folder but does exist in the path, the function in MATLAB's path will still be executed. See: Function Precedence Order for more information.
All visibility rules for functions are based on Folders. If you want to have different visibilities you have to place your functions in different folders.
Typically, avoiding duplicate function names and just adding all source files to your search path is what works. To avoid duplicate function names you may want to take a look at packages.
MATLAB's methodsview tool is handy when exploring the API provided by external classes (Java, COM, etc.). Below is an example of how this function works:
myApp = actxserver('Excel.Application');
methodsview(myApp)
I want to keep the information in this window for future reference, by exporting it to a table, a cell array of strings, a .csv or another similar format, preferably without using external tools.
Some things I tried:
This window allows selecting one line at a time and doing "Ctrl+c Ctrl+v" on it, which results in a tab-separated text that looks like this:
Variant GetCustomListContents (handle, int32)
Such a strategy can work when there are only several methods, but not viable for (the usually-encountered) long lists.
I could not find a way to access the table data via the figure handle (w/o using external tools like findjobj or uiinspect), as findall(0,'Type','Figure') "do not see" the methodsview window/figure at all.
My MATLAB version is R2015a.
Fortunately, methodsview.m file is accessible and allows to get some insight on how the function works. Inside is the following comment:
%// Internal use only: option is optional and if present and equal to
%// 'noUI' this function returns methods information without displaying
%// the table. `
After some trial and error, I saw that the following works:
[titles,data] = methodsview(myApp,'noui');
... and returns two arrays of type java.lang.String[][].
From there I found a couple of ways to present the data in a meaningful way:
Table:
dataTable = cell2table(cell(data));
dataTable.Properties.VariableNames = matlab.lang.makeValidName(cell(titles));
Cell array:
dataCell = [cell(titles).'; cell(data)];
Important note: In the table case, the "Return Type" column title gets renamed to ReturnType, since table titles have to be valid MATLAB identifiers, as mentioned in the docs.
I would like a way to track all function calls that have operated on a specific workspace variable -- for instance, a sound waveform that will be transformed by various signal processing functions.
One cumbersome and fragile way is to do this:
>> cfg = [];
>> curr_call = 'data_out = my_function(cfg,data_in);';
>> eval(curr_call);
>> data_out.cfg.history = cat(1,data_out.cfg.history,{curr_call});
What would be much better is the following:
>> cfg = [];
>> data_out = my_function(cfg,data_in);
>> data_out.cfg.history
'data_out = my_function(cfg,data_in);'
EDIT for clarification: In other words, this variable has a field, cfg.history, that keeps track of all history-enabled functions that have operated on it (ideally with arguments). The history field should be updated regardless of where function calls originate: my example above is from the command line, but calls made from cell mode or within a script should also be appended to the history. Obviously, I can edit my_function() in the above example so that it can modify the history field.
NOTE in response to discussion below: the motivation for doing this is to have the history "attached" to the data in question, rather than say, in a separate log file which would then need to be packaged with the data somehow.
Can this be done?
You can access the full Session history using this code:
import com.mathworks.mlservices.MLCommandHistoryServices
history=MLCommandHistoryServices.getSessionHistory;
To achive what you want, use this code:
import com.mathworks.mlservices.MLCommandHistoryServices;
startcounter=numel(MLCommandHistoryServices.getSessionHistory);
disp('mydummycommand');
disp('anotherdummycommand');
history=MLCommandHistoryServices.getSessionHistory;
commands=cell(history(startcounter-2:end-1));
Be aware that these functions are undocumented. It uses the command history which is typically located at the bottom right in your matlab.
I created an UItable in Matlab which I fill with various values and options.
It looks like:
the corresponding code is the following:
selector_1 = { 'A'; 'B' ; 'C' };
selector_2 = { 'A.1'; 'A.2'; 'A.3'; ...
'B.1'; 'B.2'; 'B.3'; ...
'C.1'; 'C.2'; 'C.3' };
rows = 5;
f = figure('name','Configuration of output','Position',[200 200 430 25+rows*20],'numbertitle','off','MenuBar','none');
dat = {'select outputfile...', 'select identifier...', 'Specifier', 'Index'};
dat = repmat(dat,rows,1);
columnname = {'Output file ',...
'Identifier ',...
'Specifier ', 'Index'};
columnformat = { {selector_1{:}}, {selector_2{:}}, 'char', 'numeric' };
columneditable = [true true true true];
t = uitable('Units','normalized','Position',...
[0 0 1 1], 'Data', dat,...
'ColumnName', columnname,...
'ColumnFormat', columnformat,...
'ColumnEditable', columneditable,...
'RowName',[]);
set(t, 'Data', dat,'celleditcallback','get(t,''Data'')');
So I run the code and the figure is open. The underlying script has therefore finished.
When I now edit the table my uitable object is changed and after I finished I can get my final configuration with:
finalconfig = get(t,'Data');
But the thing is I need manually type this line, because my script has already finished. If I put this line at the end of my script, I get an error.
So I thought about using the following loop, to detect when I close the table and to store the last configuration
while ~isempty(findobj('name','Configuration of output'))
% some action
end
finalconfig = get(t,'Data');
And I tried everything to put inside the loop, the whole script, just the set command including the celleditcallback, and other things, but nothing worked. Either my script get stucked inside the loop or the display of my table is not updated when I edit a value. I also tried drawnow at different positions. How one handles this situation? How can I automatically store my final results?
I assume "closing the window" is the best action to detect, as I don't think I could implement a "save" button. I also tried to create a gui using GUIDE but got completely lost, I hope to solve it without.
Edit:
I was now able to implement a "save"-button and tried the callback as follows:
uimenu('Label','Save configuration','Callback',#saveConfig);
function saveConfig(~,~)
output = get(t,'Data',);
save([pwd 'output.mat'],'output');
end
also I implemented a custom CloseRequestFcn as suggested by Lucius Domitius Ahenobarbus. But then I have either one of the following problems:
1)
I define everything as a script, everything works fine, but I need to define functions like #saveConfig (actually my favorite) or #my_Closefcn as a unique function-file in my workspace and I have a hard time to pass the right parameters as dat always remains the same, even though it actually gets changend.
(The example from the mathworks site works! But it doesn't need additional parameters.)
2) When I use
function configuration
% my script from above
end
I can implement #saveConfig or #my_Closefcn directly (nested) and I guess the passing of the parameters would work fine. But the editing of my table does not work anymore, throwing the following error:
Error using handle.handle/get
Invalid or deleted object.
Error while evaluating uitable CellEditCallback
How to solve that?
Now that I know that I can even add buttons to an uitable I REALLY like to avoid GUIDE.
My code above is executable, so I'd be glad if you try it to see what my actual problem is, as it is hard to describe.
depending on using GUIDE or not:
use the CloseRequestFcn->
without GUIDE use:
%write your own CloseRequestFcn and set the figure CloseRequest-Callback to it:
set(gcf,'CloseRequestFcn',#my_closefcn)
%use gcf or the handle of the figure directly
and define my_closefcn including a delete statement for the figure-handle, else the figure will not close :)
See the docs for more information about "Redefining the CloseRequestFcn".
with GUIDE:
you can edit the CloseRequestFcn by inspecting the figure. There is a field called CloseRequestFcn that will create the function automatically and you dont need to take care about getting the handle. It will look like this:
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject handle to figure1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: delete(hObject) closes the figure
delete(hObject);
Now BEFORE deleting the figure, you should be able to get the data of the uitable (if you have the handle) and I would suggest to just assign the data to the base workspace, like:
assignin('base', 'finalTableData', get(myTableHandle,'Data'));
EDIT
as I was not clear enough, see this example:
(use within one single script)->
function test
h=figure;
x=1:10;
mytable=uitable(h,'Data',x);
set(h,'CloseRequestFcn',#myCloseFcn)
%give a unique Tag:
set(h,'Tag', 'myTag')
set(mytable,'Tag','myTableTag')
end
function myCloseFcn(~,~)
myfigure=findobj('Tag','myTag');
myData=get(findobj(myfigure,'Tag','myTableTag'),'Data')
assignin('base','myTestData',myData)
delete(myfigure)
end
in fact, there is no need to take care for the parameters of your Closereq-Callback, if you know how to find the handle of the figure! Just give something to your figure/uitable that you are able to identify it later on. I used 'Tag', because the first thing I would think of, but there would be other parameters as well.
There are only two differences I can think of between running the code directly after the code, or inside the code.
1. Scope
Perhaps you are actually working with functions, rather than scripts. In this case the problem may be that inside your function, something you need is out of scope.
2. Timing
Though it is rare, sometimes the computer may seem to be finished, whilst it is actually still busy (for a few milliseconds or so).
Here are the steps to a general approach:
Make sure there is a trivial line at the place where you want to insert your command (1==1 for example)
Put a breakpoint at the line
Once matlab stops at the breakpoint, wait a second and try to run your command.
If it works I would bet on problem number 2. try placing a pause(1) before your command and see whether it helps.
If it doesn't work you are likely meeting problem number 1. Now it becomes a matter of finding the right place to put your command. And if the command cannot be put somewhere else in the code, perhaps try an ugly evalin(,'base'). However, the latter should really be considered a workaround rather than a solution.