Creating a video from a set of 3D plots - matlab

I used a function called ind2patch to make a 3D block which contains a number of smaller blocks in 3 dimensions. Each small block has a value that is represented by a color. A typical plot is like this one:
Now I would like to show the evolution of values (i.e. the color) with time of these small blocks using a video. I have data at different moments but I only know how to plot the graphs at different time by reading different files. Is there a way to combine the plots to a video or directly plot the graphs in the form of video?
Here is my code:
clear; close all; clc;
fig = figure(1);
set (fig, 'Units', 'normalized', 'Position', [0,0,1,1]);
fig_color='w'; fig_colordef='white';
cMap=jet(256);
faceAlpha1=1;
faceAlpha2=0.65;
edgeColor1='none';
edgeColor2='none';
NumBoxX=100;%box number in x direction
NumBoxY=100;%box number in y direction
NumBoxZ=5;%box number in z direction
fid = fopen('rho 20950.dat','r');
datacell = textscan(fid, '%f%f%f%f%f%f%f%f');
fclose(fid);
all_data = cell2mat(datacell);
M=zeros(NumBoxX,NumBoxY,NumBoxZ);
for i=1:NumBoxX
for j=1:NumBoxY
for k=1:NumBoxZ
num=k+NumBoxZ*(j-1)+NumBoxZ*NumBoxY*(i-1);
M(i,j,k)=all_data(num,4);
end
end
end
indPatch=1:numel(M);
[F,V,C]=ind2patch(indPatch,M,'v');
title('\sigma_{xy} in different cells','fontsize',20);
xlabel('y','fontsize',20);ylabel('x','fontsize',20); zlabel('z','fontsize',20); hold on;
set(get(gca,'xlabel'),'Position',[5 -50 30]);
set(get(gca,'ylabel'),'Position',[5 50 -15]);
set(get(gca,'zlabel'),'Position',[64 190 -60]);
patch('Faces',F,'Vertices',V,'FaceColor','flat','CData',C,'EdgeColor','k','FaceAlpha',0.5);
axis equal; view(3); axis tight; axis vis3d; grid off;
colormap(cMap); caxis([min(M(:)) max(M(:))]);
cb = colorbar;
set(get(cb,'title'),'string','Stress (MPa)','fontsize',20);
lbpos = get(cb,'title'); % get the handle of the colorbar title
%set(lbpos,'Units','data');% change Units to data
%pos = get (lbpos,'position'); % get position of the colorbar title
set(lbpos,'units','normalized','position',[0,1.04]);
MyAxes=gca;
set(MyAxes,'Units','Normalized','position',[0.05,0.1,0.8,0.8]);
zoom(1.85);

You could do something like this:
Loop through each patch and grab an image of it.
Insert the images into a matrix
Convert the image matrix into a movie using immovie
% // Create a matrix to hold your images
A = zeros(row,col,numOfColours, numOfFrames);
where row is the number of rows and col is the number of columns in one image.
Loop through your patches and create a video of the individual images.
for n=1:numOfPatches
imshow(patches(:,:,n)) % // display the image
frame = getframe(gcf) % // get the current figure window
im = frame2im(frame); % // convert it to an image
A(:,:,1:3,n) = im; % // Insert the image into the matrix
end
The you can use immovie to convert it to a movie
mov = immovie(RGB);
movie(mov); % // play the movie

Related

Plot categorical x axis

I have a data set (shown in picture from excel):
and I want to make a scatter plot with the categories along the x-axis:
My current code is:
Mydata= readtable('D:\Download\Book1.xlsv');
y= Mydata.Group1;
x=Mydata.Y;
size= 50;
scatter (x,y,size,'magenta','filled','square');
hold on
y= Mydata.Group2;
scatter(x,y,size,'red','filled','d');
y= Mydata.Group3;
scatter(x,y,size,'b','filled','p');
y= Mydata.Group4;
scatter(x,y,size,'yellow','filled','h');
y=Mydata.Group5;
scatter(x,y,size,'k','filled','o');
hold off
With this current code, all data were plotted in one line not like in the picture. I also want to add an error bar for each data later. How can I achieve this?
Here is one way to plot data points for a category and color them by series.
% generate numbers
X = rand(3,4);
cols = {'r','b','g'}
num_categories = size(X)(2);
num_series = size(X)(1);
labels = cell(num_categories,1)
legends = cell(num_series,1)
figure;
hold on;
% plot series
for i=1:num_series
scatter(1:num_categories,X(i,:),cols{i})
legends{i,1} = ['series ', num2str(i)];
end
% generate labels for categories
for i=1:num_categories
labels{i,1} = ['category ', num2str(i)];
end
set(gca, 'xtick',1:num_categories)
set(gca, 'xticklabel', labels)
axis([0, num_categories+1, 0, 1]);
legend(legends)
Can you elaborate what you mean with error bars and where you would want them to be? Do you want errors per category and series?

Plot digitization in MATLAB using ginput

I'm trying to digitize this image using MATLAB:
I have the following script:
%// Get data from plot
clear all; close all;
%// Input
fname = 'Fig15a.PNG';
xvec = [1e3:1:1e8];
yvec = [1e-4:1:1e-1];
xt = [1e3 1e4 1e5 1e6 1e7 1e8];
yt = [1e-4 1e-3 1e-2 1e-1];
%// Read and plot the image
im = imread(fname);
figure(1), clf
im = im(end:-1:1,:,:);
image(xvec,yvec,im)
axis xy;
grid on;
%// Set ticks
set(gca,'xtick',xt,'ytick',yt); %// Match tick marks
%// Collect data
[x,y] = ginput; %// Click on points, and then hit ENTER to finish
%// Plot collected data
hold on; plot(x,y,'r-o'); hold off;
%// Then save data as:
save Fig15a.mat x y
The script works fine
Is there a way I can change the x and y axes to a log scale ?
I have tried adding the following code in different places without luck:
%// Set Log scale on x and y axes
set(gca,'XScale','log','YScale','log');
Below's a proof of concept that should get you on the right track. I have replaced things in your original code with what I consider "good practices".
function q36470836
%% // Definitions:
FIG_NUM = 36470836;
%% // Inputs:
fname = 'http://i.stack.imgur.com/2as4t.png';
xt = logspace(3,8,6);
yt = logspace(-4,-1,4);
%% // Init
figure(FIG_NUM); clf
% Read and plot the image
im = imread(fname);
hIMG = imshow(im); axis image;
%// Set ticks
hDigitizer = axes('Color','none',...
'XLim',[xt(1) xt(end)],'YLim',[yt(1) yt(end)],...
'XScale','log','YScale','log',...
'Position',hIMG.Parent.Position .* [1 1 696/785 (609-64+1)/609]);
uistack(hDigitizer,'top'); %// May be required in some cases
grid on; hold on; grid minor;
%// Collect data:
[x,y] = ginput; %// Click on points, and then hit ENTER to finish
%// Plot collected data:
scatter(x,y,'o','MarkerEdgeColor','r');
%// Save data:
save Fig15a.mat x y
Here's an example of what it looks like:
Few notes:
xt, yt may be created in a cleaner fashion using logspace.
It is difficult (possibly impossible) to align the digitization grid with the image correctly, which would inevitably result in errors in your data. Though this can be helped in the following scenarios (for which you will require a vector graphics editor, such as the freeware InkScape):
If, by any chance, you got this image from a PDF file, where it appears as a vector image (you can test this by zooming in as much as you like without the chart becoming pixelated; this seems to be your case from the way the .png looks), you would be better off saving it as a vector image and then you have two options:
Exporting the image to a bitmap with a greatly increased resolution and then attempting the digitization procedure again.
Saving the vector image as .svg then opening the file using your favorite text editor and getting the exact coordinates of the points.
If the source image is a bitmap (as opposed to vector graphic), you can "trace the bitmap", thus converting it to vectoric, then #GOTO step 1.
This solution doesn't (currently) support resizing of the figure.
The magic numbers appearing in the Position setting are scaling factors explained in the image below (and also size(im) is [609 785 3]). These can technically be found using "primitive image processing" but in this case I just hard-coded them explicitly.
You can plot in double logarithmic scale with
loglog(x,y);
help loglog or the documentation give additional information.
For a single logarithmic scale use
semilogx(x,y);
semilogy(x,y);

MATLAB enlarge 3D plot without enlarging colorbar

Is it possible to enlarge a 3D patch without altering the size of the colorbar? My original picture is like this one:
I just want to enlarge the block in the middle of the figure keeping the colorbar unchanged. I used zoom(1.9) before, it is good but since I need to use a for loop to read sequential files to plot different graphs and make video, the graph became larger and larger so it seems that I need another method to enlarge the plot.
Update: my codes
set(gcf,'Renderer','zbuffer'); %eliminate unnecessary background and prevent stationary video - Important!
vid = VideoWriter('afation.avi'); %Create a avi file
vid.Quality = 100;
vid.FrameRate = 15;
open(vid); %Open the avi file so that films can be put into it later on
for ii=FirstFile:FileInterval:LastFile
fid = fopen(filename,'r');
datacell = textscan(fid, '%f%f%f%f%f%f%f%f'); %There are 8 columns to be read so there are 8 %f
fclose(fid);
all_data = cell2mat(datacell); %converted into a matrix containing all the dis. density info. for every simulation cell
M=zeros(NumBoxX,NumBoxY,NumBoxZ); %create a matrix of 50x50x5,representing array of simulation cells
% % the following loops assign the dislocation density from all_data to M
for i=1:NumBoxX
for j=1:NumBoxY
for k=1:NumBoxZ
num=k+NumBoxZ*(j-1)+NumBoxZ*NumBoxY*(i-1);
M(i,j,k)=all_data(num,ValCol); %the ValCol column of all_data is dislocation density
end
end
end
indPatch=1:numel(M);
[F,V,C]=ind2patch(indPatch,M,'v'); %Call the function ind2patch in order to plot 3D cube with color
title('AA in different cells','fontsize',20);%set title \sigma_{xx}
xlabel('y','fontsize',20);ylabel('x','fontsize',20); zlabel('z','fontsize',20); hold on;
set(get(gca,'xlabel'),'Position',[5 -50 30]); %set position of axis label
set(get(gca,'ylabel'),'Position',[5 50 -15]);
set(get(gca,'zlabel'),'Position',[64 190 -60]);
patch('Faces',F,'Vertices',V,'FaceColor','flat','CData',C,'EdgeColor','k','FaceAlpha',0.5);
axis equal; view(3); axis tight; axis vis3d; grid off;
colormap(cMap);
caxis([MinDis MaxDis]); %set the range of the colorbar %caxis([min(M(:)) max(M(:))]); %range of the colorbar according to one file only
cb = colorbar; % create the colorbar
set(get(cb,'title'),'string','aaty(m^{-2})','fontsize',20);
lbpos = get(cb,'title'); % get the handle of the colorbar title
set(lbpos,'units','normalized','position',[0,1.04]);
MyAxes=gca;
set(MyAxes,'Units','Normalized','position',[0.05,0.1,0.8,0.8]);
zoom(1.9);
writeVideo(vid, getframe(gcf)); %get the picture and put in the avi file with the handle "vid"
end
close(vid); %close the avi file after putting all the films into it
% winopen('ggggon.avi'); %play the movie
I put the zoom in the for loop because I need to enlarge the picture one by one and put them into my avi file to make movie.

Getting video from image sequence of figures with subplots in MATLAB

I have a sequence of MATLAB figures which I want to convert to a video. The figures are composed of 2 subplots, such that each subplot contains an imshow with 2 different plots (red and green) overlayed on it, like the following:
How do I get an image of all the data contained inside each figure, so that next I can convert the sequence of images to a video with VideoWriter?
The key is:
im = frame2im(getframe(h));
Where h is the handle to your plot or axis
You can also pass an optional argument 'rect' to getframe to specify the area to capture.
Here is an example from the MathWorks on how to use getframe in a loop to record the frames. For more information type doc getframe
Z = peaks;
surf(Z)
axis tight manual
ax = gca;
ax.NextPlot = 'replaceChildren';
loops = 40;
F(loops) = struct('cdata',[],'colormap',[]);
for j = 1:loops
X = sin(j*pi/10)*Z;
surf(X,Z)
drawnow
F(j) = getframe(gcf);
end
% Play back the movie two times.
fig = figure;
movie(fig,F,2)

MATLAB Create Movie

** I figured out how to create the movie so the code has been changed to reflect the correct one in case it is useful for anyone in the future.
This script creates a movie of a eqdconic map and saves it in avi format. The movie will run through 1255 frames. It also plots a dot at a certain point on the image, places a changing title on the movie to show what month is being run through, and has a colorbar on the right side.
Some of the variables used were created elsewhere. The code for creating them has been left out to condense the code (and since they will not be useful for anyone else other than myself).
% Create movie
nFrames = 34; % Number of frames
for k = 1:nFrames
% Eqdconic script
% Define figure and axes
fg1 = figure(1);
axesm('MapProjection','eqdconic', 'MapParallels', [], 'MapLatLimit',[-80 -59],'MapLonLimit',[190 251]) % 60-70S and 120-160W
framem on; gridm on; mlabel on; plabel on; hold all;
% Plot data
frame = dataPoint_movie(:,:,k);
image = contourfm(lat,lon,frame, 'LineStyle', 'none');
hold on
% Plot dot
plotm(-66.75,224,'k.','MarkerSize',30);
% Colorbar
caxis([0 100]);
h = colorbar;
ylabel(h,'Percent');
% Title: Days 1:1258 inclusive. 20100101 to 20130611
date = datenum(2009, 12, 31) + k; % Convert t into serial numbers
str = datestr(date, 'mmm yyyy'); % Show in the format mmm yyyy so title changes only once a month
title(str);
mov(k) = getframe(gcf); % gca would give only the image. gcf places the title and other attributes on the movie.
end
close(gcf)
% % Save as AVI file
movie2avi(mov, 'SeaIceConcentration.avi', 'compression', 'none', 'fps', 2);
I prefer to export my movies from matlab to a .avi file.
before the for loop, initialize your movie:
vidObj = VideoWriter('Movie.avi');
vidObj.FrameRate=23;
open(vidObj);
then get your frame in the for loop:
A = getframe;
writeVideo(vidObj,A);
(note, i'm not saving each frame in a matrix, so A is an MxN matrix)
Then write out your movie after the for loop
close(vidObj);
The movie will be in your current working directory. you can open using quicktime or some other avi player. To change the frame rate (speed) of your movie, edit the second line of code. 23 fps is a good smooth movie framerate.
Check the consistency of the statements:
A = dataPoint(:,:,t);
and
A(i) = getframe;
A is overwritten all the time So that you will at best get the last frame.