Put various buttons in a figure to toggle figures or print/save ONLY the figure parts. Will export_fig() work?? (using GUIDE)

1 ビュー (過去 30 日間)
Hello!
I have an app that processes several signal analysis routines on many files. A specific format, consisting of several subplots, has been created to display the relevant information (waveforms, spectra, various text, etc.). Main program is created in GUIDE -- tried AppDesigner, no way. :(
I would like to then display the results in a sequence of figures that eliminate the toobar and menubar and have four buttons at the bottom of the subplots: two to "Print" and "Save", and two to go to the next or previous dataset. I guess "Close" would also be appropriate!
Thoughts on ways to do this are appreciated! I've thought maybe Oliver Woodford's export_fig using isolate_axes would work (with Yair's mods?). Also, could create a GUIDE .fig to do this as a window? I'm not sure if that's overkill or miskill.
Thanks!
Doug Anderson
  1 件のコメント
Douglas Anderson
Douglas Anderson 2022 年 2 月 23 日
I actually have another thought: To create a GUIDE window that has the "Print" and other buttons only at the bottom, and have the figures (one by one, according to previous/next button) displayed on axes() in the GUIDE window.
Is that doable and reasonable?
Thanks!
Doug

サインインしてコメントする。

採用された回答

Voss
Voss 2022 年 2 月 23 日
編集済み: Voss 2022 年 2 月 23 日
I think GUIDE would be a perfectly fine way to do this.
I'm not familiar with export_fig, etc., but you can use the built-in print() function to print a figure to file or to a printer.
As an alternative to GUIDE, you can create everything programmatically, which is the way I would usually go about something like this. Using nested functions makes it pretty straightforward to do. The following code uses this approach and is a functional simplified version of what you want to do (I think). It'll generate some random data when you click Previous or Next and save the figure to a png file when you click Save. (And there's no need for a separate Close button because you can use the figure's CloseRequestFcn.) Try it out and adapt it to your needs if you like.
function my_app()
f = figure( ...
'Units','pixels', ...
'NumberTitle','off', ...
'Name','My App', ...
'Toolbar','none', ...
'MenuBar','none', ...
'CloseRequestFcn',@cb_close);
ax = axes( ... % you can still use subplot to create your axes and lines
'Parent',f, ...
'Units','pixels', ...
'Box','on');
data_line = line( ...
'Parent',ax, ...
'XData',1:10, ...
'YData',randn(1,10));
buttons = [ ...
uicontrol( ...
'Parent',f, ...
'Style','pushbutton', ...
'Units','pixels', ...
'String','Print', ...
'Callback',@cb_print) ...
uicontrol( ...
'Parent',f, ...
'Style','pushbutton', ...
'Units','pixels', ...
'String','Save', ...
'Callback',@cb_save) ...
uicontrol( ...
'Parent',f, ...
'Style','pushbutton', ...
'Units','pixels', ...
'String','Previous', ...
'Callback',@cb_previous) ...
uicontrol( ...
'Parent',f, ...
'Style','pushbutton', ...
'Units','pixels', ...
'String','Next', ...
'Callback',@cb_next) ...
];
current_data_set = 1;
n_data_set = 10;
output_file_name = ['.' filesep() 'output'];
set(f,'SizeChangedFcn',@scf);
scf();
function scf(~,~)
pos = get(f,'Position');
set(ax,'Position',[30 60 pos(3)-60 pos(4)-80]);
set(buttons(1),'Position',[pos(3)-290 4 60 22]);
set(buttons(2),'Position',[pos(3)-220 4 60 22]);
set(buttons(3),'Position',[pos(3)-150 4 60 22]);
set(buttons(4),'Position',[pos(3)-80 4 60 22]);
end
function cb_close(~,~)
answer = questdlg('Are you sure?');
if ~strcmp(answer,'Yes')
return
end
delete(f);
end
function cb_print(~,~)
% data = print(f,'printer1');
end
function cb_save(~,~)
% make the buttons invisible before saving:
set(buttons,'Visible','off');
% print figure to file directly:
print(f,[output_file_name sprintf('_%03d',current_data_set) '.png'],'-r300','-dpng');
% or get the figure contents as numeric RGB data (e.g., if you want
% to edit it before saving to file):
% data = print(f,'-RGBImage','-r300');
% save it to file:
% imwrite(data,[output_file_name sprintf('_%03d',current_data_set) '.png']);
% turn the buttons back on
set(buttons,'Visible','on');
end
function cb_next(~,~)
if current_data_set == n_data_set
return
end
current_data_set = current_data_set+1;
% update plots with next data set's data, e.g.,
% set(data_line,'XData',whatever,'YData',whatever)
% set(ax,'XLim',whatever,'YLim',whatever)
% (using random data here)
new_data = randn(1,10);
set(data_line,'XData',1:10,'YData',new_data);
set(ax,'XLim',[1 10],'YLim',[min(new_data) max(new_data)]);
end
function cb_previous(~,~)
if current_data_set == 1
return
end
current_data_set = current_data_set-1;
% update plots with previous data set's data
% (using random data here)
new_data = randn(1,10);
set(data_line,'XData',1:10,'YData',new_data);
set(ax,'XLim',[1 10],'YLim',[min(new_data) max(new_data)]);
end
end
  4 件のコメント
Voss
Voss 2022 年 2 月 23 日
編集済み: Voss 2022 年 2 月 23 日
For the subplots, you can specify the parent as "f", yes (though that is not strictly necessary since "f" will be the current figure when the subplots are created, assuming they're created where my code has its single axes "ax" being created - I could've omitted specfying the parent of "ax" too). The important thing is to use the output argument from subplot() so you have the handle to the axes of each subplot. Then you can set each axes' Position in the SizeChangedFcn (scf), or you can set each axes 'Units' to 'normalized' and let them scale with the figure when the figure changes size.
Regarding this approach vs GUIDE, what GUIDE does for you is create a pre-made figure with all your UI components and properties before your code runs (and provide an interface for setting up that figure and its components and their properties - which can be useful). So, to answer your question: yes, any 'Style' of uicontrol available in GUIDE is available with this approach.
set(f,'SizeChangedfcn',@scf); sets the figure's SizeChangedFcn, which is a function that executes whenever the figure changes size, so you put whatever code in there you need in order to update the component uicontrols/axes/uipanels in the figure. Then the second line scf(); just executes that SizeChangedFcn once so that the positions are all up to date when the program starts.
In this context "~" indicates an unused argument in a function definition. Basically the syntax "(~,~)" here means that the function takes two input arguments, both of which are unused. The reason to do that is that any uicontrol's Callback (and any figure's SizeChangedFcn, CloseRequestFcn, etc., - basically any function for interactive control of any type, I'll use the generic term "callback function"), requires at least two input arguments: (1) the handle to the object (i.e., the uicontrol or figure whose function is being executed), and (2) "event data", which is always empty for uicontrols as far as I know (but sometimes contains useful information for some other types of components, e.g., in a uitable's CellSelectionCallback or CellEditCallback event data tells you which cell(s) in the table is/are being interacted with). MATLAB passes those two things (object handle and event data) to any callback function, so any callback function has to have at least two input arguments.
In this case though, the callback functions don't need to use the first argument passed in, because, being nested functions, they have access to the top-level function workspace, which contains whatever figure or uicontrol handles they might need (e.g., "f", "buttons"). And, like I said, the second argument ("event data") is empty for uicontrols, so they don't need that either. So, a callback function needs (at least) two input arguments, but a nested callback function doesn't (typically) need either of those, so, "(~,~)".

サインインしてコメントする。

その他の回答 (0 件)

製品


リリース

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by