Introduction
Let's say I have two series of data, one of them in the function of "x", the second "1/x". I want to put it in a subplot, one by one. However because the scale of second plot is 1/x, it is impossible to compare this plots.
What I achieved
I can revert the order of the x-axis in the second plot, so in the best case, I can have something like this:
subplot(2,1,1);
plot(X,Y) %First plot
xlim([273 833])
xticks([350 500 650 800])
subplot(2,1,2);
plot(1./X,Z); %Second plot
xlim([1/833 1/273])
xticks([0.0013 0.0015 0.0020 0.0029])
set ( gca, 'xdir', 'reverse' ) %reverting the x-axis
The ticks are totally desynchronized. 350 should be in the one column with 2.9 (1/350=2.9*10^-3), 500 with 2, 650 with 1.5 and so on.
What I need
How to apply a non-linear x-axis or something similar, to get both axes synchronized? I know that it will be not the best idea, form the mathematical point of view, but it will be used only as a graphical, qualitative representation. The data I use is quite long, but If you have an idea how to solve it, you can use any random data to show.
Related
I have the following memory-speed problem in Matlab and I would like your help to understand whether there may be a solution.
Consider the following 4 big column vectors X1, X2, Y1, Y2.
clear
rng default
P=10^8;
X1=rand(1,P)*5;
X2=rand(1,P)*5;
Y1=rand(1,P)*5;
Y2=rand(1,P)*5;
What I would like to do is a scatter plot where on the x-axis I have the sum between any possible two elements of X1 and X2 and on the y-axis I have the sum between any possible two elements of Y1 and Y2.
I post here three options I thought about that do not work mainly because of memory and speed issues.
Option 1 (issues: too slow when doing the loop, out of memory when doing vertcat)
Xtemp=cell(P,1);
Ytemp=cell(P,1);
for i=1:P
tic
Xtemp{i}=X1(i)+X2(:);
Ytemp{i}=Y1(i)+Y2(:);
toc
end
X=vertcat(Xtemp{:});
Y=vertcat(Ytemp{:});
scatter(X,Y)
Option 2 (issues: too slow when doing the loop, time increasing as the loop proceeds, Matlab going crazy and unable to produce the scatter even if I stop the loop after 5 iterations)
for i=1:P
tic
scatter(X1(i)+X2(:), Y1(i)+Y2(:))
hold on
toc
end
Option 3 (sort of giving up) (issues: as I increase T the scatter gets closer and closer to a square which is correct; I am wondering though whether this is caused by the fact that I generated the data using rand and in option 3 I use randi; maybe with my real data the scatter does not "converge" to the true plot as I increase T; also, what is the "optimal" T and R?).
T=20;
R=500;
for t=1:T
tic
%select R points at random from X1,X2,Y1,Y2
X1sel=(X1(randi(R,R,1)));
X2sel=(X2(randi(R,R,1)));
Y1sel=(Y1(randi(R,R,1)));
Y2sel=(Y2(randi(R,R,1)));
%do option 1 among those points and plot
Xtempsel=cell(R,1);
Ytempsel=cell(R,1);
for r=1:R
Xtempsel{r}=X1sel(r)+X2sel(:);
Ytempsel{r}=Y1sel(r)+Y2sel(:);
end
Xsel=vertcat(Xtempsel{:});
Ysel=vertcat(Ytempsel{:});
scatter(Xsel,Ysel, 'b', 'filled')
hold on
toc
end
Is there a way to do what I want or is simply impossible?
You are trying to build a vector with P^2 elements, i.e. 10^16. This is many order of magnitude more that what would fit into the memory of a standard computer (10GB is 10^10 bytes or 1.2 billion double precision floats).
For smaller vectors (i.e. P<1e4), try:
Xsum=bsxfun(#plus,X1,X2.'); %Matrix with the sum of any two elements from X1 and X2
X=X(:); %Reshape to vector
Ysum=bsxfun(#plus,Y1,Y2.');
Y=Y(:);
plot(X,Y,'.') %Plot as small dots, likely to take forever if there are too many points
To build a figure with a more reasonable number of pairs picked randomly from these large vectors:
Npick=1e4;
sel1=randi(P,[Npick,1]);
sel2=randi(P,[Npick,1]);
Xsel=X1(sel1)+X2(sel2);
Ysel=Y1(sel1)+Y2(sel2);
plot(Xsel,Ysel,'.'); %Plot as small dots
Let's say we have the following data:
A1= [41.3251
18.2350
9.9891
36.1722
50.8702
32.1519
44.6284
60.0892
58.1297
34.7482
34.6447
6.7361
1.2960
1.9778
2.0422];
A2=[86.3924
86.4882
86.1717
85.8506
85.8634
86.1267
86.4304
86.6406
86.5022
86.1384
86.5500
86.2765
86.7044
86.8075
86.9007];
When I plot the above data using plot(A1,A2);, I get this graph:
Is there any way to make the graph look smooth like a cubic plot?
Yes you can. You can interpolate in between the keypoints. This will require a bit of trickery though. Blindly using interpolation with any of MATLAB's commands won't work because they require that the independent axes (the x-axis in your case) to increase. You can't do this with your data currently... at least out of the box. Therefore you'll have to create a dummy list of values that span from 1 up to as many elements as there are in A1 (or A2 as they're both equal in size) to create an independent axis and interpolate both arrays independently by specifying the dummy list with a finer spacing in resolution. This finer spacing is controlled by the total number of new points you want to introduce in the plot. These points will be defined within the range of the dummy list but the spacing in between each point will decrease as you increase the total number of new points. As a general rule, the more points you add the less spacing there will be and so the plot should be more smooth. Once you do that, plot the final values together.
Here's some code for you to run. We will be using interp1 to perform the interpolation for us and most of the work. The function linspace creates the finer grid of points in the dummy list to facilitate the interpolation. N would be the total number of desired points you want to plot. I've made it 500 for now meaning that 500 points will be used for interpolation using your original data. Experiment by increasing (or decreasing) the total number of points and seeing what effect this has in the smoothness of your data.
I'll also be using the Piecewise Cubic Hermite Interpolating Polynomial or pchip as the method of interpolation, which is basically cubic spline interpolation if you want to get technical. Assuming that A1 and A2 are already created:
%// Specify number of interpolating points
N = 500;
%// Specify dummy list of points
D = 1 : numel(A1);
%// Generate finer grid of points
NN = linspace(1, numel(A1), N);
%// Interpolate each set of points independently
A1interp = interp1(D, A1, NN, 'pchip');
A2interp = interp1(D, A2, NN, 'pchip');
%// Plot the data
plot(A1interp, A2interp);
I now get the following:
Let's say we have the following data:
A1= [41.3251
18.2350
9.9891
36.1722
50.8702
32.1519
44.6284
60.0892
58.1297
34.7482
34.6447
6.7361
1.2960
1.9778
2.0422];
A2=[86.3924
86.4882
86.1717
85.8506
85.8634
86.1267
86.4304
86.6406
86.5022
86.1384
86.5500
86.2765
86.7044
86.8075
86.9007];
When I plot the above data using plot(A1,A2);, I get this graph:
Is there any way to make the graph look smooth like a cubic plot?
Yes you can. You can interpolate in between the keypoints. This will require a bit of trickery though. Blindly using interpolation with any of MATLAB's commands won't work because they require that the independent axes (the x-axis in your case) to increase. You can't do this with your data currently... at least out of the box. Therefore you'll have to create a dummy list of values that span from 1 up to as many elements as there are in A1 (or A2 as they're both equal in size) to create an independent axis and interpolate both arrays independently by specifying the dummy list with a finer spacing in resolution. This finer spacing is controlled by the total number of new points you want to introduce in the plot. These points will be defined within the range of the dummy list but the spacing in between each point will decrease as you increase the total number of new points. As a general rule, the more points you add the less spacing there will be and so the plot should be more smooth. Once you do that, plot the final values together.
Here's some code for you to run. We will be using interp1 to perform the interpolation for us and most of the work. The function linspace creates the finer grid of points in the dummy list to facilitate the interpolation. N would be the total number of desired points you want to plot. I've made it 500 for now meaning that 500 points will be used for interpolation using your original data. Experiment by increasing (or decreasing) the total number of points and seeing what effect this has in the smoothness of your data.
I'll also be using the Piecewise Cubic Hermite Interpolating Polynomial or pchip as the method of interpolation, which is basically cubic spline interpolation if you want to get technical. Assuming that A1 and A2 are already created:
%// Specify number of interpolating points
N = 500;
%// Specify dummy list of points
D = 1 : numel(A1);
%// Generate finer grid of points
NN = linspace(1, numel(A1), N);
%// Interpolate each set of points independently
A1interp = interp1(D, A1, NN, 'pchip');
A2interp = interp1(D, A2, NN, 'pchip');
%// Plot the data
plot(A1interp, A2interp);
I now get the following:
that's a thing that is making me a bit crazy-noob so far.
I have my struct storing data from successive experiments, 7 field per each experiment:
veq1
rpmdispl1
displ1
tau1
sigma1
mu1
v_displ1
veq2
...
Then i'd like to plot in for loops, like (k is total datasets to be plotted)
figure(1)
hold all
for ii=1:k;
subplot(2,1,1)
eval(['plot(struct.displ',num2str(ii),',struct.tau',num2str(ii),')']);
subplot(2,1,2)
eval(['plot(struct.displ',num2str(ii),',struct.v_displ',num2str(ii),')']);
end
But actually I am not allowed in changing plot axes style among the plots of the loop. (using either roots or gca settings, line and color string variables, etc)
So i thought to do it in a different way, like:
for ii=1:k;
subplot(2,1,1)
plot(struct.displ(num2str(ii)),struct.tau(num2str(ii)),line,color)
subplot(2,1,2)
plot(struct.displ(num2str(ii)),struct.v_displ(num2str(ii)),line,color);
end
But no way. This last is only an idea (rather than a working code), I admit it. Can somebody suggest me something to work it out?
I'd be grateful.
I was trying to compare how similar 2 signals using correlation via DFT (Digital Fourier Transform) in Matlab, but the correlation function gives not really predictable results. For example, if I compare those 2 pairs of signals :
correlation 1 and 2
correlation 3 and 4 (autocorrelation)
I would expect correlation peak in "corr 3 and 4" case higher than in "corr 1 and 2" case.
I as also tried to make signals "average to zero", but this did not help.
Is this the expected result or did I miss some preprocessing, etc.?
You need to normalize your data traces - i.e. divide them by their respective integrals before correlating. The following code demonstrates that when you normalize your data traces, the autocorrelation indeed gives you the larger value:
%# producing your data
trace1=(abs(linspace(-64,64,128))<20)*200;
trace2=trace1-(abs(linspace(-64,64,128))<10)*50;
figure;
subplot(321);
plot(trace1);
subplot(322);
plot(trace2);
subplot(323);
plot(xcorr(trace1,trace2))
title('unnormalized cross-correlation');
subplot(324);
plot(xcorr(trace2,trace2))
title('unnormalized autocorrelation');
%
%# what you should be doing:
subplot(325);
plot(xcorr(trace1/sum(trace1(:)),trace2/sum(trace2(:))))
title('normalized cross-correlation');
subplot(326);
plot(xcorr(trace2/sum(trace2(:)),trace2/sum(trace2(:))))
title('normalized autocorrelation');
leading to
where I zoomed in on the peaks to show the normalized autocorrelation has a higher peak than the normalized cross-correlation.
#Jonas, I was unable to find how to insert image and make good enough formatting (sorry, novice here) commenting your answer, so I am leaving this comment as "answer".
So, what I found that for following figures your method giving not expected results:
as you see - peak for auto-correlation is lower than for cross correlation.
Code which I used is below:
trace1=(abs(linspace(-64,64,128))<20)*200;
trace2=trace1-(abs(linspace(-64,64,128))<10)*50;
trace1=trace1-(abs(linspace(-64,64,128))<10)*100;
subplot(321);
plot(trace1); grid on;
subplot(322);
plot(trace2); grid on;
subplot(323);
plot(xcorr(trace1,trace2)); grid on;
title('unnormalized cross-correlation');
subplot(324);
plot(xcorr(trace2,trace2)); grid on;
title('unnormalized autocorrelation');
subplot(325);
plot(xcorr(trace1/sum(trace1(:)),trace2/sum(trace2(:)))); grid on;
title('normalized cross-correlation');
subplot(326);
plot(xcorr(trace2/sum(trace2(:)),trace2/sum(trace2(:)))); grid on;
title('normalized autocorrelation');