Update gramm plot matlab crashing - matlab

I have a MATLAB GUI that calls an external function to make a plot (make_ethogram_plot).
The idea would be to have an external figure that is constantly updated with the output value from the figure. Every time the data gets updated it should replot the values, it updates at ~10 Hz. I chose gramm (https://github.com/piermorel/gramm/tree/master/%40gramm) because it is really easy to make a raster plot.
This is the function that gets called. I am having issues to
1) Make it only update in the parent figure with specific name, instead of plotting in the GUI(which is the active figure).
2) Make it not crash. It would open many figures or open or close the same figure at 10 Hz until crashing.
In this configuration, it gives error because it doesn't find g after the first plot. Making g , f, and p1 globals makes it crash (opens every time it gets called)
function make_ethogram_plot(datastructure)
% if the figure doesn't exists create it
if(isempty(findobj(0, 'Name', 'My_gramm_ethogram')))
f=figure('Name', 'My_gramm_ethogram');
p1 = uipanel('Parent',f,'BackgroundColor',[1 1 1],'BorderType','none');
g = gramm('x', datastructure.final_data.frameID, 'color', categorical(datastructure.final_data.behavior));
g.geom_raster();
g.set_parent(p1);
g.draw()
else
% defining f,p1, g here (or having them global) works but crashes
% due to refresh rate
g.update()
end
end

I wrote this code to try to replicate your problem:
function animate_random_data
N = 10000;
data = [cumsum(rand(N,1)),randn(N,1)];
for ii=0:1000
% Plot the data
make_ethogram_plot(data);
drawnow
% Compute new data
data(:,1) = cumsum(rand(N,1));
data(:,2) = randn(N,1);
end
function make_ethogram_plot(data)
fig = findobj(0, 'Name', 'My_gramm_ethogram');
if(isempty(fig))
% If the figure doesn't exists create it
fig = figure('Name', 'My_gramm_ethogram');
ax = axes(fig);
plot(ax,data(:,1),data(:,2));
drawnow
set(ax,'xlimmode','manual','ylimmode','manual');
else
% If it does, update it
line = findobj(fig,'type','line');
set(line,'xdata',data(:,1));
set(line,'ydata',data(:,2));
end
Here, I followed your concept of looking for a named figure window, and creating one if it didn't exist. However, if it does exist, I simply replace the XData and YData property of the line that is already there. This is the fastest way of animating a graph, much faster than deleting the existing plot and creating a new one. After plotting, I use drawnow to update the display. I set XLimMode and YLimMode to manual to prevent re-computation of axes limits and consequent re-drawing of the axes.
The function took 17 seconds to draw all 1000 frames, meaning it's drawing about 60 frames a second. It does not (and should not) crash MATLAB.
You can limit the display rate to 20 frames/sec with drawnow limitrate. It will skip updating the display if the frames come too fast.
I don't know what the gramm/update method does, the class is too complicated to quickly see what is going on, but I dare presume it deletes the axes and creates a new plot from scratch. Not that this should crash MATLAB, it might be worth while to submit a bug report. However, you would probably want to update the figure in the more efficient way, following the method I demonstrated above.
Note that this method can be used to update any of the graphical elements in a plot. For example, I have used this method to animate images.

Related

MATLAB Using a single figure frame for chasePlot used inside a loop

I have a while loop inside of which I have to use a plot and a chasePlot function.
The problem is, it comes up with a new window figure each time the loop runs. I somehow want a single frame which can be updated rather than each time making a new window and figure for it.
Anybody knows how to prevent a new figure in each loop so that one figure is there and that keeps on updating.
Don't use 'figure' before the 'plot' command and the code will keep overwriting every time on the same figure. You can also use the 'drawnow limitrate' command for better visualization. See an example below:
clc; close all; clear all;
x = 0 :100 :1e5;
y = zeros(size(x));
for n = 1:numel(x)
y(n) = sin(x(n));
plot(x(1:n), y(1:n));
drawnow limitrate;
end

How to plot several function calls in one figure

I made a matlab-function that plots a graph. When I call the function several times, I want it to plot all the graphs in one prepared figure. But instead my code opens with every function call the prepared figure in a new window with only one Graph in it.
My function looks like this
function myfunction(x,y)
if ~exist('myfigure')
myfigure = openfig('myfigure.fig')
assignin('base', 'myfigure',myfigure)
end
figure(myfigure);
plot(x,y)
end
With the if-function I tried to prevent it from opening a new figure-window, when myfigure is allready opened. But it seems like Matlab just ignores the if-function for my surprise. Even the Assignin didn't help out. Although checking in the command window, showed that exist('myfigure') changes its value.
I really don't know why the if-function is ignored by Matlab. Have you any suggestions how to fix this
The problem here is exist cannot see the previous figure, because it's handle is deleted when the previous call to the function was ended. My suggestion is as follow:
Pass the figure handle to the function, and also return it as output:
function myfigure = myfunction(x,y,myfigure)
if nargin<3 % if you pass 2 variables or less
myfigure = figure; % create a figure
else
figure(myfigure); % otherwise use the one in handle
end
plot(x,y)
end
Here a sample code for that:
x = 0:0.01:2*pi;
myfigure = myfunction(x,sin(x)); %first call
myfunction(x,cos(x),myfigure); % second call
myfunction(x,tan(x),myfigure); % third call...
Note that you only need to get myfunction output on the first call, then you can continue using it until you delete the figure.
The function figure that you used is probably why it opens a new figure.
What you might want to do is simply get the current axes and plot in it.
So your function would look like this
function myfunction(x,y)
myaxes = gca;
plot(myaxes,x,y)
end
This would work if you only have one active figure and axes, if you have more than you mihgt want to pass the axes handle to the function.

How to retrieve data from one gui to another gui in matlab?

I have two GUIs. In the first gui I want to plot an input signal (ex: sine signal). My problem is, how can I plot back the same signal in the second GUI after I clicked the 'load' pushbutton in the second GUI? Can somebody help me? I really need help.
Here is some code to get you going about using setappdata and getappdata. This is very basic and there are things which I did not mention (eg using the handles structure or passing variables as input arguments to functions) but using setappdata and getappdata is a safe way to go.
I created 2 programmatic GUIs. The code looks a bit different than when GUIs are designed with GUIDE, but the principle is exactly the same. Take the time to examine it and understand what everything does; that's not too complicated.
Each GUI is composed of one pushbutton and an axes. In the 1st GUI (sine_signal) the sine wave is created and displayed. Pressing the pushbutton opens the 2nd GUI (gui_filtering) and calls setappdata. Once you press the pushbutton of that 2nd GUI, setappdata is called to fetch the data and plot it.
Here is the code for both GUIs. You can save them as .m files and press "run" in the sine_signal function.
1) sine_signal
function sine_signal
clear
clc
%// Create figure and uicontrols. Those will be created with GUIDE in your
%// case.
hFig_sine = figure('Position',[500 500 400 400],'Name','sine_signal');
axes('Position',[.1 .1 .8 .8]);
uicontrol('Style','push','Position',[10 370 120 20],'String','Open gui_filtering','Callback',#(s,e) Opengui_filt);
%// Create values and plot them.
xvalues = 1:100;
yvalues = sin(xvalues).*cos(xvalues);
plot(xvalues,yvalues);
%// Put the x and y values together in a single array.
AllValues = [xvalues;yvalues];
%// Use setappdata to associate "AllValues" with the root directory (0).
%// This way the variable is available from anywhere. You could also
%// associate the data with the GUI itself, using "hFig_sine" instead of "0".
setappdata(0,'AllValues',AllValues);
%// Callback of the pushbutton. In this case it is simply used to open the
%// 2nd GUI.
function Opengui_filt
gui_filtering
end
end
And
2) gui_filtering
function gui_filtering
%// Same as 1st GUI.
figure('Position',[1000 1000 400 400],'Name','sine_signal')
axes('Position',[.1 .1 .8 .8])
%// Pushbutton to load data
uicontrol('Style','push','Position',[10 370 100 20],'String','Load/plot data','Callback',#(s,e) LoadData);
%// Callback of the pushbutton
function LoadData
%// Use "getappdata" to retrieve the variable "AllValues".
AllValues = getappdata(0,'AllValues');
%// Plot the data
plot(AllValues(1,:),AllValues(2,:))
end
end
To show you the expected output, here are 3 screenshots obtained when:
1) You run the 1st GUI (sine signal):
2) After pressing the pushbutton to open the 2nd GUI:
3) After pressing the pushbutton of the 2nd GUI to load/display the data:
That's about it. Hope that helps!

Ordinary Differential Equations in Matlab

Question -
I am working on some matlab code that solves 2 first degree differentials and 2 second order differentials. I am ok with dsolve() but when I want to plot I am currently using ezplot and it is not giving me what I want. I want to produce 1 window with four graphs. I know I would use subplot but I dont know how, an example would be nice. Also I dont know how to make my plots show the importiant area not just a large area. my code is below:
close all % close all figure windows that are open
clear all % clear all the variables currently stored in memory
clc % clear the commands in the command window
%%Problem 1%%%%%
a = (dsolve('Dv = -500*v+5000','v(0)=5'));
display (a)
b = (dsolve('Dx = -2000*x+100','x(0)=-.02'));
display (b)
%%Problem 2%%%%%
c = (dsolve('D2y+2000*Dy+26000000*y-520000000=0','Dy(0)=0','y(0)=5'));
display(c)
d = (dsolve('D2y+100*Dy+2500*y-520000000=0','Dy(0)=20','y(0)=0'));
display (d)
figure
ezplot(a);
axis([0,.01,4,10])
figure
ezplot(b);
axis([0,.01,0,10])
figure
ezplot(c);
axis([0,.01,4,10])
figure
ezplot(d);
axis([0,.01,4,10])
I didn't know until now, but it seems that ezplot only generates data points for "interesting part" of your plot. So if you specify the x-limit that ezplot does not use, you don't see anything. What you need to do is to specify the x-limits in its second argument of ezplot. Then, you can create subplots with standard suplot function, get axis handle, and specify the axis. The plotting part of your code should be like this.
figure
h1=subplot(2,2,1);
ezplot(a, [0,0.01]);
axis(h1,[0,0.01,4,10])
h2=subplot(2,2,2);
ezplot(b, [0,0.01]);
axis(h2,[0,.01,0,10])
h3=subplot(2,2,3);
ezplot(c, [0,0.01]);
axis(h3,[0,.01,4,10])
h4=subplot(2,2,4);
ezplot(d, [0,0.01]);
axis(h4,[0,.01,4,10])

MATLAB query about for loop, reading in data and plotting

I am a complete novice at using matlab and am trying to work out if there is a way of optimising my code. Essentially I have data from model outputs and I need to plot them using matlab. In addition I have reference data (with 95% confidence intervals) which I plot on the same graph to get a visual idea on how close the model outputs and reference data is.
In terms of the model outputs I have several thousand files (number sequentially) which I open in a loop and plot. The problem/question I have is whether I can preprocess the data and then plot later - to save time. The issue I seem to be having when I try this is that I have a legend which either does not appear or is inaccurate.
My code (apolgies if it not elegant):
fn= xlsread(['tbobserved' '.xls']);
time= fn(:,1);
totalreference=fn(:,4);
totalreferencelowerci=fn(:,6);
totalreferenceupperci=fn(:,7);
figure
plot(time,totalrefrence,'-', time, totalreferencelowerci,'--', time, totalreferenceupperci,'--');
xlabel('Year');
ylabel('Reference incidence per 100,000 population');
title ('Total');
clickableLegend('Observed reference data', 'Totalreferencelowerci', 'Totalreferenceupperci','Location','BestOutside');
xlim([1910 1970]);
hold on
start_sim=10000;
end_sim=10005;
h = zeros (1,1000);
for i=start_sim:end_sim %is there any way of doing this earlier to save time?
a=int2str(i);
incidenceFile =strcat('result_', 'Sim', '_', a, 'I_byCal_total.xls');
est_tot=importdata(incidenceFile, '\t', 1);
cal_tot=est_tot.data;
magnitude=1;
t1=cal_tot(:,1)+1750;
totalmodel=cal_tot(:,3)+cal_tot(:,5);
h(a)=plot(t1,totalmodel);
xlim([1910 1970]);
ylim([0 500]);
hold all
clickableLegend(h(a),a,'Location','BestOutside')
end
Essentially I was hoping to have a way of reading in the data and then plot later - ie. optimise the code.
I hope you might be able to help.
Thanks.
mp
Regarding your issue concerning
I have a legend which either does not
appear or is inaccurate.
have a look at the following extracts from your code.
...
h = zeros (1,1000);
...
a=int2str(i);
...
h(a)=plot(t1,totalmodel);
...
You are using a character array as index. Instead of h(a) you should use h(i). MATLAB seems to cast the character array a to double as shown in the following example with a = 10;.
>> double(int2str(10))
ans = 49 48
Instead of h(10) the plot handle will be assigned to h([49 48]) which is not your intention.