LevelList in contour plots - matlab

There is some information I couldn't find neither in the documentation nor in forums:
My Z has 5 orders of magnitude, how can I plot correctly these values? 0.002 all the way to 100-ish
Is it possible to specify this order of magnitude rather than the exact number? In LevelList somehow, I mean. E.g. I want a level at 10^2, which can mean 100 or 190, or 131.34.
Code:
[C,h] = contour(beta,alpha,Coupling)
clabel(C,h)
axis([0 3 0 3])

Let's say you had some random data
% Data Order of magnitude base 10
a = [0.0964 % O(1e-1)
0.0157 % O(1e-2)
0.0970 % O(1e-1)
0.9571 % O(1e+0)
0.4853 % O(1e+0)
0.8002 % O(1e+0)
1.4188 % O(1e+0)
4.2176 % O(1e+1)
9.1573] % O(1e+1)
Where the orders of magnitude are given by
orders = round(log10(a));
You can replace your z values with this formula z2 = 10.^round(log10(z)) to define them by their magnitude. Then produce a contour plot with the distinct orders of magnitude just as you did before, but using z2 not z.
For your example:
CouplingMagnitudes = 10.^(round(log10(Coupling)));
[C,h] = contour(beta, alpha, CouplingMagnitudes)

Related

How to plot and estimate empirical CDF and cdf in matlab

the question has already been raised several times, but mine differs a little from those previously voiced. There is a table (x value and relative frequencies).
x
150
250
350
450
550
650
750
y
1
2
8
30
18
16
5
I don’t really understand the meaning of the function [f,x] = ecdf(y) built into matlab, since I estimate and plot an empirical distribution function,
however, it is clearly not correct, if you build a histogram based on the selected data (x and y), then the resulting ECDF does not describe the correctly chosen distribution.
Therefore, such a question arose: how to construct correctly ECDF function from the table (empirical distribution function for x and having an array of relative frequencies)for the distribution function and from it directly estimate and plot cumulative distribution function?
My code for plot hist and ECDF:
%% data
y = [1; 2; 8; 30; 18; 16; 5];
x = [150; 250; 350; 450; 550; 650; 750];
%% hist and polygon
figure(1)
bar(x,y,'LineWidth',1,...
'FaceColor',[0.0745098039215686 0.623529411764706 1],...
'EdgeColor',[0.149019607843137 0.149019607843137 0.149019607843137],...
'BarWidth',1,...
'BarLayout','stacked');
hold on
plot(x,y,'-o','Color','red','LineWidth',1)
hold off
%% ecdf
[ff,x] = ecdf(y);
x_e = [0;x];
figure(2)
stairs(x_e,ff,'Marker','o','LineWidth',1,'Color',[0.0745098039215686 0.623529411764706 1]);
set(gca,'GridAlpha',0.25,'GridLineStyle','--','MinorGridLineStyle','--',...
'XGrid','on','XMinorGrid','on','YGrid','on');
xlim([0 780]);
You should not use the ecdf function, because it takes the data values as input. Your inputs, on the other hand, seem to be the population values and their absolute frequencies. So you only need to
normalize the frequencies to make them relative, and then
compute their cumulative sum.
When plotting, I suggest you include some initial and final population values with respective normalized frequencies 0 and 1 for a clearer graph.
x = [150; 250; 350; 450; 550; 650; 750];
y = [1; 2; 8; 30; 18; 16; 5]; % example data
cdf = cumsum(y./sum(y)); % normalize, then compute cumulative sum
stairs([100; x; 900], [0; cdf; 1], 'linewidth', .8), grid on % note two extra values

Generate a mesh with unequal steps based on a density function, using Matlab

I'm trying to generate a 1D mesh with unequal step length, and with a fixed number of elements [same as the initial mesh].
The length should be proportional to a node density. In the example, this density is inversely proportional to the gradient of a function.
[imagine for example that you have a distribution of the temperature in a 1D mesh, and you want to make the mesh denser in the parts of the mesh where the temperature gradient is higher]
This is what I coded so far:
% % % Initial fixed-step 1D mesh
X=(0:.01:2)';
% % % Values of a function at each mesh node [in this example, f(x)=5*sin(2*pi*x)*x ]
Y=5*sin(2*pi*X).*X;
% % % Calculate density of mesh points based on the Y function gradient
rho=[1e-9; abs(diff(Y))];
% % % Calculate x-steps from the original mesh
h = diff(X);
% % % Rescale the steps based on the inverse of the density
F = cumsum([0; h]./rho);
% % % Make sure F is between 0 and 1
F = F/F(end);
% % % Calculate the new mesh with scaled steps
X2 = X(1) + F * (X(end)-X(1));
% % % Interpolate the function Y at the new positions
Y2 = interp1(X,Y,X2);
% % % Plot
figure
subplot(2,1,1)
hold on
plot(X,Y,'ko-')
plot(X2,Y2,'r.-')
xlabel('x')
ylabel('y')
subplot(2,1,2)
plot(X,rho,'ko-')
xlabel('x')
ylabel('rho')
There are a few problems with this approach:
1. as you see from this example, there are big jumps when the density is very low (gradient almost zero). How could I implement a minimum/maximum time step size?
2. the node density is calculated correctly, but after "integrating" the unequal steps it can happen that the imposed large time step when the gradient is small causes to skip a high-gradient region that should have finer time-steps. [for example, please take a look at the region 1.8-1.9 in the example below, which should have small time step because it has high node density, but the large step size at ~1.75 causes to skip a large section of X]
Any suggestion to improve my code will be appreciated!
Calculate the cumulative sum (CDF) of rho. Take equally spaced samples from the CDF. Map from CDF to X to get new X3. Map from X3 to Y to get Y3:
CDF = cumsum(rho);
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF)+1).';
eq_smpl = eq_smpl(1:end-1) + diff(eq_smpl)/2; %use center points
X3 = interp1(CDF, X, eq_smpl);
Y3 = interp1(X, Y, X3);
plot(X3,Y3,'ro-')
hold on
plot(X,Y,'k.')
The third subplot shows the the result.
rahnema1's answer gave me a huge help, but there were still two remaining issues:
1- the first element of the new mesh is not identical to the first element of the original mesh
2- in case the gradient is zero at some point, the interp1 function will give error ["The grid vectors are not strictly monotonic increasing."]
For the 1st point, I replaced the two lines defining eq_smpl with the following line:
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF))';
[taking as many elements as CDF, and not centering the points]
For the 2nd point, I added a line after the calculation of rho to replace eventual 0 with small non-zero values:
rho(rho==0)=1e-12;
The final code that does what I want is the following:
% % % Initial fixed-step 1D mesh
X=(0:.01:2)';
% % % Values of a function at each mesh node [in this example, f(x)=5*sin(2*pi*x)*x ]
Y=5*sin(2*pi*X).*X;
% % % Calculate density of mesh points based on the Y function gradient
rho=[0; abs(diff(Y)./abs(diff(X)))];
% % % Replace eventual 0 with small non-zero values
rho(rho==0)=1e-12;
CDF = cumsum(rho);
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF))';
% % % Calculate new mesh
X3 = interp1(CDF, X, eq_smpl);
% % % Interpolate the function Y at the new positions
Y3 = interp1(X, Y, X3);
% % % Plot
figure
subplot(2,1,1)
hold on
plot(X,Y,'ko-')
plot(X3,Y3,'r.-')
xlabel('x')
ylabel('y')
subplot(2,1,2)
plot(X,rho,'ko-')
xlabel('x')
ylabel('rho')
Thank you again to rahnema1 for providing 90% of the answer [probably I didn't explain very well the original request]!

Matlab's hist3, which axis corresponds to X and which one to Y

So suppose you pass some matrix N to hist3 in Matlab, which is a m-by-2 matrix, simply for an example purposes. Where the first column is your variable X and column 2 corresponds to your variable Y.
When you run the cnt = hist3(N, {bins_X bins_Y}), you would get a m-by-m matrix. Rows here are which variable, X or Y?
OP seems to have solved his problem. However, I am leaving a code snippet exemplifying hist3's output indexing in case anyone finds it useful.
% Simulate random 2-column matrix
X = randn(1e5,2);
% Scale x-axis data to see label distinction
X(:,1) = X(:,1)*10;
% Define bins
bin_x = linspace(-30,30,80);
bin_y = linspace(-3,3,100);
% Get frequency grid
cnt = hist3(X,{bin_x,bin_y});
% Plot frequency values with surf
[x,y] = meshgrid(bin_x,bin_y);
figure
surf(x,y,cnt')
title('Original hist3 output')
xlabel('First Column')
ylabel('Second Column')
zlabel('Frequency')
% Access and modify cnt, and plot again
cnt(end,1:10) = 60;
cnt(25:55,1:55)= 0;
figure
surf(x,y,cnt')
title('Modified hist3 output')
xlabel('First Column')
ylabel('Second Column')
zlabel('Frequency')

How to plot colorful histogram type constellation diagram in Matlab

I would like to plot constellation diagram similar to the figure below.
.
My approach is something like this
clc;
clear all;
close all;
N=30000;
M=16;
Sr=randint(N,1,[0,(M-1)]);
S=qammod(Sr,16,0,'gray'); S=S(:);
Noisy_Data=awgn(S,20,'measured'); % Add AWGN
figure(2)
subplot(1,2,1)
plot(S,'o','markersize',10);
grid on
subplot(1,2,2)
plot(Noisy_Data,'.');
grid on
May you assist me to make necessary modification to get graph similar to the figure attached above. Thank you.
The first thing to do would be to compute a 2D histogram of your data. This can be done with the following:
% Size of the histogram matrix
Nx = 160;
Ny = 160;
% Choose the bounds of the histogram to match min/max of data samples.
% (you could alternatively use fixed bound, e.g. +/- 4)
ValMaxX = max(real(Noisy_Data));
ValMinX = min(real(Noisy_Data));
ValMaxY = max(imag(Noisy_Data));
ValMinY = min(imag(Noisy_Data));
dX = (ValMaxX-ValMinX)/(Nx-1);
dY = (ValMaxY-ValMinY)/(Ny-1);
% Figure out which bin each data sample fall into
IdxX = 1+floor((real(Noisy_Data)-ValMinX)/dX);
IdxY = 1+floor((imag(Noisy_Data)-ValMinY)/dY);
H = zeros(Ny,Nx);
for i=1:N
if (IdxX(i) >= 1 && IdxX(i) <= Nx && IdxY(i) >= 1 && IdxY(i) <= Ny)
% Increment histogram count
H(IdxY(i),IdxX(i)) = H(IdxY(i),IdxX(i)) + 1;
end
end
Note that you can play around with parameters Nx and Ny to adjust the desired resolution of the plot. Keep in mind that the larger the histogram, the more data samples (controlled by the parameter N of your simulation) you'll need to have enough data in the histogram bins to avoid getting a spotty plot.
You can then plot the histogram as a color map based on this answer. In doing so, you likely would want to add a constant to all non-zero bins of the histogram so that the white band is reserved for zero valued bins. This would provide a better correlation with the scatter plot. This can be done with:
% Colormap that approximate the sample figures you've posted
map = [1 1 1;0 0 1;0 1 1;1 1 0;1 0 0];
% Boost histogram values greater than zero so they don't fall in the
% white band of the colormap.
S = size(map,1);
Hmax = max(max(H));
bias = (Hmax-S)/(S-1);
idx = find(H>0);
H(idx) = H(idx) + bias;
% Plot the histogram
pcolor([0:Nx-1]*dX+ValMinX, [0:Ny-1]*dY+ValMinY, H);
shading flat;
colormap(map);
After increasing N to 1000000, this gives the following plot for the data generated according to your sample:

scatter plot over boxplot using Matlab

I've plotted a simple boxplot of a vector y (1xN) using Matlab. I used multiple grouping variables: x1, x2, x3
x1 (1xN) represents length (0.5, 1 , 2 or 3)
x2 (1xN) represents gauge (26 or 30)
x3 (1xN cell array) represents the name of the vendor.
close all; clc;
N = 1000;
% measurements values: they represent some kind of an
% electrical characteristic of a cable.
y = randn(N,1);
% each cable being measured can be of length 1m, 2m, or 3m:
x1 = randi(3,N,1);
% each cable being measured have a gauge of 1awg or 2awg:
x2 = randi(2,N,1);
% each cable can be produced by a different vendor. for instance: 'SONY' or
% 'YAMAHA'
x3 = cell(N,1);
for ii = 1:N
if mod(ii,3) == 0
x3{ii} = 'SONY';
else
x3{ii} = 'YAMAHA';
end
end
figure(1)
boxplot(y,{x1,x2,x3});
I would like to plot a scatter plot over this boxplot in order to show the relevant values of y that create the boxplot, but I could not find a function that groups the values as the boxplot function does.
the closest thing I've found is the following function but it only accepts a single grouping variable.
any help?
The box of the boxplot is determined by the IQR. The data between boxes and outliers is everything in a range of 1.5*IQR from the upper and lower quartile. You can filter the data manually.
For instance...
% data generation
data=randn(100,3);
%%
datas=sort(data);
datainbox=datas(ceil(end/4)+1:floor(end*3/4),:);
[n1 n2]=size(datainbox);
figure(1);clf
boxplot(data); hold on
plot(ones(n1,1)*[1 2 3],datainbox,'k.')
%%
% All datapoints coincide now horizontally. Consider adding a little random
% horizontal play to make them not coincide:
figure(2);clf
boxplot(data); hold on
plot(ones(n1,1)*[1 2 3]+.4*(rand(n1,n2)-.5),datainbox,'k.')
%%
% If you want to add all data between boxes and outliers too, do something like:
dataoutbox=datas([1:ceil(end/4) floor(end*3/4)+1:end],:);
n3=size(dataoutbox,1);
% calculate quartiles
dataq=quantile(data,[.25 .5 .75]);
% calculate range between box and outliers = between 1.5*IQR from quartiles
dataiqr=iqr(data);
datar=[dataq(1,:)-dataiqr*1.5;dataq(3,:)+dataiqr*1.5];
dataoutbox(dataoutbox<ones(n3,1)*datar(1,:)|dataoutbox>ones(n3,1)*datar(2,:))=nan;
figure(3);clf
boxplot(data); hold on
plot(ones(n1,1)*[1 2 3]+.4*(rand(n1,n2)-.5),datainbox,'k.')
plot(ones(n3,1)*[1 2 3]+.4*(rand(n3,n2)-.5),dataoutbox,'.','color',[1 1 1]*.5)
found a simple solution:
I edited the signature of the 'boxplot' function so it will return 'groupIndexByPoint' in addition to 'h':
function [h,groupIndexByPoint] = boxplot(varargin)
groupIndexByPoint is an internal variable used by 'boxplot'.
and now simply add 4 lines to the original code:
N = 1000;
% measurements values: they represent some kind of an
% electrical characteristic of a cable.
y = randn(N,1);
% each cable being measured can be of length 1m, 2m, or 3m:
x1 = randi(3,N,1);
% each cable being measured have a gauge of 1awg or 2awg:
x2 = randi(2,N,1);
% each cable can be produced by a different vendor. for instance: 'SONY' or
% 'YAMAHA'
x3 = cell(N,1);
for ii = 1:N
if mod(ii,3) == 0
x3{ii} = 'SONY';
else
x3{ii} = 'YAMAHA';
end
end
figure(1);
hold on;
[h,groups] = boxplot(y,{x1,x2,x3});
scattering_factor = 0.3;
scaterring_vector = (rand(N,1)-0.5)*scattering_factor;
groups_scattered = groups + scaterring_vector;
plot(groups_scattered,y,'.g');