I have a 576x576x150 matrix. Each 576x576 set represents an image. When I want to plot one frame I do it by using the plot command:
figure(1);
imshow(B(:,:,45),[]) % plots frame 45
title('45') % tells frame number
However I would like to add a slider to the plot, so I can move from 1-150 frame within the figure.I've seen examples of people using uicontrol but I don't know how to code it. In addition to that, I would like to have a title on top of the figure telling me the frame number.
Here is how I do it. I like to keep a single function that does the plotting so you don't recycle commands elsewhere. You could replace the first two lines by function test(B) to use you own B matrix. This code is pretty easy to extend. You will also want to play with the layout to suit your purpose.
function test
B=rand(576,576,150);
fig=figure(100);
set(fig,'Name','Image','Toolbar','figure',...
'NumberTitle','off')
% Create an axes to plot in
axes('Position',[.15 .05 .7 .9]);
% sliders for epsilon and lambda
slider1_handle=uicontrol(fig,'Style','slider','Max',150,'Min',1,...
'Value',2,'SliderStep',[1/(150-1) 10/(150-1)],...
'Units','normalized','Position',[.02 .02 .14 .05]);
uicontrol(fig,'Style','text','Units','normalized','Position',[.02 .07 .14 .04],...
'String','Choose frame');
% Set up callbacks
vars=struct('slider1_handle',slider1_handle,'B',B);
set(slider1_handle,'Callback',{#slider1_callback,vars});
plotterfcn(vars)
% End of main file
% Callback subfunctions to support UI actions
function slider1_callback(~,~,vars)
% Run slider1 which controls value of epsilon
plotterfcn(vars)
function plotterfcn(vars)
% Plots the image
imshow(vars.B(:,:,get(vars.slider1_handle,'Value')));
title(num2str(get(vars.slider1_handle,'Value')));
The idea is to use uicontrol() to enable sliding/scrolling.
The following code is for scrolling (created by Evan Brooks, you can modify it to sliding):
function scrollfigdemo
% create new figure window
f = figure;
set(f,'doublebuffer', 'on', 'resize', 'off')
% set columns of plots
cols = 2;
% create 5 data sets to plot
x=0:1e-2:2*pi;
y{1}=sin(x);
y{2}=cos(x);
y{3}=tan(x);
y{4}=x.^2;
y{5}=x.^3;
% determine required rows of plots
rows = ceil(length(y)/cols);
% increase figure width for additional axes
fpos = get(gcf, 'position');
scrnsz = get(0, 'screensize');
fwidth = min([fpos(3)*cols, scrnsz(3)-20]);
fheight = fwidth/cols*.75; % maintain aspect ratio
set(gcf, 'position', [10 fpos(2) fwidth fheight])
% setup all axes
buf = .15/cols; % buffer between axes & between left edge of figure and axes
awidth = (1-buf*cols-.08/cols)/cols; % width of all axes
aidx = 1;
rowidx = 0;
while aidx <= length(y)
for i = 0:cols-1
if aidx+i <= length(y)
start = buf + buf*i + awidth*i;
apos{aidx+i} = [start 1-rowidx-.92 awidth .85];
a{aidx+i} = axes('position', apos{aidx+i});
end
end
rowidx = rowidx + 1; % increment row
aidx = aidx + cols; % increment index of axes
end
% make plots
axes(a{1}), plot(x,y{1}), title('sine'), xlabel('x'), ylabel('sin(x)')
axes(a{2}), plot(x,y{2}), title('cosine'), xlabel('x'), ylabel('cos(x)')
axes(a{3}), plot(x,y{3}), title('tangent'), xlabel('x'), ylabel('tan(x)')
axes(a{4}), plot(x,y{4}), title('x^2'), xlabel('x'), ylabel('x^2')
axes(a{5}), plot(x,y{5}), title('x^3'), xlabel('x'), ylabel('x^3')
% determine the position of the scrollbar & its limits
swidth = max([.03/cols, 16/scrnsz(3)]);
ypos = [1-swidth 0 swidth 1];
ymax = 0;
ymin = -1*(rows-1);
% build the callback that will be executed on scrolling
clbk = '';
for i = 1:length(a)
line = ['set(',num2str(a{i},'%.13f'),',''position'',[', ...
num2str(apos{i}(1)),' ',num2str(apos{i}(2)),'-get(gcbo,''value'') ', num2str(apos{i}(3)), ...
' ', num2str(apos{i}(4)),'])'];
if i ~= length(a)
line = [line,','];
end
clbk = [clbk,line];
end
% create the slider
uicontrol('style','slider', ...
'units','normalized','position',ypos, ...
'callback',clbk,'min',ymin,'max',ymax,'value',0);
Related
This is part of the code the makes the video:
k = 10000;
j = 1;
v = VideoWriter('myVideo.avi');
open(v)
while j < k
axis([0 5 0 1000]);
plot(0:dr:R, u_sol_matrix(:,j))
frame = getframe(gcf);
writeVideo(v,frame);
j = j + 50;
% pause(0.01)
end
close(v)
Now, given a matrix u_sol_matrix, where every column represents a solution for a PDE at a certain time point, I plot the solutions and the by the getframe command capture these plots and make a movie out of it.
The problem is that the axis keeps changing as the plot keeps adjusting to the solution. I want the axis to be constant. How do I get this to work? I have tried adding axis but this does not work apparently.
k = 10000;
j = 1;
v = VideoWriter('myVideo.avi');
open(v)
while j < k
fig = figure(); % Explicitly create figure
plot(0:dr:R, u_sol_matrix(:,j))
axis([0 5 0 1000]); % first plot, then change axis
frame = getframe(gcf);
writeVideo(v,frame);
close(fig) % close figure explicitly.
j = j + 50;
% pause(0.01)
end
close(v)
Flipping the figure creation and setting axis limits should do the trick. When you call axis without an open figure, MATLAB creates one, only to overwrite it if you don't call hold on, thus changing the limits to whatever the plot "needs" to fit.
Like Adriaan answered, you just have to flip the order of plotting and setting axis limits to make this work.
However, when creating animations, it is faster to first initialize a figure and the graphics objects (i.e. lines, scatter points, etc.), and later update the data in a loop.
k = 10000;
j = 1;
v = VideoWriter('myVideo.avi');
open(v)
% some test data
x = 10;
y = sin(1:k);
% init a figure and plot handles
fig = figure(1);
p = plot(x, y(1), 'o'); % create line object, and store the handle
axis([9 11 -1 1]) % axis limits for test data
% update data during animation
while j < k
p.XData = x; % update X and Y data properties of line object
p.YData = y(j);
frame = getframe(gcf);
writeVideo(v,frame);
j = j + 50;
pause(0.01)
end
close(v)
Since you don't have to create a new line primitive each loop iteration, this will save a lot of time. You only have to adjust the X and Y data properties of the already existing line, which has considerable less overhead.
I want to plot y=omega*x^2, which omega is -3 into 3 with step size 0.25, x from -4 into 4 with step size 0.001. But this code give me the curve is cannot moving and axes is moving. I want the curve is moving, like this.
x=-4:0.001:4;
for omega=-3:0.25:3
for i=1:length(x)
y(i)=omega*x(i)^2;
end
plot(x,y);
pause(0.1);
end
How to do that?
As another answer has indicated, you need to set the axis limits.
(Also note that there is no reason to calculate y using a loop.)
But instead of using plot every time through the loop it's more efficient to create the line only once, and then replace the x and y data of the line each time through the loop.
x=-4:0.001:4;
all_omega=-3:0.25:3;
for idx = 1:numel(all_omega)
omega = all_omega(idx);
y=omega*(x.^2);
if idx == 1
% create line
hl = plot(x,y);
axis([-4,4,-40,40]);
box on
grid on
else
% replace line data
set(hl,'XData',x,'YData',y);
end
title(sprintf('\\Omega = %.2f',omega));
pause(0.1);
end
Or you might want to use animatedline,
x=-4:0.001:4;
all_omega=-3:0.25:3;
for idx = 1:numel(all_omega)
omega = all_omega(idx);
y=omega*(x.^2);
if idx == 1
% create animated line
am = animatedline(x,y);
axis([-4,4,-40,40]);
box on
grid on
else
% replace the line
clearpoints(am)
addpoints(am,x,y);
end
title(sprintf('\\Omega = %.2f',omega));
pause(0.1);
end
A quick method is setting the x- and y-axes limits in the loop after each plot, using the axis([xmin, xmax, ymin, ymax]) command. This method isn't foolproof, in the case that the script gets help up after plotting but before setting the axes limits, but in most cases it should work.
figure(1)
x=-4:0.001:4;
for omega=-3:0.25:3
for i=1:length(x)
y(i)=omega*x(i)^2;
end
plot(x,y);
axis([-4 4 -50 50])
pause(0.1);
end
This is the same as #phil-goddard's answer, but makes more efficient use of handles to the animated YData and title string.
x = -4 : 0.001 : 4;
y = zeros(1, numel(x));
omega_range = -3 : 0.25 : 3;
% Create line and title, and obtain handles to them.
h_plot = plot(x, y);
axis([-4, 4, -40, 40]);
box on;
grid on;
h_title = title(sprintf('\\omega = %.2f', 0));
for idx = 1:numel(omega_range)
omega = omega_range(idx);
y = omega * (x.^2);
% Replace y data.
h_plot.YData = y;
% Replace title string.
h_title.String = sprintf('\\omega = %.2f', omega);
pause(0.1);
end
Suppose I have a 5x5 matrix.
The elements of the matrix change (are refreshed) every second.
I would like to be able to display the matrix (not as a colormap but with the actual values in a grid) in realtime and watch the values in it change as time progresses.
How would I go about doing so in MATLAB?
A combination of clc and disp is the easiest approach (as answered by Tim), here's a "prettier" approach you might fancy, depending on your needs. This is not going to be as quick, but you might find some benefits, such as not having to clear the command window or being able to colour-code and save the figs.
Using dispMatrixInFig (code at the bottom of this answer) you can view the matrix in a figure window (or unique figure windows) at each stage.
Example test code:
fig = figure;
% Loop 10 times, pausing for 1sec each loop, display matrix
for i=1:10
A = rand(5, 5);
dispMatrixInFig(A,fig)
pause(1)
end
Output for one iteration:
Commented function code:
function dispMatrixInFig(A, fig, strstyle, figname)
%% Given a figure "fig" and a matrix "A", the matrix is displayed in the
% figure. If no figure is supplied then a new one is created.
%
% strstyle is optional to specify the string display of each value, for
% details see SPRINTF. Default is 4d.p. Can set to default by passing '' or
% no argument.
%
% figname will appear in the title bar of the figure.
if nargin < 2
fig = figure;
else
clf(fig);
end
if nargin < 3 || strcmp(strstyle, '')
strstyle = '%3.4f';
end
if nargin < 4
figname = '';
end
% Get size of matrix
[m,n] = size(A);
% Turn axes off, set origin to top left
axis off;
axis ij;
set(fig,'DefaultTextFontName','courier', ...
'DefaultTextHorizontalAlignment','left', ...
'DefaultTextVerticalAlignment','bottom', ...
'DefaultTextClipping','on');
fig.Name = figname;
axis([1, m-1, 1, n]);
drawnow
tmp = text(.5,.5,'t');
% height and width of character
ext = get(tmp, 'Extent');
dy = ext(4);
wch = ext(3);
dwc = 2*wch;
dx = 8*wch + dwc;
% set matrix values to fig positions
x = 1;
for i = 1:n
y = 0.5 + dy/2;
for j = 1:m
y = y + 1;
text(x,y,sprintf(strstyle,A(j,i)));
end
x = x + dx;
end
% Tidy up display
axis([1-dwc/2 1+n*dx-dwc/2 1 m+1]);
set(gca, 'YTick', [], 'XTickLabel',[],'Visible','on');
set(gca,'XTick',(1-dwc/2):dx:x);
set(gca,'XGrid','on','GridLineStyle','-');
end
I would have thought you could achieve this with disp:
for i=1:10
A = rand(5, 5);
disp(A);
end
If you mean that you don't want repeated outputs on top of each other in the console, you could include a clc to clear the console before each disp call:
for i=1:10
A = rand(5, 5);
clc;
disp(A);
end
If you want to display your matrix on a figure it is quite easy. Just make a dump matrix and display it. Then use text function to display your matrix on the figure. For example
randMatrix=rand(5);
figure,imagesc(ones(20));axis image;
hold on;text(2,10,num2str(randMatrix))
If you want to do it in a for loop and see the numbers change, try this:
for i=1:100;
randMatrix=rand(5);
figure(1),clf
imagesc(ones(20));axis image;
hold on;text(2,10,num2str(randMatrix));
drawnow;
end
I have script handling figures so that I can print and input them in a latex document with scale = 1 and everything looks nice.
In this context I want to save the figure, axes and legend handles.
Is there a way to save them like when using fig = figure. I know two 'hacks'
1)
nfig = nfig+1; fig = figure(nfig);
plot()
ax = gca
leg = legend()
2)
nfig = nfig+1; fig = figure(nfig);
ax = subplot(1,1,1)
plot()
leg = legend()
My script
function fig_set(fig,ax,leg,width,heigth,font_size)
%% fig_set removes borders and set witdth and height of figure
%
% The function fig_set sets the border of a figure to 0
% and set the width as a scale of the width an a4 paper and the height
% as a scale of the previously set width of the figure.
%
% Syntax:
% fig_set(fig,ax,leg,width,heigth,font_size)
%
% Input:
% - fig: figure handl
% - ax: axes handle
% - leg: legend handle
% - width: width of figure, in scales of A4 paper width
% - height: height of figure, in scales of width of figure
% - font_size: font size of axes and text, it not set default=10
%
% Output:
% -figure of handel "fig" with set width, height and font
% size and Interpreters set to Latex
%
% Auther: Malthe Vibaek Eisum
% Version: 4.1
% Date: 15/3 - 2016
%% Setting font and font size
if nargin < 3
error('need figure and axes handle')
elseif nargin < 6
font_size = 10;
end
%% Setting figure, axes and legende Interpreters to Latex
set(fig,'DefaultTextInterpreter','Latex');
ax.TickLabelInterpreter='Latex';
if leg ~= 0
leg.Interpreter='Latex';
end
%% Setting width and height of figure
PaperSize = get(0,'defaultFigurePaperSize');
switch fix(PaperSize(1))
case 8
Unit = 'inches';
case 20
Unit = 'centimeters';
otherwise
error('defaultFigurePaperSize is not equivalent to a4 paper')
end
width = PaperSize(1) * width;
height = width * heigth;
set(fig,'Units',Unit,...
'Position',[2 5 width height],...
'PaperSize',[width height],...
'PaperPositionMode','auto',...
'Renderer','painters');
end
Example of creating and printing a figure
x = 1:3;
y = rand(1,3);
nfig = nfig+1; fig=figure(nfig);
ax = gca;
plot(x,y)
xlabel('$\rho$')
ylabel('more $latex_{math}$')
leg = legend('rand');
fig_set(fig,ax,leg,1,1)
print -depsc2 myplot.eps
Unless you close them, you shoudl be able to do
nfig = nfig+1;
fig{nfig} = figure(nfig);
plot()
ax{nfig} = gca
leg{nfig} = legend()
nfig=nfig+1; %// raise the counter
Fig{nfig}=figure(); %// create nfig-th figure
Ax{nfig}=axes('parent',Fig{Nfig}); %// create nfig-th axes and bind them to nfig-th figure
plot() %// plot a curve
Leg{nfig}=legend(Ax{nfig},'Label1',...);%// assign nfig-th label to nfig-th axes
%% Some other code %%
get(Ax{12},'TickLabelInterpreter') %// get the interpreter of 12-th axes (in 12-th figure)
set(Ax{5},'xlim',[-10,10]) %// set the x-limits of 5-th axes
I hope it is what you are looking for.
I am using the code below to plot data from the serial port. Since I have two axes for plotting, how can I select a particular axes for this plot?
From similar problem, I found that they use axes(handles.axes2);. Since I have the plot declared at the start of the program, where should I place this line of code? I tried placing it before specifying the plot title etc. but it is not working.
% Serial Data Logger
% Yu Hin Hau
% 7/9/2013
% **CLOSE PLOT TO END SESSION
clear
clc
%User Defined Properties
serialPort = 'COM5'; % define COM port #
plotTitle = 'Serial Data Log'; % plot title
xLabel = 'Elapsed Time (s)'; % x-axis label
yLabel = 'Data'; % y-axis label
plotGrid = 'on'; % 'off' to turn off grid
min = -1.5; % set y-min
max = 1.5; % set y-max
scrollWidth = 10; % display period in plot, plot entire data log if <= 0
delay = .01; % make sure sample faster than resolution
%Define Function Variables
time = 0;
data = 0;
count = 0;
%Set up Plot
plotGraph = plot(time,data,'-mo',...
'LineWidth',1,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',2);
title(plotTitle,'FontSize',25);
xlabel(xLabel,'FontSize',15);
ylabel(yLabel,'FontSize',15);
axis([0 10 min max]);
grid(plotGrid);
%Open Serial COM Port
s = serial(serialPort)
disp('Close Plot to End Session');
fopen(s);
tic
while ishandle(plotGraph) %Loop when Plot is Active
dat = fscanf(s,'%f'); %Read Data from Serial as Float
if(~isempty(dat) && isfloat(dat)) %Make sure Data Type is Correct
count = count + 1;
time(count) = toc; %Extract Elapsed Time
data(count) = dat(1); %Extract 1st Data Element
%Set Axis according to Scroll Width
if(scrollWidth > 0)
set(plotGraph,'XData',time(time > time(count)-scrollWidth),'YData',data(time > time(count)-scrollWidth));
axis([time(count)-scrollWidth time(count) min max]);
else
set(plotGraph,'XData',time,'YData',data);
axis([0 time(count) min max]);
end
%Allow MATLAB to Update Plot
pause(delay);
end
end
%Close Serial COM Port and Delete useless Variables
fclose(s);
clear count dat delay max min plotGraph plotGrid plotTitle s ...
scrollWidth serialPort xLabel yLabel;
disp('Session Terminated...');
The trick to get reliable plotting and manipulation is to always specify the parent explicitly using the Parent parameter when creating a plot or any other graphics object. All graphics objects support this parameter.
hax = axes();
plot(x,y, 'Parent', hax);
The other alternative, as suggested by #matlabgui is to specify the parent axes as the first input to plot:
plot(hax, x, y);
I personally prefer to use the Parent parameter as a parameter value pair though, as that behavior is consistent across all graphics objects.
You should also specify the axes handle when using other functions which operate on an axes.
xlabel(hax, 'XLabel')
ylabel(hax, 'YLabel')
title(hax, 'This is a title')
axis(hax, [0 0 1 1])
grid(hax, 'on')
hold(hax, 'on')
This is particularly important if you are dealing with an interactive GUI as the user could easily click on a different axes in the middle of your plotting causing the value of gca to change unexpectedly. Also changing the current axes (using axes(hax)) can cause a poor user experience.
Summary
For your specific code, this would involve changing your initial plot call:
plotGraph = plot(time,data,'-mo',...
'LineWidth',1,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',2, ...
'Parent', handles.axes2);
I would also recommend adding explicit axes handles to your calls to: grid, title, axis, xlabel, and ylabel to ensure that their target is the axes you want.