One out of two of my tabs will not respond and update after initial run of data acquisition

1 view (last 30 days)
Within my app designer I have two tabs that both collect data. The first tab displays the data on one graph (as shown below)
the second tab displays the data on two graphs(as shown below)
both work fine on the first run but, when I try to change the graph postio, number of channels, calibration... nothing changes
(this is after pressing start and stop)
This problem is only happening with my second tab that displays multiple graphs and its not happening with my first tab that uses one graph.
The plotting functions for each are as follows:
Tab 1(one graph)
function updateLivePlot(app)
if isempty(app.DataFIFOBufferch1) || isempty(app.SelectedChannels)
return
end
% Disable interactivity
disableDefaultInteractivity(app.LiveAxes);
% Keep the colors the same after each new data point
app.LiveAxes.ColorOrderIndex = 1;
% % set the x,y axis and legends
xlabel(app.LiveAxes,"Time (s)")
ylabel(app.LiveAxes, app.Units)
% First-Time Setup
if isempty(app.LivePlotLine)
% Preallocate for efficiency
app.LivePlotLine = gobjects(size(app.UITable.Data(:,1)));
% Plot for the first time
for ii = 1:numel(app.SelectedChannels)
app.LivePlotLine(ii) = plot(app.LiveAxes, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:, ii));
end
% setting the leegnds to match the channels that are sleected
legend(app.LiveAxes,app.legnam(app.SelectedChannels))
else
% Update existing plot
for i = 1:numel(app.SelectedChannels)
% Check if the handle is still valid and within the bounds
if i <= numel(app.LivePlotLine) && ishandle(app.LivePlotLine(i))
% used to update the plotting
set(app.LivePlotLine(i), 'XData', app.TimestampsFIFOBuffer, 'YData', app.DataFIFOBufferch1(:,i));
hold(app.LiveAxes, "on")
else
% Re-plot if handle is invalid or out of bounds
app.LivePlotLine(i) = plot(app.LiveAxes, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:, i));
hold(app.LiveAxes, "on")
end
end
% setting the legend to match the channels that are selected
legend(app.LiveAxes,app.legnam(app.SelectedChannels))
end
if numel(app.TimestampsFIFOBuffer) > 1
xlim(app.LiveAxes, [app.TimestampsFIFOBuffer(1), app.TimestampsFIFOBuffer(end)]);
end
end
Tab 2 (2 graphs)
function updateLivePlot2(app)
disp(app.graphnums)
if isempty(app.DataFIFOBufferch1) || isempty(app.SelectedChannels)
return
end
% Disable interactivity
disableDefaultInteractivity(app.LiveAxes_2);
disableDefaultInteractivity(app.LiveAxes_3);
% Keep the colors the same after each new data point
app.LiveAxes_2.ColorOrderIndex = 1;
app.LiveAxes_3.ColorOrderIndex = 1;
% set the x,y axis and
xlabel(app.LiveAxes_2,"Time (s)")
ylabel(app.LiveAxes_2, app.Units)
% set the x,y axis and
xlabel(app.LiveAxes_3,"Time (s)")
ylabel(app.LiveAxes_3, app.Units)
% First-Time Setup
if isempty(app.LivePlotLine)
% Preallocate for efficiency
app.LivePlotLine = gobjects(size(app.UITable.Data(:,1)));
% Plot for the first time
for ii = 1:numel(app.SelectedChannels)
if app.graphnums(ii) == 1
app.LivePlotLine(ii) = plot(app.LiveAxes_2, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:, ii));
elseif app.graphnums(ii) == 2
app.LivePlotLine(ii) = plot(app.LiveAxes_3, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:, ii));
end
end
% setting the legnds to match the channels that are sleected
for iii = app.SelectedChannels
if app.graphnums(iii) == 1
legend(app.LiveAxes_2,app.legnam(app.SelectedChannels(iii)))
elseif app.graphnums(iii) == 2
legend(app.LiveAxes_3,app.legnam(app.SelectedChannels(iii)))
end
end
else
% Update existing plot
for i = 1:numel(app.SelectedChannels)
if app.graphnums(i) == 1
% Check if the handle is still valid and within the bounds
if i <= numel(app.LivePlotLine) && ishandle(app.LivePlotLine(i))
% used to update the plotting
set(app.LivePlotLine(i), 'XData', app.TimestampsFIFOBuffer, 'YData', app.DataFIFOBufferch1(:,i));
hold(app.LiveAxes_2, "on")
else
% Re-plot if handle is invalid or out of bounds
app.LivePlotLine(i) = plot(app.LiveAxes_2, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:,i));
hold(app.LiveAxes_2, "on")
end
elseif app.graphnums(i) == 2
if i <= numel(app.LivePlotLine) && ishandle(app.LivePlotLine(i))
% used to update the plotting
set(app.LivePlotLine(i), 'XData', app.TimestampsFIFOBuffer, 'YData', app.DataFIFOBufferch1(:,i));
hold(app.LiveAxes_3, "on")
else
% Re-plot if handle is invalid or out of bounds
app.LivePlotLine(i) = plot(app.LiveAxes_3, app.TimestampsFIFOBuffer, app.DataFIFOBufferch1(:, i));
hold(app.LiveAxes_3, "on")
end
end
end
% setting the legend to match the channels that are selected
% also checking to see which graph the legend is to go on
for iii = 1:numel(app.SelectedChannels)
if app.graphnums(iii) == 1
legend(app.LiveAxes_2,app.legnam(app.SelectedChannels(iii)))
elseif app.graphnums(iii) == 2
legend(app.LiveAxes_3,app.legnam(app.SelectedChannels(iii)))
end
end
end
if numel(app.TimestampsFIFOBuffer) > 1
xlim(app.LiveAxes_3, [app.TimestampsFIFOBuffer(1), app.TimestampsFIFOBuffer(end)]);
end
if numel(app.TimestampsFIFOBuffer) > 1
xlim(app.LiveAxes_2, [app.TimestampsFIFOBuffer(1), app.TimestampsFIFOBuffer(end)]);
end
end
The following is what I use to update the graphs from the UItable
try
tic
if app.tabstate == 1
% Update the Legends on the Axes based on the channel names with their default names and/or renamed names
app.legnam = table2array(app.UITable.Data(:,1));
% Update SelectedChannels based on ofchan
app.SelectedChannels = find(table2array(app.UITable.Data(:,2)));
% Update SelectedCal based on IndvCal
app.SelectedCal = find(table2array(app.UITable.Data(:,3)));
% checks which values have been checked (for error checking)
app.cals = table2array(app.UITable.Data(:,3));
% Call the function that uses the selected channels (e.g., data calibration)
updateChannelMeasurementComponents(app)
elseif app.tabstate == 2
% Update the Legends on the Axes based on the channel names with their default names and/or renamed names
app.legnam = table2array(app.UITable.Data(:,1));
% Update SelectedChannels based on ofchan
app.SelectedChannels = find(table2array(app.UITable.Data(:,2)));
% Update SelectedCal based on IndvCal
app.SelectedCal = find(table2array(app.UITable.Data(:,3)));
% checks which values have been checked (for error checking)
app.cals = table2array(app.UITable.Data(:,3));
app.graphnums = (table2array(app.UITable.Data(:,4)));
disp(app.graphnums)
assignin("base","graphnums",app.graphnums)
% Call the function that uses the selected channels (e.g., data calibration)
updateChannelMeasurementComponents(app)
end
toc
catch exception
%In case of error show it and revert the change
uialert(app.LiveDataAcquisitionUIFigure, exception.message, 'Selected channels too fast, Please press restore default buttons to avoid any other error and select channels at a slower speed. Thanks');
setAppViewState(app, 'configuration');
app.legnam = table2array(app.UITable.Data(:,1));
app.SelectedChannels = find(table2array(app.UITable.Data(:,2)));
app.SelectedCal = find(table2array(app.UITable.Data(:,3)));
app.cals = table2array(app.UITable.Data(:,3));
app.graphnums = (table2array(app.UITable.Data(:,4)));
end
After using breakpoints and the debugging tool I can see that it is reading in the new values which is leaving me quite confued on what the problem might be. I also was having difficulty with setting up the multiple graphs, any and all help is appreciated!
  9 Comments
Voss
Voss on 12 Apr 2024
Edited: Voss on 12 Apr 2024
"I am not quite sure what you mean when you say the lines would be created elsewhere."
Basically your code would create the lines as soon as its known how many channels you have. That may be in the startup function of your app. Or if the number of channels can change while the app is running, then it might be in some function that updates what needs to be updated when the number of channels changes, adding or deleting lines as necessary.
"I have also had to put the legend within the update plotting function"
I'm pretty sure legends can update themselves automatically when lines are created/deleted/made visible/made invisible. The lines' DisplayName is what will show up in the legend, so as long as that is set correctly for each line, the legend would update properly automatically.
If I had your app, I could maybe offer more specific advice or fix up the code a bit, but I'm not sure I'd be able to run/adapt it since I don't have the Data Acquisition Toolbox. What I'll do instead is put together an example app that illustrates how I think your app should run and post an answer with that app. It might be a few hours before I can have it done. In the meantime, try to do what you can.
Connor
Connor on 12 Apr 2024
Thanks, I appreciate it alot! I have attached my app file, not sure if you will be able to run it but I hope it can help in someway.

Sign in to comment.

Accepted Answer

Voss
Voss on 12 Apr 2024
Edited: Voss on 12 Apr 2024
I'm attaching an app that does kind of a simplified version of what I think your app is meant to do.
You can select from multiple devices, select and deselect channels, change the names of the channels, switch between the single plot tab and dual plot tab, and change whether each channel is plotted in the top axes or the bottom axes in the dual plot tab (double-click in the third column of the table to see the embedded dropdown), all of which is similar to how your app functions. However, I don't have the Data Acquisition Toolbox, so in this app you have to click the "Get (More) Data" button to "acquire" and plot new data.
The idea behind the design of the code is that as soon as the user does anything, whatever needs to be updated is updated immediately. This may be different than how you designed your app (I don't know because I didn't look into it beyond to get the gist of what it does), but in my opinion it makes for a more robust app because you're basically guaranteeing (ideally) that the app is never in a self-inconsistent state. I think your app gets into some self-inconsistent state(s) somehow or other because of how things are updated, and that's ultimately what's causing the problems you've been seeing.
Anyway, please run the attached app, and mess around with it - make sure it behaves like yours is supposed to - and then investigate the code, and try to apply some of the same principles to your app. Let me know if you have any questions.

More Answers (0)

Categories

Find more on Simultaneous and Synchronized Operations in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

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

Start Hunting!