Synchronized Data Presentations in a GUIDE GUI

About the Example

This example shows how to program a GUI that has the following features:

  • Initializes a table and a plot.

  • Plots selected data in real time as you select data observations.

  • Generates line graphs that display different views of data.

This GUI plots different kinds of graphs into different axes for an entire data set or selections of it, and shows how Fourier transforms can identify periodicity in time series data.

You can use this GUI to analyze and visualize time-series data containing periodic events.

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 with the following commands:

    copyfile(fullfile(docroot, 'techdoc','creating_guis',...
    'examples','tablestat*.*')), fileattrib('tablestat*.*', '+w');
    guide tablestat.fig;
    
  2. In the GUIDE Layout Editor, click the Editor button .

    The tablestat.m code file opens in the MATLAB® Editor.

Recreate the GUI

In the GUIDE Layout Editor, the tablestat GUI looks like this.

Perform the following steps in GUIDE and in the Property Inspector to generate the layout:

  1. In the Command Window, type guide, select the Blank GUI template, and then click OK.

  2. Use the Panel tool, , to drag out the three uipanels into the positions shown above. Keep the defaults for their Tag properties (which are uipanel1, uipanel2, and uipanel3). Create, in order:

    1. A long panel on the left. In the Property Inspector, set its Title property value to Data Set.

    2. A panel on the lower right, half the height of the first panel. In the Property Inspector, set its Title property value to Data Statistics.

      renaming its Title to in the Property Inspector.

    3. A panel above the Data Statistics panel. In the Property Inspector, set its Title property to Sunspots v. Year Plots. This panel changes its name when the type of plot changes.

  3. Use the Table tool, , to drag a uitable inside the Data Set panel. Use the Property Inspector to set the property values as follows:

    • ColumnName: Year and Sunspot.

    • Data: As described in Initialize the Data Table.

    • Tag: data_table.

    • TooltipString: Drag to select a range of 11 or more observations.

    • CellSelectionCallback: data_table_CellSelectionCallback.

      Click the pencil-and-paper icon to have GUIDE set this property value automatically and declare it in the code file.

  4. Drag a second uitable inside the Data Statistics panel. Use the Table Property Editor to set row values as follows:

    1. Double-click the Data Statistics table to open it in the Property Inspector.

    2. In the Property Inspector, click the Table Property Editor icon to the right of the RowName property to open the Table Property Editor.

    3. In the Table Property Editor, select Rows from the list in the left-hand column.

    4. Select the bottom radio button, Show names entered below as row headers.

    5. Type the nine strings listed in order on separate lines in the data entry pane, and then click OK.

      • BackgroundColor: yellow (using the color picker).

      • ColumnName: Population and Selection.

      • Tag: data_stats.

      • TooltipString: statistics for table and selection.

      • RowNameto nine strings: N, Min, Max, Mean, Median, Std Dev, 1st Year, Last Year, and Est. Period.

        The Table Property Editor looks like this before you close it.

    The Data Statistics table does not use any callbacks.

  5. Use the Axes tool to drag out an axes within the top half of the Sunspots v. Year Plots panel, leaving its name as axes1.

  6. Drag out a second axes, leaving its name as axes2 inside the Sunspots v. Year Plots panel, directly below the first axes.

    Leave enough space below each axes to display the x-axis labels.

  7. Identify the axes with labels. Using the Text tool, drag out a small rectangle in the upper right corner of the upper axes (axes1). Double-click it, and in the Property Inspector, change its String property to Population and its Tag property to poplabel.

  8. Place a second label in the lower axes (axes2), renaming this text object Selection and setting its Tag property to sellabel.

  9. Create a title for the GUI. Using the Text tool, drag out a static text object at the top left of the GUI, above the data table. Double-click it, and in the Property Inspector, change its String property to "Zurich" Sunspot Statistics, 1700-1987 and its FontWeight property to bold.

  10. Add a prompt above the axes; place a text label just above the Sunspots v. Year Plots panel, near its right edge. Change its Tag property to newfig, its String property to Right-click plots for larger view and its FontAngle property to Italic.

  11. Make a pop-up menu to specify the type of graph to plot. Using the Pop-up Menu tool , drag out a pop-up menu just above the Sunspots v. Year panel, aligning it to the panel's left edge. In the Property Inspector, set these properties:

    • String:

      Sunspots v. Year Plots
      FFT Periodogram Plots
    • Tag: plot_type

    • Tooltip: Choose type of data plot

    Then, click the Callback property's icon. This creates a declaration called plot_type_Callback, to which you add code later on.

  12. Select the Push Button tool , and drag out a push button in the upper right of the figure. In the Property Inspector, rename it to Quit and set up its callback as follows:

    • Double-click it and in the Property Inspector, set its Tag property to quit and its String property to Quit.

    • Click the Callback property to create a callback for the button in the code file tablestat.m. GUIDE sets the Callback of the Quit item to quit_Callback.

    • In the code file, for the quit_Callback function. enter:

      close(ancestor(hObject,'figure'))
  13. Save the GUI in GUIDE, naming it tablestat.fig. This action also saves the code file as tablestat.m.

Initialize the Data Table

Although you can use the Opening Function to load data into a table, this example uses GUIDE to put data into the Data Set table. This way, the data becomes part of the figure after you save it. Initializing the table data causes the table to have the same number of rows and columns as the variable that it contains:

  1. Access the sunspot example data set. In the Command Window, type:

    load sunspot.dat

    The variable sunspot, a 288-by-2 double array, displays in the MATLAB workspace.

  2. Open the Property Inspector for the data table by double-clicking the Data Set table.

  3. In the Property Inspector, click the Table Editor icon to the right of the Data property to open the Table Property Editor.

  4. In the Table Property Editor, select Table from the list in the left-hand column.

  5. Select the bottom radio button, Change data value to the selected workspace variable below.

  6. From the list of workspace variables in the box below the radio button, select sunspot and click OK.

GUIDE inserts the sunspot data in the table.

Compute the Data Statistics

The Opening Function retrieves the preloaded data from the data table and calls the local function, setStats, to compute population statistics, and then returns them. The data_table_CellSelectionCallback performs the same action when you select more than 10 rows of the data table. The only difference between these two calls is what input data is provided and what column of the Data Statistics table is computed. Here is the setStats function:

function stats = setStats(table, stats, col, peak)
% Computes basic statistics for data table.
%   table  The data to summarize (a population or selection)
%   stats  Array of statistics to update
%   col    Which column of the array to update
%   peak   Value for the peak period, computed externally

stats{1,col} =   size(table,1);      % Number of rows
stats{2,col} =    min(table(:,2));
stats{3,col} =    max(table(:,2));
stats{4,col} =   mean(table(:,2));
stats{5,col} = median(table(:,2));
stats{6,col} =    std(table(:,2));
stats{7,col} =        table(1,1);    % First row
stats{8,col} =        table(end,1);  % Last row
if ~isempty(peak)
    stats{9,col} = peak;             % Peak period from FFT
end

    Note:   When assigning data to a uitable, use a cell array, as shown in the code for setStats. You can assign data that you retrieve from a uitable to a numeric array, however, only if it is entirely numeric. Storing uitable data in cell arrays enables tables to hold numbers, strings of characters, or combinations of them.

The stats matrix is a 9-by-2 cell array in which each row is a separate statistic computed from the table argument. The last statistic is not computed by setStats; it comes from the plotPeriod function when it computes and plots the FFT periodogram and is passed to setStats as the peak parameter.

Specify the Type of Data Plot

From the GUI, you can choose either of two types of plots to display from the plot_type pop-up menu:

  • Sunspots v. Year Plots — Time-series line graphs displaying sunspot occurrences year by year (default).

  • Periodogram Plots — Graphs displaying the FFT-derived power spectrum of sunspot occurrences by length of cycle in years.

When the plot type changes, one or both axes refresh. They always show the same kind of plot, but the bottom axes is initially empty and does not display a graph until you select at least 11 rows of the data table.

The plot_type control callback is plot_type_Callback. GUIDE generates it, and you must add code to it that updates plots appropriately. In the example, the callback consists of this code:

function plot_type_Callback(hObject, eventdata, handles)
% hObject    handle to plot_type (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% ---- Customized as follows ----
% Determine state of the pop-up and assign the appropriate string
% to the plot panel label
index = get(hObject,'Value');    % What plot type is requested?
strlist = get(hObject,'String');        % Get the choice's name
set(handles.uipanel3,'Title',strlist(index))  % Rename uipanel3

% Plot one axes at a time, changing data; first the population
table = get(handles.data_table,'Data'); % Obtain the data table
refreshDisplays(table, handles, 1)

% Now compute stats for and plot the selection, if needed.
% Retrieve the stored event data for the last selection
selection = handles.currSelection;
if length(selection) > 10  % If more than 10 rows selected
    refreshDisplays(table(selection,:), handles, 2)
else
    % Do nothing; insufficient observations for statistics
end

The function updates the Data Statistics table and the plots. To perform the updates, it calls the refreshDisplays function twice, which is a custom function added to the GUI code file. In between the two calls, the refreshDisplays function retrieves row indices for the current selection from the currSelection member of the handles structure, where they were cached by the data_table_CellSelectionCallback.

You can see the effect of toggling the plot type in the two illustrations that follow. The one on the left shows the Sunspots v. Year plots, and the one on the right shows the FFT Periodograms Plots. The selection in both cases is the years 1901–1950.

Respond to Data Selections

The Data Set table has two columns: Year and Sunspots. The data tables's Cell Selection Callback analyzes data from its second column, regardless of which columns you highlight. The setStats function (not generated by GUIDE) computes summary statistics observations from the second column for insertion into the Data Statistics table on the right. The plotPeriod function (not generated by GUIDE) plots either the raw data or a Fourier analysis of it.

The data_table_CellSelectionCallback function manages the application's response to you selecting ranges of data. Ranges can be contiguous rows or separate groups of rows; holding down the Ctrl key lets you add discontiguous rows to a selection. Because the Cell Selection Callback is triggered as long as you hold the left mouse button down within the table, the selection statistics and lower plot are refreshed until selection is completed.

Selection data is generated during mouseDown events (mouse drags in the data table). The uitable passes this stream of cell indices (but not cell values) via the eventdata structure to the data_table_CellSelectionCallback callback. The callback's code reads the indices from the Indices member of the eventdata.

When the callback runs (for each new value of eventdata), it turns the event data into a set of rows:

selection = eventdata.Indices(:,1);
selection = unique(selection);

The event data contains a sequence of [row, column] indices for each table cell currently selected, one cell per line. The preceding code trims the list of indices to a list of selected rows, removing column indices. Then it calls the unique MATLAB function to eliminate any duplicate row entries, which arise whenever you select both columns. For example, suppose eventdata.Indices contains:

 1    1
 2    1
 3    1
 3    2
 4    2

This indicates that you selected the first three rows in column one (Year) and rows three and four in column two (Sunspots) by holding down the Ctrl key when selecting numbers in the second column. The preceding code transforms the indices into this vector:

1
2
3
4

This vector enumerates all the selected rows. If the selection includes less than 11 rows (as it does here) the callback returns, because computing statistics for a sample that small is not useful.

When the selection contains 11 or more rows, the data table is obtained, the selection is cached in the handles structure, and the refreshDisplays function is called to update the selection statistics and plot, passing the portion of the table that you selected:

table = get(hObject,'Data');
handles.currSelection = selection;
guidata(hObject,handles)
refreshDisplays(table(selection,:), handles, 2)

Caching the list of rows in the selection is necessary because changing plot types can force selection data to be replotted. As the plot_type_Callback has no access to the data table's event data, it requires a copy of the most recent selection.

Update the Statistics Table and the Graphs

The code must update the Data Statistics table and the graphs above it when:

  • The GUI is initialized, in its tablestat_OpeningFcn.

  • You select cells in the data table, in its data_table_CellSelectionCallback.

  • You select a different plot type, in the plot_type_Callback.

In each case, the refreshDisplays function is called to handle the updates. It in turn calls two other custom functions:

  • setStats — Computes summary statistics for the selection and returns them.

  • plotPeriod — Plots the type of graph currently requested in the appropriate axes.

The refreshDisplays function identifies the current plot type and specifies the axes to plot graphs into. After calling plotPeriod and setStats, it updates the Data Statistics table with the recomputed statistics. Here is the code for refreshDisplays:

function refreshDisplays(table, handles, item)
if isequal(item,1)
    ax = handles.axes1;
elseif isequal(item,2)
    ax = handles.axes2;
end
peak = plotPeriod(ax, table,...
              get(handles.plot_type,'Value'));
stats = get(handles.data_stats, 'Data');
stats = setStats(table, stats, item, peak);
set(handles.data_stats, 'Data', stats);
set(ax,'FontSize',7.0);

If you are reading this document in the MATLAB Help Browser, click the names of the functions underlined above to see their complete code (including comments) in the MATLAB Editor.

Display Graphs in New Figure Windows

The tablestat GUI contains code to display either of its graphs in a larger size in a new figure window when you right-click either axes and selects the pop-up menu item, Open plot in new window. The static text string (tagged newfig) above the plot panel, Right-click plots for larger view, informs you that this feature is available.

The axes respond by:

  1. Creating a new figure window.

  2. Copying their contents to a new axes parented to the new figure.

  3. Resizing the new axes to use 90% of the figure's width.

  4. Constructing a title string and displaying it in the new figure.

  5. Saving the figure and axes handles in the handles structure for possible later use or destruction.

      Note:   Handles are saved for both plots, but each time a new figure is created for either of them, the new handles replace the old ones, if any, making previous figures inaccessible from the GUI.

Create Two Context Menus.  To create the two context menus, from the GUIDE Tools menu, select the Menu Editor. After you create the two context menus, attach one to the each axes, axes1 and axes2. In the Menu Editor, for each menu:

  1. Click the Context Menus tab to select the type of menu you are creating.

  2. Click the New Context Menu icon .

    This creates a context menu in the Menu Editor workspace called untitled. It has no menu items and is not attached to any GUI object yet.

  3. Select the new menu and in the Tag edit field in the Menu Properties panel, type plot_axes1.

  4. Click the New Menu Item icon .

    A menu item is displayed underneath the plot_axes1 item in the Menu Editor workspace.

  5. In the Menu Properties panel, type Open plot in new window for Label and plot_ax1 for Tag. Do not set anything else for this item.

  6. Repeat the last four steps to create a second context menu:

    • Make the Tag for the menu plot_axes2.

    • Create a menu item under it and make its Label Open plot in new window and assign it a Tag of plot_ax2.

  7. Click OK to save your menus and exit the Menu Editor.

For more information about using the Menu Editor, see Create Menus for GUIDE GUIs.

Attach Context Menus to Axes.  Add the context menus you just created to the axes:

  1. In the GUIDE Layout Editor, double-click axes1 (the top axes in the upper right corner) to open it in the Property Inspector.

  2. Click the right-hand column next to UIContextMenu to see a drop-down list.

  3. From the list, select plot_axes1.

Perform the same steps for axes2, but select plot_axes2 as its UIContextMenu.

Code Context Menu Callbacks.  The two context menu items perform the same actions, but create different objects. Each has its own callback. Here is the plot_ax1_Callback callback for axes1:

function plot_ax1_Callback(hObject, eventdata, handles)
% hObject    handle to plot_ax1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
%
% Displays contents of axes1 at larger size in a new figure

% Create a figure to receive this axes' data
axes1fig = figure;
% Copy the axes and size it to the figure
axes1copy = copyobj(handles.axes1,axes1fig);
set(axes1copy,'Units','Normalized',...
              'Position',[.05,.20,.90,.60])
% Assemble a title for this new figure
str = [get(handles.uipanel3,'Title') ' for ' ...
       get(handles.poplabel,'String')];
title(str,'Fontweight','bold')
% Save handles to new fig and axes in case
% we want to do anything else to them
handles.axes1fig = axes1fig;
handles.axes1copy = axes1copy;
guidata(hObject,handles);

The other callback, plot_ax2_Callback, is identical to plot_ax1_Callback, except that all instances of 1 in the code are replaced by 2, and poplabel is replaced with sellabel. The poplabel and sellabel objects are the Population and Selection labels on axes1 and axes2, respectively. These strings are appended to the current Title for uipanel3 to create a title for the plot in the new figure axes1fig or axes2fig.

Use Plot in New Window Feature.  Whenever you right-click one of the axes in the GUI and select Open plot in new window, a new figure is generated containing the graph in the axes. The callbacks do not check whether a graph exists in the axes (axes2 is empty until you select cells in the Data Set) or whether a previously opened figure contains the same graph. A new figure is always created and the contents of axes1 or axes2 are copied into it. For example, you could right-click a periodogram in axes1 and select Open plot in new window.

It is your responsibility to remove the new window when it is no longer needed. The context menus can be programmed to do this. Because their callbacks call guidata to save the handle of the last figure created for each of the GUI's axes, another callback can delete or reuse either figure. For example, the plot_ax1_Callback and plot_ax2_Callback callbacks could check guidata for a valid axes handle stored in handles.axes1copy or handles.axes2copy, and reuse the axes instead of creating a new figure.

Related Examples

Was this topic helpful?