clear all
[filename, filepath, ~] = uigetfile('/Users/brunohawkins/Library/Excel data for experiments/Fatigue test/BH_fatiguetest_1_1.xls');
% headers.
[~, headers, ~] = xlsread([filepath, filename], 1, '1:3');
time = xlsread([filepath, filename], 1, 'A:A');
displacement = xlsread([filepath, filename], 1, 'B:B');
load = xlsread([filepath, filename], 1, 'C:C');
A = 30.2; % original cross-sectional area of sample
L = 8.89; % original length of sample
figure,plot(time,load);
% Make sure to give your plot a suitable title and name to the axis %
xlabel('time, s','FontSize',14)
ylabel('load, N','FontSize',14)
title('Load Vs Time graph for Fatigue of HDPE for 17.52N/s','FontSize',14);
grid on;
I am trying to load the data for the 'load' from this file, but it is loading time for both the x and the y axis of my graph, so i get a line. i want it to plot load on the y axis and time on the x. What is wrong with my code?
I genuinly dont understand what is wrong. Is MATLAB crashing because I have over 600000 data points?
Related
I really like scatter()'s ability to automatically color points based on some vector of values, I just want to add colored lines between the points.
The plot in question has time on x-axis, monte-carlo number on y-axis, and then some measured value as the color vector (e.g. number of cars seen in a video frame).
Basically, each point is an update in the system. So calling scatter(time,monte_carlo_number,[],color_vec) plots the points at which there is an update in the system, with color representing some value. This is great, but I would like to add line segments that connect these points, each segment matching the color specified by color_vec.
Basic working example
% Create example data
data = table();
data.time = randsample(1:100, 1000, true)';
data.mc = randsample(1:50, 1000, true)'; % actual monte-carlo run number labels are sorted
data.color_value = randsample(1:10, 1000, true)';
% Create the scatter plot
scatter(data.time, data.mc, [] , data.color_value, 'filled')
colorbar('Ticks', unique(data.color_value))
% Always label your axes
xlabel('Time (s)')
ylabel('Monte-Carlo Run Number')
Below is a screen-shot of what this code might produce. If color_value is the number of cars seen in a video frame, we can see each time this value is updated via the points. However, it is easier for humans to read this plot if there were lines connecting each point to the next with the correct color. This demonstrates to the viewer that this value continues on in time until the next update.
Something like this? I changed the number of samples to 100, and it is already quite a mess, so I don't think this is going to the viewer understand what's plotted.
% Create example data
data = table();
np = 100;
data.time = randsample(1:100, np, true)';
data.mc = randsample(1:50, np, true)'; % actual monte-carlo run number labels are sorted
data.color_value = randsample(1:10, np, true)';
vals = unique(data.color_value).';
cmap = parula(numel(vals));
colors = [];
for k = 1:numel(vals)
ind = find(data.color_value == vals(k));
data_sel{k} = sortrows(data(ind,:));
colors(k,:) = cmap(k,:);
end
figure(1); clf;
% Create the scatter plot
scatter(data.time, data.mc, [] , data.color_value, 'filled')
hold on
for k = 1:numel(vals)
plot(data_sel{k}.time, data_sel{k}.mc, 'Color',colors(k,:))
end
colorbar('Ticks', unique(data.color_value))
% Always label your axes
xlabel('Time (s)')
ylabel('Monte-Carlo Run Number')
I have a spectral data (1000 variables on xaxis, and peak intensities as y) and a list of peaks of interest at various specific x locations (a matrix called Peak) which I obtained from a function I made. Here, I would like to draw a line from the maximum value of each peaks to the xaxis - or, eventually, place a vertical arrow above each peaks but I read it is quite troublesome, so just a vertical line is welcome. However, using the following code, I get "Error using line Value must be a vector of numeric type". Any thoughts?
X = spectra;
[Peak,intensity]=PeakDetection(X);
nrow = length(Peak);
Peak2=Peak; % to put inside the real xaxis value
plot(xaxis,X);
hold on
for i = 1 : nbrow
Peak2(:,i) = round(xaxis(:,i)); % to get the real xaxis value and round it
xline = Peak2(:,i);
line('XData',xline,'YData',X,'Color','red','LineWidth',2);
end
hold off
Simple annotation:
Here is a simple way to annotate the peaks:
plot(x,y,x_peak,y_peak+0.1,'v','MarkerFaceColor','r');
where x and y is your data, and x_peak and y_peak is the coordinates of the peaks you want to annotate. The add of 0.1 is just for a better placing of the annotation and should be calibrated for your data.
For example (with some arbitrary data):
x = 1:1000;
y = sin(0.01*x).*cos(0.05*x);
[y_peak,x_peak] = PeakDetection(y); % this is just a sketch based on your code...
plot(x,y,x_peak,y_peak+0.1,'v','MarkerFaceColor','r');
the result:
Line annotation:
This is just a little bit more complicated because we need 4 values for each line. Again, assuming x_peak and y_peak as before:
plot(x,y);
hold on
ax = gca;
ymin = ax.YLim(1);
plot([x_peak;x_peak],[ymin*ones(1,numel(y_peak));y_peak],'r')
% you could write instead:
% line([x_peak;x_peak],[ymin*ones(1,numel(y_peak));y_peak],'Color','r')
% but I prefer the PLOT function.
hold off
and the result:
Arrow annotation:
If you really want those arrows, then you need to first convert the peak location to the normalized figure units. Here how to do that:
plot(x,y);
ylim([-1.5 1.5]) % only for a better look of the arrows
peaks = [x_peak.' y_peak.'];
ax = gca;
% This prat converts the axis unites to the figure normalized unites
% AX is a handle to the figure
% PEAKS is a n-by-2 matrix, where the first column is the x values and the
% second is the y values
pos = ax.Position;
% NORMPEAKS is a matrix in the same size of PEAKS, but with all the values
% converted to normalized units
normpx = pos(3)*((peaks(:,1)-ax.XLim(1))./range(ax.XLim))+ pos(1);
normpy = pos(4)*((peaks(:,2)-ax.YLim(1))./range(ax.YLim))+ pos(2);
normpeaks = [normpx normpy];
for k = 1:size(normpeaks,1)
annotation('arrow',[normpeaks(k,1) normpeaks(k,1)],...
[normpeaks(k,2)+0.1 normpeaks(k,2)],...
'Color','red','LineWidth',2)
end
and the result:
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);
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
I haven't used MATLAB in a while and I am stuck on a small detail. I would really appreciate it if someone could help me out!
So I am trying to plot a transfer function using a specific function called freqs but I can't figure out how I can label specific points on the graph.
b = [0 0 10.0455]; % Numerator coefficients
a = [(1/139344) (1/183.75) 1]; % Denominator coefficients
w = logspace(-3,5); % Frequency vector
freqs(b,a,w)
grid on
I want to mark values at points x=600 Hz and 7500 Hz with a marker or to be more specific, points (600,20) and (7500,-71), both of which should lie on the curve. For some reason, freqs doesn't let me do that.
freqs is very limited when you want to rely on it plotting the frequency response for you. Basically, you have no control on how to modify the graph on top of what MATLAB generates for you.
Instead, generate the output response in a vector yourself, then plot the magnitude and phase of the output yourself so that you have full control. If you specify an output when calling freqs, you will get the response of the system.
With this, you can find the magnitude of the output by abs and the phase by angle. BTW, (600,20) and (7500,-71) make absolutely no sense unless you're talking about magnitude in dB.... which I will assume is the case for the moment.
As such, we can reproduce the plot that freqs gives by the following. The key is to use semilogx to get a semi-logarithmic graph on the x-axis. On top of this, declare those points that you want to mark on the magnitude, so (600,20) and (7500,-71):
%// Your code:
b = [0 0 10.0455]; % Numerator coefficients
a = [(1/139344) (1/183.75) 1]; % Denominator coefficients
w = logspace(-3,5); % Frequency vector
%// New code
h = freqs(b,a,w); %// Output of freqs
mag = 20*log10(abs(h)); %// Magnitude in dB
pha = (180/pi)*angle(h); %// Phase in degrees
%// Declare points
wpt = [600, 7500];
mpt = [20, -71];
%// Plot the magnitude as well as markers
figure;
subplot(2,1,1);
semilogx(w, mag, wpt, mpt, 'r.');
xlabel('Frequency');
ylabel('Magnitude (dB)');
grid;
%// Plot phase
subplot(2,1,2);
semilogx(w, pha);
xlabel('Frequency');
ylabel('Phase (Degrees)');
grid;
We get this:
If you check what freqs generates for you, you'll see that we get the same thing, but the magnitude is in gain (V/V) instead of dB. If you want it in V/V, then just plot the magnitude without the 20*log10() call. Using your data, the markers I plotted are not on the graph (wpt and mpt), so adjust the points to whatever you see fit.
There are a couple issues before we attempt to answer your question. First, there is no data-point at 600Hz or 7500Hz. These frequencies fall between data-points when graphed using the freqs command. See the image below, with datatips added interactively. I copy-pasted your code to generate this data.
Second, it does not appear that either (600,20) or (7500,-71) lie on the curves, at least with the data as you entered above.
One solution is to use plot a marker on the desired position, and use a "text" object to add a string describing the point. I put together a script using your data, to generate this figure:
The code is as follows:
b = [0 0 10.0455];
a = [(1/139344) (1/183.75) 1];
w = logspace(-3,5);
freqs(b,a,w)
grid on
figureHandle = gcf;
figureChildren = get ( figureHandle , 'children' ); % The children this returns may vary.
axes1Handle = figureChildren(1);
axes2Handle = figureChildren(2);
axes1Children = get(axes1Handle,'children'); % This should be a "line" object.
axes2Children = get(axes2Handle,'children'); % This should be a "line" object.
axes1XData = get(axes1Children,'xdata');
axes1YData = get(axes1Children,'ydata');
axes2XData = get(axes2Children,'xdata');
axes2YData = get(axes2Children,'ydata');
hold(axes1Handle,'on');
plot(axes1Handle,axes1XData(40),axes1YData(40),'m*');
pointString1 = ['(',num2str(axes1XData(40)),',',num2str(axes1YData(40)),')'];
handleText1 = text(axes1XData(40),axes1YData(40),pointString1,'parent',axes1Handle);
hold(axes2Handle,'on');
plot(axes2Handle,axes2XData(40),axes2YData(40),'m*');
pointString2 = ['(',num2str(axes2XData(40)),',',num2str(axes2YData(40)),')'];
handleText2 = text(axes2XData(40),axes2YData(40),pointString2,'parent',axes2Handle);