Related
I'm trying to find a way to generate these pretty correlation plots in MATLAB. These are generated in R using 'corrplot' function, but couldn't find any similar code in MATLAB. Any help would be appreciated.
As a quick description, this function will create a color scale of the correlation values, and create circles in each cell of the correlation matrix/plot with the associated color. The size of the circles is also an indicator of the magnitude of the correlation, with larger circles representing a stronger relationship (positive or negative). More details could be found here.
you can use plot-corrmat (or modify it, depending how articulate you are in matlab), to obtain similar visualizations of correlation matrices (top pic). Or use Correlation circles , that looks somewhat similar as well (bottom pic)...
https://github.com/elayden/plot-corrmat
I could write the below code to generate a similar graph, based on the code provided here
% Produce the input lower triangular matrix data
C = -1 + 2.*rand(12,12);
C = tril(C,-1);
C(logical(eye(size(C)))) = 1;
% Set [min,max] value of C to scale colors
clrLim = [-1,1];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
myLabel = {'ICA','Elev','Pr','Rmax','Rmin','Srad','Wspd','Tmin','Tmax','VPD','ET_o','AW'};
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(C,2); % x edges
y = 1 : 1 : size(C,1); % y edges
[xAll, yAll] = meshgrid(x,y);
xAll(C==0)=nan; % eliminate cordinates for zero correlations
% Set color of each rectangle
% Set color scale
cmap = jet(256);
% cmap = CorrColormap; % Uncomment for CorrColormap
Cscaled = (C - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size between [0 1]
Cscaled = (abs(C) - 0)/1;
diamSize = Cscaled * range(diamLim) + diamLim(1);
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'jet');
% colormap(CorrColormap) %Uncomment for CorrColormap
tickvalues = 1:length(C);
x = zeros(size(tickvalues));
text(x, tickvalues, myLabel, 'HorizontalAlignment', 'right');
x(:) = length(C)+1;
text(tickvalues, x, myLabel, 'HorizontalAlignment', 'right','Rotation',90);
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
h = arrayfun(#(i)fill(diamSize(i)/2 * cos(theta) + xAll(i), ...
diamSize(i)/2 * sin(theta) + yAll(i), cmap(colIdx(i),:),'LineStyle','none'),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
axis off
The exact graph is available here:
Fancy Correlation Plots in MATLAB
I'm trying to fill an area between two curves with respect to a function which depends on the values of the curves.
Here is the code of what I've managed to do so far
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
N=[n_vec,fliplr(n_vec)];
X=[x_vec,fliplr(y_vec)];
figure(1)
subplot(2,1,1)
hold on
plot(n_vec,x_vec,n_vec,y_vec)
hp = patch(N,X,'b')
plot([n_vec(i) n_vec(i)],[x_vec(i),y_vec(i)],'linewidth',5)
xlabel('n'); ylabel('x')
subplot(2,1,2)
xx = linspace(y_vec(i),x_vec(i),100);
plot(xx,cc(xx,y_vec(i),x_vec(i)))
xlabel('x'); ylabel('c(x)')
This code produces the following graph
The color code which I've added represent the color coding that each line (along the y axis at a point on the x axis) from the area between the two curves should be.
Overall, the entire area should be filled with a gradient color which depends on the values of the curves.
I've assisted the following previous questions but could not resolve a solution
MATLAB fill area between lines
Patch circle by a color gradient
Filling between two curves, according to a colormap given by a function MATLAB
NOTE: there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
The surf plot method
The same as the scatter plot method, i.e. generate a point grid.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
Generate a logical array indicating whether the points are inside the polygon, but no need to extract the points:
in = inpolygon(px, py, N, X);
Generate Z. The value of Z indicates the color to use for the surface plot. Hence, it is generated using the your function cc.
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
Set Z values for points outside the area of interest to NaN so MATLAB won't plot them.
pz(~in) = nan;
Generate a bounded colourmap (delete if you want to use full colour range)
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
Finally, plot.
figure;
colormap(jet)
surf(px,py,pz,'edgecolor','none');
view(2) % x-y view
Feel free to turn the image arround to see how it looks like in the Z-dimention - beautiful :)
Full code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
% generate z
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
pz(~in) = nan;
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
% plot
figure;
colormap(c)
surf(px,py,pz,'edgecolor','none');
view(2)
You can use imagesc and meshgrids. See comments in the code to understand what's going on.
Downsample your data
% your initial upper and lower boundaries
n_vec_long = linspace(2,10,1000000);
f_ub_vec_long = linspace(2, 10, length(n_vec_long));
f_lb_vec_long = abs(sin(n_vec_long));
% downsample
n_vec = linspace(n_vec_long(1), n_vec_long(end), 1000); % for example, only 1000 points
% get upper and lower boundary values for n_vec
f_ub_vec = interp1(n_vec_long, f_ub_vec_long, n_vec);
f_lb_vec = interp1(n_vec_long, f_lb_vec_long, n_vec);
% x_vec for the color function
x_vec = 0:0.01:10;
Plot the data
% create a 2D matrix with N and X position
[N, X] = meshgrid(n_vec, x_vec);
% evaluate the upper and lower boundary functions at n_vec
% can be any function at n you want (not tested for crossing boundaries though...)
f_ub_vec = linspace(2, 10, length(n_vec));
f_lb_vec = abs(sin(n_vec));
% make these row vectors into matrices, to create a boolean mask
F_UB = repmat(f_ub_vec, [size(N, 1) 1]);
F_LB = repmat(f_lb_vec, [size(N, 1) 1]);
% create a mask based on the upper and lower boundary functions
mask = true(size(N));
mask(X > F_UB | X < F_LB) = false;
% create data matrix
Z = NaN(size(N));
% create function that evaluates the color profile for each defined value
% in the vectors with the lower and upper bounds
zc = #(X, ub, lb) 1 ./ (1 + (exp(-X) ./ (exp(-ub) - exp(-lb))));
CData = zc(X, f_lb_vec, f_ub_vec); % create the c(x) at all X
% put the CData in Z, but only between the lower and upper bound.
Z(mask) = CData(mask);
% normalize Z along 1st dim
Z = normalize(Z, 1, 'range'); % get all values between 0 and 1 for colorbar
% draw a figure!
figure(1); clf;
ax = axes; % create some axes
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
xlabel('n')
ylabel('x')
This already looks kinda like what you want, but let's get rid of the blue area outside the boundaries. This can be done by creating an 'alpha mask', i.e. set the alpha value for all pixels outside the previously defined mask to 0:
figure(2); clf;
ax = axes; % create some axes
hold on;
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
% set a colormap
colormap(flip(hsv(100)))
% set alpha for points outside mask
Calpha = ones(size(N));
Calpha(~mask) = 0;
sc.AlphaData = Calpha;
% plot the other lines
plot(n_vec, f_ub_vec, 'k', n_vec, f_lb_vec, 'k' ,'linewidth', 1)
% set axis limits
xlim([min(n_vec), max(n_vec)])
ylim([min(x_vec), max(x_vec)])
there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
It is difficult to achieve this using patch.
However, you may use scatter plots to "fill" the area with coloured dots. Alternatively, and probably better, use surf plot and generate z coordinates using your cc function (See my seperate solution).
The scatter plot method
First, make a grid of points (resolution 500*500) inside the rectangular space bounding the two curves.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
figure;
scatter(px(:), py(:), 1, 'r');
The not-interesting figure of the point grid:
Next, extract the points inside the polygon defined by the two curves.
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
hold on;
scatter(px, py, 1, 'k');
Black points are inside the area:
Finally, create color and plot the nice looking gradient colour figure.
% create color for the points
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s'); % use size 16, filled square markers.
Note that you may need a fairly dense grid of points to make sure the white background won't show up. You may also change the point size to a bigger value (won't impact performance).
Of cause, you may use patch to replace scatter but you will need to work out the vertices and face ids, then you may patch each faces separately with patch('Faces',F,'Vertices',V). Using patch this way may impact performance.
Complete code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate point grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
% generate color
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s');
I'm very new to Matlab. I'm learning some image manipulation basics, and I'm a bit confused on how to write a translation without using imtranslate.
this is my code but it just displays a black background. Thank you.
img = imread('name2.png');
figure(1);
% pixel matrix
[orig_x, orig_y,z] = size(img);
final_x = 600;
final_y = 600;
% define the final array with calculated dimensions and fill the array with zeros ie.,black
final_img = uint8(zeros([final_x final_y 3 ]));
for i = 1 : size(final_img, 1)
for j = 1 : size(final_img, 2)
new_x = img(i) + 5;
new_y = img(j) + 5;
% fprintf('X: %f\n',new_x); % prints 255
final_img(i) = new_x;
final_img(j) = new_y;
end
end
imshow(final_img);
This is one solution for 'translation only' transformation.
I = imread('Lenna.png');
shiftX = 5; % shift columns
shiftY = 5; % shift rows
% Assigning empty matrix for result, expected to be shiftX-1 larger in rows and shiftY-1 larger in columns
nI = uint8( zeros(size(I,1)+shiftY-1, size(I,2)+shiftX-1, size(I,3));
% Translate
nI(shiftY:end, shiftX:end, :) = I;
imshow(nI)
Now the image will start from (x,y) = (5,5) instead of (1,1). Also note that in matlab image coordinate system, x and y axis start from upper left corner (documentation).
final_img:
You've defined "final_img" with new x and new y but you haven't replaced the zeros in the red/green/blue values. It's all black because of your initialisation filling the final_img with all zeros.
Maybe try this instead of what you've written:
%{
[X,map] = imread('name2.png');
figure(1);
% X should be 600 by 600
%Translate X however you wish, e.g.:
X = X +5;
%Verify that the colormap, map, is not empty, and convert
%the data in X to RGB and store as your final_img.
if ~isempty(map)
final_img = ind2rgb(X,map);
end
%}
I am also not sure if you want to be indexing img with just a single i without the the other dimensions like you have:
new_x = img(i) + 5;
?
For the problems in your specific code, I wrote in the comments some of them.
A short way to achieve image translation is by 2D convolution with a filter of zeros and just one 1, that will preserve the values of the image, but relocate them according to the size of the filter and the position of the 1 in it.
That seems you want to move the image but preserve the size of the total image, if I get it right. So:
r=3; c=5; % number of rows and columns to move
filt=zeros(r*2+1, c*2+1); filt(end)=1; % the filetr
img2=conv2(img,filt,'same'); % the translated image
Just for the example, lets translate "cameraman" with 20 rows and columns:
img=imread('cameraman.tif');
imshow(img)
r=20; c=20;
filt=zeros(r*2+1, c*2+1); filt(end)=1;
img2=conv2(img,filt,'same');
figure; imshow(img2,[])
I have a image of low resolution, 128x128 pixels. I need to obtain the mean value of a circle ROI, in order to do that I use the easy method:
%% Draw circle ROI
t = 0:pi/500:2*pi;
xi = ((R0/pixelSize)*cos(t)+63.5+x0+((Rsphere)/pixelSize)*cos(theta))*4;
yi = ((R0/pixelSize)*sin(t)+63.5+y0+((Rsphere)/pixelSize)*sin(theta))*4;
%% Calculate roi statistics
line(xi,yi,'LineWidth',1,'Color',color);
ROImask = poly2mask(xi,yi, size(im,1),size(im,2));
ptROI = find(ROImask);
ROImean = mean(im(ptROI));
The problem here is that using this method I don't account for the partial value of a pixel in the ROI, as can be seen in the image.
Is there any direct way to obtain the mean of the ROI weighting the value of the pixels?
Thanks
If you really want to do this exactly, you'll need to do some calculus (integral of a circle on a square domain for each pixel). But, this probably overkill for your application. My suggestion is to calculate your circle on a fine grid, then resize it to match the image:
upFactor = 3;
% load built-in example image
x = imread('rice.png');
% convert to double
x = im2double(x);
% define the ROI
center = [68.5, 180]; % [row, column]
radius = 1; % pixels
% do the distance calculation
% (getting the coordinate systems to match is the hardest part, try making
% small examples to see how it works)
iVector = (0:size(x,1)*upFactor-1)/upFactor + .5 + 1/upFactor/2;
jVector = (0:size(x,2)*upFactor-1)/upFactor + .5 + 1/upFactor/2;
[I, J] = ndgrid( iVector - center(1), jVector - center(2));
sqDist = I.^2 + J.^2;
insideBig = double(sqDist <= radius^2); % need this to not be logical type
% this resizes back to the original image size my taking the mean of each
% upFactor by upFactor block
inside = reshape( mean( im2col( insideBig, [upFactor upFactor], 'distinct')), size(x));
% check that we have the values we expect
uniqueVals = unique(inside(:))
% show examples
figure
imagesc(x)
figure
imagesc(inside)
result = sum(sum( x .* inside )) / sum(inside(:))
I wrote some quick code for visualization of superposition of two waves with different amplitudes in space, point source geometry. this works at khanacademy CS platform. http://www.khanacademy.org/cs/superposition/1245709541 but i cant reproduce the exact phenomena in matlab. all i get is a noisy image. Is this something to do with difference in random number generation? I have no idea how different random(0,1)(in JS) and rand(in matlab) are.
here is the matlab code
A wave superposition function for a point x,y on image plane
function S = Super(refamp,objamp,x,y,a,lambda)
r1 = sqrt(a*a+x*x+y*y); %a is in z-axis
S = refamp+(objamp*cos(2*pi*r1/(lambda/(10^6))));
The test script
close all;
clear all;
clc;
a=10; %distance from source to image plane
width = 1024;
height =1024;
im = zeros(width); % the image
x=1;
y=1;
A0 = 3; % amplitude of reference wave
A1 = 1; % amplitude of object wave A0>>A1: A0/A1>=3
lambda = 632; % wavelength in nanometers
% generate the superposition in space width*height at a along z-axis
for y=1:height
for x=1:width
s = Super(A0,A1,x-(width/2),y-(height/2),a, lambda);
r=rand;
if(r<(s/(A0+A1)))
im(x,y) = 1;
end
end
%display the image
figure
imshow(im,[])
title('test image')
The main problem is that your scales are off, so you aren't seeing the interference pattern. If you play around with how big/far everything is, it will work out right and you can see the pattern.
The second problem is that your code would really benefit from vectorization. I've shown this below - doing it this way speeds up the execution dramatically.
function Interference
a=1000 * 10^-9; #% distance from source to image plane
width = 10000 * 10^-9;
height= 10000 * 10^-9;
size = 700;
A0 = 3; %# amplitude of reference wave
A1 = 1; %# amplitude of object wave A0>>A1: A0/A1>=3
lambda = 632 * 10^-9; #% wavelength in nanometers
x=linspace(0,width,size); #% vector from 0 to width
y=linspace(0,height,size); #% vector from 0 to height
[X,Y]=meshgrid(x,y); #% matrices of x and y values at each position
s=Super(A0, A1, X-(width/2), Y-(height/2), a, lambda); #% size-by-size (700x700)
r=rand(size); #% 700x700 matrix of random values on [0 1]
im = zeros(size);
im(r<(s/(A0+A1))) = 1; %# do this all at once instead of pixel-by-pixel
#% display the image
figure
imshow(im,[])
title('test image')
end #% end of function Interference
#% Super is now vectorized, so you can give it a matrix of values for x and y
function S = Super(refamp,objamp,x,y,a,lambda)
r1 = sqrt(a.*a+x.*x+y.*y); #% dot notation: multiply element-wise
S = refamp+(objamp*cos(2*pi*r1/(lambda)));
end #% end of function Super
function i = Interference(width, height, sizeh,sizev,z)
% parameters explained
% width: is the horizontal pixel pitch in microns
% height: is the vertical pixel pitch in microns
% size is the width=height of the CCD in number of pixels
% z is distance from source to image plane
A0 = 3; %# amplitude of reference wave
A1 = 1; %# amplitude of object wave A0>>A1: A0/A1>=3
lambda = 635 * 10^-9; % wavelength in nanometers
%the linspace was wrong
x=linspace(0,width*sizeh,sizeh); % vector from 0 to width of size 'size'
y=linspace(0,height*sizev,sizev); % vector from 0 to height of size 'size'
[X,Y]=meshgrid(x,y); % matrices of x and y values at each position
s=Super(A0, A1, X-((width*sizeh)/2), Y-((height*sizev)/2), z, lambda); % size-by-size (1024x1024)
r=rand(size); % 1024x1024 matrix of random values on [0 1]
%i=s;
im = zeros(size);
im(r<(s/(A0+A1))) = 1; %# do this all at once instead of pixel-by-pixel
i=im;
end % end of function Interference
% Super is now vectorized, so you can give it a matrix of values for x and y
function S = Super(refamp,objamp,x,y,a,lambda)
r1 = sqrt(a.*a+x.*x+y.*y); % dot notation: multiply element-wise
S = refamp+(objamp*cos(2*pi*r1/(lambda)));
end % end of function Super
usage of the function
width = 2.8 * 10^-6;
height= 2.8 * 10^-6; %pixel size
% sizeh = 16; %image size in pixels
% sizev = 16;
sizeh = 1600; %image size in pixels
sizev = 1200;
int_z = 100*10^-3; % z dist in m
% xes1 = 100;
%xes2 = ;
int_im = Interference(width,height,sizeh, sizev,int_z);
int_im = int_im/max(max(int_im)); % normalize
int_im = (int_im-0.5)*2; % enhance visualy
% display the image
figure
imshow(int_im,[])