In MATLAB R2019a a new way to export figures was added whereby the result "is tightly cropped around the axes with minimal white space". This feature is accessed using the axes toolbar:
My question is: How do we invoke this new export feature programmatically?
It should be fairly easy to get the export dialog to open for specific axes (i.e. simulate a button click), but I'm more interested in bypassing the dialog and just saving a file to disk, e.g.
croppedExport(hAxes, outputPath);
P.S.
I am aware that this functionality can be achieved using a 3rd party tool like export_fig.
TL;DR
matlab.graphics.internal.export.exportTo(hAxes, fullpath);
The tooltip of this new button says "Export...", which is going to help us identify it. Digging within the properties of the axes toolbar (struct(hAxes.Toolbar)) we can get a glimpse of the function that is being called when the button is pressed:
hB = struct(struct(hAxes.Toolbar).ButtonGroup).NodeChildren(1);
%{
hB =
ToolbarPushButton (Export...) with properties:
Tooltip: 'Export...'
Icon: 'export'
ButtonPushedFcn: #(e,d)matlab.graphics.internal.export.exportCallback(d.Axes)
%}
which unfortunately points to directory full of .p files:
...\MATLAB\R2019a\toolbox\matlab\graphics\+matlab\+graphics\+internal\+export
...and forces us to do proceed with trial and error. For example, we can choose a random .p file whose name sounds right to us, and see if we can discover its API:
>> matlab.graphics.internal.export.exportTo()
Error using matlab.graphics.internal.export.exportTo
Not enough input arguments.
>> matlab.graphics.internal.export.exportTo('')
Error using matlab.graphics.internal.export.exportTo
Not enough input arguments.
>> matlab.graphics.internal.export.exportTo('','')
Error using matlab.graphics.internal.export.ExporterArgumentParser/parseInputParams
'' matches multiple parameter names: 'background', 'destination', 'format', 'handle', 'margins', 'resolution', 'target'. To avoid ambiguity, specify the complete name of the parameter.
Error in matlab.graphics.internal.export.ExporterArgumentParser/processArguments
Error in matlab.graphics.internal.export.Exporter/process
Error in matlab.graphics.internal.export.exportTo
The last error message provides very interesting information, which allows us to take some educated guesses regarding the required inputs:
'background' - probably background color
'destination' - probably where to put the file
'format' - probably what is the file extension
'handle' - probably the axes handle
'margins' - (self explanatory)
'resolution' - (self explanatory)
'target' - ???
Following the "minimal" input set that is requested in the question, our next attempt is:
membrane;
matlab.graphics.internal.export.exportTo('handle', gca, 'destination', 'e:\blabla.png');
... which creates the a file at the desired location and also returns a truecolor RGB image that is cropped just like we wanted!
Although we are done, we can try to simplify this function call even further based on the "convention" of saveas, which is saveas(what, where, ...):
matlab.graphics.internal.export.exportTo(gca, 'e:\blabla.png');
... which works (!) and so this becomes our method of choice.
Related
So I am working on constructing a mask for a CAN unpack system. It's a basic mask with 2 promoted parameters and a browse button. The promoted parameters are the "CANdb" file field and the drop down menu, "MsgList", that follows it.
The basic mask it self works. I'm able to browse for a CAN ".dbc" file and its path is available in the promoted field, and even the drop down menu works where I'm able to select a message from those available in the ".dbc" file. But this is about all the functionality I'm getting.
My observation was that this problem is in 2 different parts. I'll try to explain them individually.
The first is with the "CANdb" promoted parameter. While on the outside it appears as though the parameter is changing (it changes in the mask), internally nothing changes: when i peak under the mask, there is no change on the values of the CANUnpack Block that i am using. Then CANUnpack block itself does update when I double click to open it. The new DBC and message list shows up but only on the block.
The second issue was with The list of messages, that is also promoted to the mask is also not updating. The list from the previous DBC file remains there, and does not change even if i run the simulation, update the model or refresh the block. When i close and reopen the model, it updates then.
These observations lead me to believe that i need to add some kind of code to update the mask, but i don not know what this code will be. I though that the issue may have to do with the fact that the value needs to propagate from the mask to the block and then updated all the parameters so maybe that prevents or hinders an update.
For this i then removed the promoted parameter for the DCB file and linked the browse button directly to the block parameter. The only difference this made is that the name of the new DBC file shows up on the CAN unpack block. Nothing else changes. Not even the messages of the "MsgList" till I double click to open the block. And as usual, the message list on the mask remains unchanged.
I am adding some images and the code for my browse button below to aid with trouble shooting. Thanks in advance.
pp = Simulink.Mask.get('NXP_CAN_Unpack/Subsystem/CANUnpack2');
p = pp.getParameter("CANdbFile");
[fName,pName] = uigetfile("*.dbc");
p.Value = [pName,fName] ;
Mask for system
Inside Mask
Block Parameters for CANUNpack
I found a neat bit of code for setting drawing tools via callback:
draw.m .
Edit
My apologies - I didn't realize that the Name property was a red herring - it is the annotation call that enables drawing the various figures.
So my corrected question is: is there a way to execute other menu item commands, such as set(gcf,'Some_property','Rotate 3D') ?
The easiest way to execute a menu item's command is to get a handle to the menu item and then inspect the Callback property to see what it calls internally.
rotate_menu = findall(gcf, 'type', 'uimenu', 'tag', 'figMenuRotate3D');
rotate_menu.Callback
% 'toolsmenufcn Rotate'
As you can see this uses an internal function toolsmenufcn which we could call directly to activate the tool.
toolsmenufcn(gcf, 'Rotate')
If you actually look at the contents of toolsmenufcn.m (edit toolsmenufcn), you will see a list of all available commands.
Using the toolsmenufcn directly is of course undocumented so use at your own risk. On the other hand, dynamically retrieving and executing the Callback for the menu should work across versions.
I currently have a GUI that outputs a single text file based on various input parameters. However, I need to modify my application such that the GUI outputs multiple text files based on N inputs. The original GUI designer is no longer available and the main m-file has over 5k lines of code making it difficult to troubleshoot (not to mention the code is very unorganized and not commented). Does anyone have any suggestions on how I can run the GUI N times based on the N inputs and output N text files without modifying the original m-file?
Assume your gui is called myApp and your callback to s called myButton_Callback.
I also assumng that the tag of the uicontrol is 'myButton'.
Here is the caller script:
myApp_h = myApp();
myApp_handles = guidata(myApp_h);
myButton_h = myApp_handles.myButton;
MyApp('myButton_Callback', myButton_h, myApp_handles);
You can automate any gui control by this method.
I have a GUI that displays plots, and it launches a "playlist" window. When I perform an action in the playlist window, is there a way to run a function in the launching window?
To be more clear, if I add files in the playlist window, I would like the first file in the list to be displayed in the launching window, but I would like to do this through a function in the launching window rather than passing the plot handle to the playlist window.
Thank you in advance for any assistance you can offer!
One of the easiest ways to do this, would be using findobj.
This looks through graphics objects, finding those that match the provided filter criteria.
As the number of existing figures should be relatively small, it should also be reasonably fast.
Assuming your launcher-figure has some name you can get the launcher figure-handle
e.g. via
launcherFig = findobj(0,'type','figure', 'name', <launcher-name>);
Or give your lauchner figure a Tag that you can search for:
% in your launcher-figure code:
launcherFig = figure('Tag', 'MyLauncher');
% and modify the search accordingly:
launcherFig = findobj(0, 'type', 'figure', 'Tag', 'MyLauncher');
And, for completeness, though I don't like them, you could use a global variable:
% in your launcher-figure code:
launcherFig = figure(...);
% store handle in the global variable:
global LauncherHandle;
LauncherHandle = launcherFig;
% no need for a search now anymore, just get the global variable:
global LauncherHandle
Say I've written a class in a package, called mypackage.myclass. I've written my own HTML documentation for the package and the class, and have included this within the MATLAB help browser as described in the MATLAB documentation.
I can display this HTML documentation by using the help browser to navigate directly to it, but typing doc mypackage.myclass does not display it; instead it displays some HTML documentation that is auto-generated by helpwin (which is a nice feature, but not what I want - the auto-generated documentation is too techy for my users).
How can I force doc to display my documentation, rather than the auto-generated documentation?
Equivalently:
When you run doc docTopic, inside the doc command the Java class com.mathworks.mlservices.MLHelpServices.showReferencePage(docTopic) gets called. If a reference page for docTopic exists, it displays it and returns a success value. If a reference page doesn't exist, it returns a failure value, which then causes helpwin(docTopic) to get called. Somewhere there must be some catalog that connects values of docTopic with individual reference HTML files. How can I fiddle with that catalog - or can I create one for my package?
MathWorkers and #Yair, please give me enough undocumented rope to hang myself with :)
As far as I know this is not possible and not intended by MathWorks. I don't know of an undocumented way of doing this either. As far as I remember the keywords for doc are hard-coded somewhere.
Depending on your setup you can try the following: Prepare your own doc command that uses web(..., '-helpbrowser') to display HTML pages in MATLAB's help browser:
function doc(topic)
my_topics = {
'foo', 'foo.html'
'bar', 'bar/help/intro.html'
};
for i = 1 : size(my_topics, 1)
if strcmpi(topic, my_topics{i, 1})
web(my_topics{i, 2}, '-helpbrowser');
return;
end
end
% Fall back to MATLAB's doc. Note that our doc shadows MATLAB's doc.
docs = which('doc', '-all');
old_dir = cd();
c = onCleanup(#() cd(old_dir));
cd(fileparts(docs{2}));
doc(topic);
end
If you put that function in a file doc.m and put the corresponding directory at the beginning of the MATLAB path (see help addpath) then it will be called instead of the built-in doc.
Of course you could use some other place to store your custom doc mapping (a file, for instance) or use some kind of dynamic lookup scheme.
UPDATE: As of MATLAB R2012b, the '-helpbrowser' option of web is undocumented. This is probably related to the GUI changes in that MATLAB version, which also include the help browser. web(..., '-helpbrowser') still works as intended, but that may change in future versions of MATLAB. As far as I know, there is no documented way of opening any HTML page in the help browser in R2012b.