One out of two of my tabs will not respond and update after initial run of data acquisition
Show older comments
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
Connor
on 12 Apr 2024
Connor
on 12 Apr 2024
Voss
on 12 Apr 2024
I suspect a lot of the problems would go away if you follow the advice I gave in the last paragraph of my answer to your previous question, about a 1:1 correspondence between channels and lines:
Connor
on 12 Apr 2024
Voss
on 12 Apr 2024
Sounds good.
I'll offer some more advice while you are thinking about that, which is to try to forget about the code as it is now (at least the plot updating part) and think about how it would be if you had one line object per channel. For example, if you have 1:1 correspondence between channels and line objects, that plot updating function might be as simple as this:
function updateLivePlot(app)
% update the XData and YData of each line (whether its channel is selected or not)
for i = 1:size(app.UITable.Data,1)
set(app.LivePlotLine(i), 'XData', app.TimestampsFIFOBuffer, 'YData', app.DataFIFOBufferch1(:,i));
end
% update the axes x-limits
if numel(app.TimestampsFIFOBuffer) > 1
xlim(app.LiveAxes, app.TimestampsFIFOBuffer([1 end]));
end
end
Because the lines would already have all been created elsewhere (probably when the app starts), the legend would've been created elsewhere (probably when the app starts), and the lines' visibility would've been updated elsewhere (when the app starts and/or when a channel is selected or de-selected).
Note that that assumes that app.DataFIFOBufferch1 has the same number of columns as app.UITable.Data has rows - that is, one column for each channel (not only selected channels) - which I don't know is the case, and if not, then the 1:1 correspondence is not going to work. That is:
- if app.DataFIFOBufferch1 contains data from the selected channels only (not all channels), then something like what you are already doing - creating lines as needed, etc. - might be what you have to do. But
- if app.DataFIFOBufferch1 contains data from all channels (not only selected channels), then you can create all your lines in advance and the function that updates them can be simple.
Of course, I don't know what app.DataFIFOBufferch1 is, so I can't know the answer to that question.
Connor
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
on 12 Apr 2024
Accepted Answer
More Answers (0)
Categories
Find more on Legend in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!