|On this page…|
This example shows how to create a GUIDE GUI that accepts input parameters and plots data in two axes. The parameters define a time-varying and frequency-varying signal. One plot displays the data in the time domain, and the other plot displays the data in the frequency domain.
To get and view the example code:
Copy the example FIG-file and code file to your current (writeable) folder and open the FIG-file in GUIDE:
copyfile(fullfile(docroot, 'techdoc','creating_guis',... 'examples','two_axes*.*')), fileattrib('two_axes*.*', '+w') guide two_axes.fig
From the GUIDE Layout Editor, click the Editor button .
The two_axes.m code displays in the MATLAB® Editor.
If you run the GUI and click the Plot button, the GUI appears as shown in the preceding figure. The GUI code evaluates the expression displayed at the top of the GUI using parameters that you enter in the f1, f2, and t fields. The upper line graph displays a Fourier transform of the computed signal displayed in the lower line graph.
Note: To create a more advanced GUI that also displays time and frequency plots, see Synchronized Data Presentations in a GUIDE GUI.
This GUI plots two graphs depicting three input values:
Frequency one (f1)
Frequency two (f2)
A time vector (t)
When you click the Plot button, the GUI puts these values into a MATLAB expression that is the sum of two sine functions:
x = sin(2*pi*f1*t) + sin(2*pi*f2*t)
Then, the GUI calculates the FFT (fast Fourier transform) of x and plots the data in the frequency domain and the time domain in separate axes.
The GUI provides default values for the three inputs. This enables you to click the Plot button and see a result as soon as you run the GUI. The defaults indicate typical values.
The default values were created by setting the String property of the edit text. The following figure shows how the value was set for the time vector.
Since there are two axes in this GUI, you must specify which one you want to target when plotting data. To identify the target axes, use the handles structure, which contains the handles of all components in the GUI. The handles structure is a variable that GUIDE passes as an argument to all component callbacks. For instance:
plot_button_Callback(hObject, eventdata, handles, varargin)
You access the handles using field names that GUIDE derives from the component Tag properties. To make code more readable and memorable, this example sets the Tag property to descriptive names. The following graphic shows how the upper axes Tag is set to 'frequency_axes' in the Property Inspector.
Altering the Tag property value sets the field name for the frequency plot axes to frequency_axes in the handles structure. Within the plot_button_Callback code, you access that axes' handle with handles.frequency_axes. Use the handle as the first argument of the plot function to ensure that the graph is displayed in the correct axes, as follows:
Similarly, set the Tag property value of the time axes to time_axes. Then, call plot as follows:
When you use the GUI, you type parameters into three edit text boxes as strings of text. If you type an invalid value, the graphs can fail to inform or even to generate. Preventing bad inputs from being processed is an important function of almost any GUI that performs computations. This GUI validates that:
All three inputs are positive or negative real numbers
The t (time) input is a vector that increases monotonically and is not too long to legibly display
In this example, each edit text control callback validates its input. If the input fails validation, the callback disables the Plot button, changes its String to indicate the type of problem encountered, and restores focus to the edit text control, highlighting the erroneous input. When you enter a valid value, the Plot button reenables with its String set back to 'Plot'. This approach prevents plotting errors and avoids the need for an error dialog box.
The str2double function validates most cases, returning NaN (Not a Number) for nonnumeric or nonscalar string expressions. An additional test using the isreal function makes sure that a text edit field does not contain a complex number, such as '4+2i'. The f1_input_Callback contains the following code to validate input for f1 :
function f1_input_Callback(hObject, eventdata, handles) % Validate that the text in the f1 field converts to a real number f1 = str2double(get(hObject,'String')); if isnan(f1) || ~isreal(f1) % isdouble returns NaN for non-numbers and f1 cannot be complex % Disable the Plot button and change its string to say why set(handles.plot_button,'String','Cannot plot f1') set(handles.plot_button,'Enable','off') % Give the edit text box focus so user can correct the error uicontrol(hObject) else % Enable the Plot button with its original name set(handles.plot_button,'String','Plot') set(handles.plot_button,'Enable','on') end
Similarly, f2_input_Callback code validates the f2 input.
The time vector input, t, is more complicated to validate. As the str2double function does not operate on vectors, the eval function is called to convert the input string into a MATLAB expression. Because you can type many things that eval cannot handle, the first task is to make sure that eval succeeded. The t_input_Callback uses try, catch blocks to do the following:
Call eval with the t_input string inside the try block.
If eval succeeds, perform additional tests within the try block.
If eval generates an error, pass control to the catch block.
In that block, the callback disables the Plot button and changes its String to 'Cannot plot t'.
The remaining code in the try block makes sure that the variable t returned from eval is a monotonically increasing vector of numbers with no more than 1000 elements. If t passes all these tests, the callback enables Plot button and sets its String to 'Plot'. If it fails any of the tests, the callback disables the Plot button and changes its String to an appropriate short message. Here are the try and catch blocks from the callback:
function t_input_Callback(hObject, eventdata, handles) % Disable the Plot button ... until proven innocent set(handles.plot_button,'Enable','off') try t = eval(get(handles.t_input,'String')); if ~isnumeric(t) % t is not a number set(handles.plot_button,'String','t is not numeric') elseif length(t) < 2 % t is not a vector set(handles.plot_button,'String','t must be vector') elseif length(t) > 1000 % t is too long a vector to plot clearly set(handles.plot_button,'String','t is too long') elseif min(diff(t)) < 0 % t is not monotonically increasing set(handles.plot_button,'String','t must increase') else % All OK; Enable the Plot button with its original name set(handles.plot_button,'String','Plot') set(handles.plot_button,'Enable','on') return end % Found an input error other than a bad expression % Give the edit text box focus so user can correct the error uicontrol(hObject) catch EM % Cannot evaluate expression user typed set(handles.plot_button,'String','Cannot plot t') % Give the edit text box focus so user can correct the error uicontrol(hObject) end
The edit text callbacks execute when you enter text in an edit box and press Return or click elsewhere in the GUI. Even if you immediately clicks the Plot button, the edit text callback executes before the plot button callback activates. When a callback receives invalid input, it disables the Plot button, preventing its callback from running. Finally, it restores focus to itself, selecting the text that did not validate so that you can re-enter a value.
For example, here is the GUI's response to input of a time vector, [1 2 6 4 5 7 9], that does not monotonically increase.
In this figure, the two plots reflect the last successful set of inputs, f1 = 31.41, f2 = 120, and t = [1 2 3 4 5 7 9]. The time vector [1 2 6 4 5 7 9] appears highlighted so that you can enter a new, valid, value. The highlighting results from executing the command uicontrol(hObject) in the preceding code listing.
When you click the Plot button, the plot_button_Callback performs three basic tasks: it gets input from the edit text components, calculates data, and creates the two plots.
The first task for the plot_button_Callback is to read the input values. This involves:
Reading the current values in the three edit text boxes using the handles structure to access the edit text handles.
Converting the two frequency values (f1 and f2) from strings to doubles using str2double.
Evaluating the time string using eval to produce a vector t, which the callback used to evaluate the mathematical expression.
The following code shows how the plot_button_Callback obtains the input:
% Get user input from GUI f1 = str2double(get(handles.f1_input,'String')); f2 = str2double(get(handles.f2_input,'String')); t = eval(get(handles.t_input,'String'));
After constructing the string input parameters to numeric form and assigning them to local variables, the next step is to calculate data for the two graphs. The plot_button_Callback computes the time domain data using an expression of sines:
x = sin(2*pi*f1*t) + sin(2*pi*f2*t);
The callback computes the frequency domain data as the Fourier transform of the time domain data:
y = fft(x,512);
For an explanation of this computation, see the fft function.
The final task for the plot_button_Callback is to generate two plots. This involves:
Targeting plots to the appropriate axes. For example, this code directs a graph to the time axes:
Providing the appropriate data to the plot function
Turning on the axes grid, which the plot function automatically turns off
Note: Performing the last step is necessary because many plotting functions (including plot) clear the axes and reset properties before creating the graph. This means that you cannot use the Property Inspector to set the XMinorTick, YMinorTick, and grid properties in this example, because they are reset when the callback executes plot.
In the following code listing, notice how the handles structure provides access to the handle of the axes, when needed.
function plot_button_Callback(hObject, eventdata, handles, varargin) % hObject handle to plot_button (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get user input from GUI f1 = str2double(get(handles.f1_input,'String')); f2 = str2double(get(handles.f2_input,'String')); t = eval(get(handles.t_input,'String')); % Calculate data x = sin(2*pi*f1*t) + sin(2*pi*f2*t); y = fft(x,512); m = y.*conj(y)/512; f = 1000*(0:256)/512; % Create frequency plot in proper axes plot(handles.frequency_axes,f,m(1:257)) set(handles.frequency_axes,'XMinorTick','on') grid on % Create time plot in proper axes plot(handles.time_axes,t,x) set(handles.time_axes,'XMinorTick','on') grid on
Two GUI Options settings (accessed using Tools > Menu Options) are particularly important for this GUI:
Resize behavior: Proportional
Selecting Proportional as the resize behavior enables you to resize the GUI to better view the plots. Using this option setting, when you resize the GUI, everything expands or shrinks proportionately, except text.
Command-line accessibility: Callback
When GUIs include axes, their handles should be visible from other objects' callbacks. This enables you to use plotting commands like you would on the command line. Callback is the default setting for command-line accessibility.
For more information, see GUIDE Options.