GUI That Accepts Parameters and Generates Plots

About the Example

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:

  1. 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
    
  2. 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.

GUI Design

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.

Default Values for Inputs

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 are created by setting the String property of the edit text. The following figure shows how the value was set for the time vector.

Identify the Axes

Since there are two axes in this GUI, you must specify which one you want to target when plotting data. Use the handles structure to access the target axes in your code. All fields in the handles structure are named according to each object's Tag property value. In this case, handles.frequency_axes returns the top axes, and the handles.time_axes returns the bottom axes.

Validate GUI Input as Numbers

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

Validate all three inputs are positive or negative real numbers

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.

Validate the Time Input Vector

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 click 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.

Plot Push Button Behavior

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.

Get Input

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'));

Calculate Data

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.

Plot Data

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:

    plot(handles.time_axes,t,x)
    
  • 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.

Plot_Button Callback

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

GUI Option Settings

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.

Was this topic helpful?