how to produce this particular 3D graph from scalar data in Matlab? - matlab

I am trying to produce this graph using Matlab. The built-in ellipsoid function is confusing. For this problem I have two variables ( width and length ) and a constant height.
to make it very simple I want to show that the width is changing while we approach the tip but height is constant. w,x,h are the variables shown in the graph.
I would really appreciate it if someone can help.

The following code gets you a long way, I think. See example output:
I added enought comments that you should be able to take it from here...
% plot ellipsoid in 3D
% height and width of ellipsoid:
e_h = 10;
e_w = 3;
% position where the "quivers" (arrows) go:
q_offset = 2; % distance from axis
q_scale = 0.5; % multiplier to give parabola some size
q_spacing = 0.5; % distance between arrows
q_height = 2.5; % height above XY plane where arrows are drawn
N = 1000; % number of points for drawing
theta = linspace(0, 2*pi, N); % parameter to help drawing ellipse
zerov = zeros(1, N); % array of zeros that I will need
% coordinates of main ellipse:
x = e_w * sin(theta);
y = zeros(size(x));
z = e_h * cos(theta);
% plot main ellipse:
figure;
plot3(x, y, z)
% secondary plot
y2 = q_scale*(e_w.^2 - x.^2) + 2; % offset parabola - what your plot looked like...
hold on
plot3(x, y2, zerov+q_height); % plotting the parabola in the XY plane at height
axis equal % make the plot dimensions isotropic
% add quivers
q_base = -e_w:q_spacing:e_w; % x coordinate; y and z are fixed
q_length = (e_w.^2 - q_base.^2)*q_scale; % length of quiver - just an equation I chose
q0 = zeros(size(q_base)); % another vector I will need multiple times
q1 = ones(size(q_base)); % ditto
% plot the arrows: the "-1" argument means "don't scale"
quiver3(q_base, q0+q_offset, q_height*q1, q0, q_length, q0, -1)

Related

Creating a circle in a square grid

I try to solve the following 2D elliptic PDE electrostatic problem by fixing the Parallel plate Capacitors code. But I have problem to plot the circle region. How can I plot a circle region rather than the square?
% I use following two lines to label the 50V and 100V squares
% (but it should be two circles)
V(pp1-r_circle_small:pp1+r_circle_small,pp1-r_circle_small:pp1+r_circle_small) = 50;
V(pp2-r_circle_big:pp2+r_circle_big,pp2-r_circle_big:pp2+r_circle_big) = 100;
% Contour Display for electric potential
figure(1)
contour_range_V = -101:0.5:101;
contour(x,y,V,contour_range_V,'linewidth',0.5);
axis([min(x) max(x) min(y) max(y)]);
colorbar('location','eastoutside','fontsize',10);
xlabel('x-axis in meters','fontsize',10);
ylabel('y-axis in meters','fontsize',10);
title('Electric Potential distribution, V(x,y) in volts','fontsize',14);
h1=gca;
set(h1,'fontsize',10);
fh1 = figure(1);
set(fh1, 'color', 'white')
% Contour Display for electric field
figure(2)
contour_range_E = -20:0.05:20;
contour(x,y,E,contour_range_E,'linewidth',0.5);
axis([min(x) max(x) min(y) max(y)]);
colorbar('location','eastoutside','fontsize',10);
xlabel('x-axis in meters','fontsize',10);
ylabel('y-axis in meters','fontsize',10);
title('Electric field distribution, E (x,y) in V/m','fontsize',14);
h2=gca;
set(h2,'fontsize',10);
fh2 = figure(2);
set(fh2, 'color', 'white')
You're creating a square due to the way you're indexing (see this post on indexing). You've specified the rows to run from pp1-r_circle_small to pp1+r_circle_small and similar for the columns. Given that Swiss cheese is not an option, you're creating a complete square.
From geometry we know that all points within distance sqrt((X-X0)^2 - (Y-Y0)^2) < R from the centre of the circle at (X0,Y0) with radius R are within the circle, and the rest outside. This means that you can simply build a mask:
% Set up your grid
Xsize = 30; % Your case: 1
Ysize = 30; % Your case: 1
step = 1; % Amount of gridpoints; use 0.001 or something
% Build indexing grid for circle search, adapt as necessary
X = 0:step:Xsize;
Y = 0:step:Ysize;
[XX,YY] = meshgrid(X, Y);
V = zeros(numel(X), numel(Y));
% Repeat the below for both circles
R = 10; % Radius of your circle; your case 0.1 and 0.15
X0 = 11; % X coordinate of the circle's origin; your case 0.3 and 0.7
Y0 = 15; % Y coordinate of the circle's origin; your case 0.3 and 0.7
% Logical check to see whether a point is inside or outside
mask = sqrt( (XX - X0).^2 + (YY - Y0).^2) < R;
V(mask) = 50; % Give your circle the desired value
imagesc(V) % Just to show you the result
axis equal % Use equal axis to have no image distortion
mask is a logical matrix containing 1 where points are within your circle and 0 where points are outside. You can then use this mask to logically index your potential grid V to set it to the desired value.
Note: This will, obviously, not create a perfect circle, given you cannot plot a perfect circle on a square grid. The finer the grid, the more circle-like your "circle" will be. This shows the result with step = 0.01
Note 2: You'll need to tweek your definition of X, Y, X0, Y0 and R to match your values.

Fancy Correlation Plots in MATLAB

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

How to show a zoomed part of a graph within a MATLAB plot?

I have about four series of data on a Matlab plot, two of them are quite close and can only be differentiated with a zoom. How do I depict the zoomed part within the existing plot for the viewer. I have checked similar posts but the answers seem very unclear.
I look for something like this:
Here is a suggestion how to do this with MATLAB. It may need some fine tuning, but it will give you the result:
function pan = zoomin(ax,areaToMagnify,panPosition)
% AX is a handle to the axes to magnify
% AREATOMAGNIFY is the area to magnify, given by a 4-element vector that defines the
% lower-left and upper-right corners of a rectangle [x1 y1 x2 y2]
% PANPOSTION is the position of the magnifying pan in the figure, defined by
% the normalized units of the figure [x y w h]
%
fig = ax.Parent;
pan = copyobj(ax,fig);
pan.Position = panPosition;
pan.XLim = areaToMagnify([1 3]);
pan.YLim = areaToMagnify([2 4]);
pan.XTick = [];
pan.YTick = [];
rectangle(ax,'Position',...
[areaToMagnify(1:2) areaToMagnify(3:4)-areaToMagnify(1:2)])
xy = ax2annot(ax,areaToMagnify([1 4;3 2]));
annotation(fig,'line',[xy(1,1) panPosition(1)],...
[xy(1,2) panPosition(2)+panPosition(4)],'Color','k')
annotation(fig,'line',[xy(2,1) panPosition(1)+panPosition(3)],...
[xy(2,2) panPosition(2)],'Color','k')
end
function anxy = ax2annot(ax,xy)
% This function converts the axis unites to the figure normalized unites
% AX is a handle to the figure
% XY is a n-by-2 matrix, where the first column is the x values and the
% second is the y values
% ANXY is a matrix in the same size of XY, but with all the values
% converted to normalized units
pos = ax.Position;
% white area * ((value - axis min) / axis length) + gray area
normx = pos(3)*((xy(:,1)-ax.XLim(1))./range(ax.XLim))+ pos(1);
normy = pos(4)*((xy(:,2)-ax.YLim(1))./range(ax.YLim))+ pos(2);
anxy = [normx normy];
end
Note that the units of areaToMagnify are like the axis units, while the units of panPosition are between 0 to 1, like the position property in MATLAB.
Here is an example:
x = -5:0.1:5;
subplot(3,3,[4 5 7 8])
plot(x,cos(x-2),x,sin(x),x,-x-0.5,x,0.1.*x+0.1)
ax = gca;
area = [-0.4 -0.4 0.25 0.25];
inlarge = subplot(3,3,3);
panpos = inlarge.Position;
delete(inlarge);
inlarge = zoomin(ax,area,panpos);
title(inlarge,'Zoom in')

Replace quiver arrowheads with images

I have a circular lattice and on the lattice sites I plot normalized arrows that remain in the same magnitude and change direction according to a simulation, the details of which don't matter.
My plots look like this
Is it possible to replace the arrow in the quiver plot by an jpg/bmp/gif/png image? or by any other command?
Ideally, it would look something like this (although not necessarily arrows)
Explanation
One way that you can do this, would be to use a surface object with a texture-map as the FaceColor.
In MATLAB, you can create a simple rectangular surface. You can set the FaceColor to be texturemap which will cause the value assigned to CData to be mapped across the surface.
Then to get transparency, you can also set the FaceAlpha value to be texturemap and set the AlphaData and those transparency values will be mapped across the extent of the surface as well.
For this to be applied to your case, you want to set the CData to the image that you want to use to replace your arrows. And you will want the AlphaData to be the same size as your image data with values of 1 where you want it to be opaque and 0 where you want it to be transparent. This will allow it to not look like the image that you have posted where you can clearly see the bounding box. Then you will need to draw one of these surfaces where each of the arrows would go and scale/position it appropriately.
Implementation
Update: A more polished version of this code (ImageQuiver) is now available on Github as well as the MATLAB File Exchange.
As a demonstration of what I'm talking about, I have created the following function which essentially does just this. It accepts the same inputs as quiver (with the image data being supplied first and an optional AlphaData parameter at the end) and creates a surface at all of the requested coordinates pointing in the requested direction, and scaled by the specified amount.
function h = quiverpic(im, X, Y, dX, dY, scale, alpha)
% im - RGB or indexed image
% X - X positions
% Y - Y positions
% dX - X direction vector
% dY - Y direction vector
% scale - Any scaling (Default = 1)
% alpha - Transparency (same size as im), if not specified = ~isnan(im)
h = hggroup();
if ~exist('scale', 'var')
% By default there is no scaling
scale = 1;
end
if ~exist('alpha', 'var')
% By default, any NaN will be transparent
alpha = ~isnan(im);
end
% Determine aspect ratio of the source image
width_to_height = size(im, 2) / size(im, 1);
for k = 1:numel(X)
% Determine angle from displacement vectors
theta = atan2(dY(k), dX(k));
% Subtract pi/2 to +y is considered "up"
theta = theta + pi/2;
% Setup surface plot boundary
[xx,yy] = meshgrid([-0.5, 0.5] * width_to_height, [0 1]);
% Scale depending on magnitude of dX and dY
this_scale = scale * sqrt(dX(k).^2 + dY(k).^2);
% Scale X and Y components prior to rotating
xx = xx .* this_scale;
yy = yy .* this_scale;
% Rotate to align with the desired direction
xdata = xx .* cos(theta) - yy .* sin(theta);
ydata = xx .* sin(theta) + yy .* cos(theta);
% Determine what is considered the "anchor" of the graphic.
% For now this is assumed to be the "bottom-middle"
xoffset = X(k) - mean(xdata(2,:));
yoffset = Y(k) - mean(ydata(2,:));
% Actually plot the surface.
surf(xdata + xoffset, ...
ydata + yoffset, zeros(2), ...
'Parent', h, ...
'FaceColor', 'texture', ...
'EdgeColor', 'none', ...
'CData', im, ...
'FaceAlpha', 'texture', ...
'AlphaData', double(alpha));
end
end
Example
I wrote a little test script to show how this can be used and to show the results.
t = linspace(0, 2*pi, 13);
dX = cos(t(1:end-1));
dY = sin(t(1:end-1));
X = (3 * dX) + 5;
Y = (3 * dY) + 5;
scale = 1;
% Load the MATLAB logo as an example image
png = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
[im, map] = imread(png);
im = ind2rgb(im, map);
% Determine alpha channel based on upper left hand corner pixel
flatim = reshape(im, [], 3);
alpha = ~ismember(flatim, squeeze(im(1,1,:)).', 'rows');
alpha = reshape(alpha, size(im(:,:,1)));
% Plot some things prior to creating the quiverpic object
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'equal');
% Plot a full circle
t = linspace(0, 2*pi, 100);
plot((cos(t) * 3) + 5, (sin(t) * 3) + 5, '-')
hold(hax, 'on')
% Plot markers at all the quiver centers
plot(X, Y, 'o', 'MarkerFaceColor', 'w')
% Plot a random image behind everything to demonstrate transparency
him = imagesc(rand(9));
uistack(him, 'bottom')
axis(hax, 'equal')
colormap(fig, 'gray')
set(hax, 'clim', [-4 4]);
% Now plot the quiverpic
h = quiverpic(im, X, Y, dX, dY, 1, alpha);
axis(hax, 'tight')
Results
Absurdity
Same image with varying vectors and scaling
Any image of any aspect ratio will work just fine

visualization of light waves superposition in matlab

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,[])