How to generate a heatmap of a disk having its different temperatures? - matlab

I'm having some problems in generating heatmaps given a defined figure.
I'm studying the temperature at the point of contact between two surfaces, a disk and a cylinder that could be modelled as one-dimensional, compared to the disk.
I have 3 sets of data, 1 for the radius(r) of a disk, another one for the angle (Theta) of the contact point and a last one for the temperature of the contacting point where the friction occurs.
So far I am able to create the disk and the differents points in a simulation obtained via another program, that gives me the previous sets of data.
Where I have the trouble is when I want to link the temperature obtained to its point and giving it a colour scale based on its temperature. I don't know how to establish this relationship.
As I say, this is what I have arrived to, which is only the definition of the points given by the results of the simulation.
Theta = xlsread('Laiton1.xlsx',1,'G2:G3381'); % Parameter turning angle
r = xlsread('Laiton1.xlsx',1,'C2:C3381'); % Parameter radius
Tsurf_d = xlsread('Laiton1.xlsx',1,'E2:E3381'); % Temperature on the surface
x = r*cos(Theta'); % parametrical transformation of (r,Theta) for the X axis
y = r*sin(Theta'); % parametrical transformation of (r,Theta) for the Y axis
Theta1 = linspace(0,360,5000); % Angle to define the 2 circumferences of the disk
x1 = 0.0145*cos(Theta1); % X points for the inner circumerference
y1 = 0.0145*sin(Theta1); % Y points for the inner circumerference
x2 = 0.0475*cos(Theta1); % X points for the external circumerference
y2 = 0.0475*sin(Theta1); % Y points for the external circumerference
plot(X,Y,X1,Y1,'black',X2,Y2,'black')

I hope I understood your question right: You have three vectors of coordinates and measurements, and you wish to plot a heat map with these. The code below does this. Vary the parameter "resolution" in order to zoom in or out of the plot.
% Me simulating your data
numData = 100;
Theta = (0:2*pi/(numData-1):2*pi) + (rand(1,numData)-.5)/10;
r = 23 + (rand(1,numData)-.5);
Tsurf_d = rand(1,numData)*100;
% Creating a table on which you can gather your data for plotting
resolution = 1; % Smaller number -> bigger and fewer pixels
c = resolution*ceil(max(r)) + 1; % Which pixel will be your center coordinate
width = 2*c + 1; % The width and height of your table
tempSumMap = zeros(width);
numDataMap = zeros(width);
% Calculating corresponding positions of each data point
xCoords = round( resolution*r.*cos(Theta) );
yCoords = round( resolution*r.*sin(Theta) );
% Adding the data points. In situations where two data points want to add
% to the same pixel, they both add, and numDataMap remembers to later
% divide by 2
for dataNo = 1:numData
y = yCoords(dataNo) + c ;
x = xCoords(dataNo) + c ;
tempSumMap(y,x) = tempSumMap(y,x) + Tsurf_d(dataNo);
numDataMap(y,x) = numDataMap(y,x) + 1;
end
% Remember to divide by the number of times you added a certain temperature
% to a pixel
tempMap = tempSumMap./max(1,numDataMap);
% Display the result
imagesc(tempMap)

Related

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

Points distribution in n-dimension

How to distribute the points to be like Fig.A
This matlab code for Fig. B :
N = 30; % number of points
r = 0.5; % r = radius
d = 50; % dimension
C_point = 0; % center point
figure, clf
C = ones(1, d) * C_point;
C_rep = repmat( C,N,1);
X = randn(N,d);
s2 = sum(X.^2,2) ;
radius = r * (rand(N,1).^(1/d));
X = X.*repmat(radius./sqrt(s2),1,d) + C_rep;
%% Plot 2D
t = linspace(0, 2*pi, 100);
x = r*cos(t) + C(1);
y = r*sin(t) + C(2);
plot(x,y,'b')
hold on
plot(C(1),C(2),'b.', 'MarkerSize', 10) % center point
hold on
plot(X(:,1), X(:,2),'r.','markersize',10);
axis equal;rotate3d off; rotate3d on;drawnow;shg;
hold on
ax = axis;
Source of the code
What I should change to be like fig. A
The OP's code computes points uniformly distributed within a d-dimensional box, projects those onto a d-dimensional sphere, then samples the radius to move them inside the d-dimensional ball. This is perfect except that the points inside the box, when projected onto the sphere, do not form a uniform distribution on that sphere. If instead you find random points distributed in a Gaussian distribution, you are guaranteed uniform angle distribution.
First compute points with a Gaussian distribution in d dimensions (I do all here with minimal changes to the OP's code):
N = 1000; % number of points
r = 0.5; % r = radius
d = 3; % dimension
C_point = 0; % center point
C = ones(1,d) * C_point;
C_rep = repmat(C,N,1);
X = randn(N,d);
Note that I use randn, not rand. randn creates a Gaussian distribution.
Next we normalize the vectors so the points move to the sphere:
nX = sqrt(sum(X.^2,2));
X = X./repmat(nX,1,d);
These points are uniformly distributed, which you can verify by scatter3(X(:,1),X(:,2),X(:,3)); axis equal and turning the display around (a 2D rendering doesn't do it justice). This is the reason I set d=3 above, and N=1000. I wanted to be able to plot the points and see lots of them.
Next we compute, as you already did, a random distance to the origin, and correct it for the dimensionality:
radius = r * (rand(N,1).^(1/d));
X = X.*repmat(radius,1,d) + C_rep;
X now is distributed uniformly in the ball. Again, scatter3(X(:,1),X(:,2),X(:,3)); axis equal shows this.
However, if you set d=50 and then plot only two dimensions of your data, you will not see the data filling the circle. And you will not see a uniform distribution either. This is because you are projecting a 50-D ball onto 2 dimensions, this simply does not work. You either have to trust the math, or you have to slice the data:
figure, hold on
t = linspace(0, 2*pi, 100);
x = r*cos(t) + C(1);
y = r*sin(t) + C(2);
plot(x,y,'b')
plot(C(1),C(2),'b.', 'MarkerSize', 10) % center point
axis equal
I = all(abs(X(:,3:d))<0.1,2);
plot(X(I,1), X(I,2),'r.','markersize',10);
The I there indexes points that are close to the origin in dimensions perpendicular to the first two shown. Again, with d=50 you will have very few points there, so you will need to set N very large! To see the same density of points as in the case above, for every dimension you add, you need to multiply N by 10. So for d=5 you'd have N=1000*10*10=1e5, and for d=50 you'd need N=1e50. That is totally impossible to compute, of course.

Oblique to rectangular coordinate basis transformation of a matrix

I have my 2D-data stored in a [K,K] matrix. The indices represent coordinates (q_1, q_2) in the oblique coordinate system defined by its strain -0.5<gamma<0.5. The goal is to transform the data to a rectangular coordinate system, which is given by the coordinates:
q_x = q_1
q_y = q_2 - gamma*q_1
The result is illustrated in this picture:
The code below achieves this transformation on a pixel-by-pixel basis. Would anyone happen to know a more elegant and vectorized approach obtain the same result?
% Oblique-to-rectangular coordinate transformation
K = 10; % number of pixels
gamma = 0.37; % some arbitrary strain position range (-0.5; 0.5)
Koffset = (1-(-1).^(K-1))/4; % =0.5 when K is even, =0.0 when K is odd
% Mock data
S0 = rand(K,K); % data collected in the oblique coordinate system
qindex = -ceil((K-1)/2) : floor((K-1)/2); % all the possible q-values, with the zero'th element in the middle. Must be in this order to comply with FFT's convention
S = zeros(K,K); % data to be transformed to the rectangular coordinate system
% let indices (i,j) run through all the positions of the oblique matrix
for i=1:K
for j=1:K
% obtain the q-values corresponding to the current matrix position (i,j)
q1 = qindex(i);
q2 = qindex(j);
% apply the coordinate transformation to get the q-values in the rectangular system
qx = round(q1);
qy = round(q2-gamma*q1);
% apply periodic boundary condition
qy = qy - K*round((qy+Koffset)/K); % should be a unique value in the range of qindex
% find out the indices in the rectangular system
ii = i;
jj = find(qindex == qy);
% add the element
S(ii,jj) = S(ii,jj) + S0(i,j);
end
end
The best way to do this is to create a grid of points using meshgrid, deform the grid using your transformations, and then use interp2 to sample the original image at these locations.
% Desired output range
[xx,yy] = meshgrid(-3:0.01:3, -3:0.01:3);
% Transform these X and Y coordinates to q1 and q2 coordinates
q1 = xx;
q2 = yy + gamma*q1;
% Sample the original image using these coordinates where q1range and q2
% range and the q1 and q2 values corresponding to each element in the image qdata
output = interp2(q1range, q2range, qdata, q1, q2);

Convert Matlab code into Simulink

I would like to convert a image processing program(part of the program below) from Matlab to Simulink and possibly convert the simulink diagram into C code later on. I have 0 experience in Simulink and was wondering if there's any limitations on the types of matlab program/functions that can be converted and how I would go about doing this. Thanks.
clear all
clc
% Read in an image 1
C1 = imread('cloud1.jpg');
Cloud1 = C1(:,:,1); % use only one color
%Cloud1 = Cloud1'; % transpose to get (x,y) instead of (y,x)
Cloud1_xsize = size(Cloud1,2); % get x size of image
Cloud1_ysize = size(Cloud1,1); % get y size of image
%figure(3), imshow(Cloud1) % to plot you need to transpose back to their coordinate system
%hold on
% Read in an image 2
C2 = imread('cloud2.jpg');
Cloud2 = C2(:,:,1); % use only one color
%Cloud2 = Cloud2'; % transpose to get (x,y) instead of (y,x)
Cloud2_xsize = size(Cloud2,2); % get x size of image
Cloud2_ysize = size(Cloud2,1); % get y size of image
%figure(2), imshow(Cloud2)
%hold on
% show the shift in the initial images several times
num = 0;
for k = 1:4
num=num+1;
pause(.5)
figure(1), h1=imshow(C1)
xlabel('FIGURE 1')
F(num) = getframe(gcf);
%image(F.cdata)
%colormap(F.colormap)
pause(0.25)
figure(1), h2=imshow(C2)
xlabel('FIGURE 2')
num=num+1;
F(num) = getframe(gcf);
%image(F.cdata)
%colormap(F.colormap)
end
% Play the movie twenty times
%movie(F,20)
%%%% Set the template size %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% First calc the number of pixels in the shortest direction of the image (usually y direction)
MinSize = min(Cloud1_xsize, Cloud1_ysize); % number of pixels in shortest direction
%%% N is the minimum number of boxes in the shorter direction (usually y direction).
%%% In the shorter axis (usually y)there will be N-2 boxes analyzed.
%%% This is because the top and bottom boxes are considered too close to the edge to use.
%%% In the larger direction (usually x) there may be more boxes.
N = 6;
EdgeBoxSize = 1; % the number of edge boxes along each edge
TempWidth = floor(MinSize / N); % the pixel width of each template box
TempHeight = TempWidth; % make the template height and width the same size so corr part works good
%%% Now calculate the exact number of boxes in x and y directions
%%% This depends on the number of x versus y pixels.
Nx = floor(Cloud1_xsize/TempWidth);
Ny = floor(Cloud1_ysize/TempWidth);

Ideas for reducing the complexity of a 3D density function for generating a ternary surface plot in Matlab

I have a 3D density function q(x,y,z) that I am trying to plot in Matlab 8.3.0.532 (R2014a).
The domain of my function starts at a and ends at b, with uniform spacing ds. I want to plot the density on a ternary surface plot, where each dimension in the plot represents the proportion of x,y,z at a given point. For example, if I have a unit of density on the domain at q(1,1,1) and another unit of density on the domain at q(17,17,17), in both cases there is equal proportions of x,y,z and I will therefore have two units of density on my ternary surface plot at coordinates (1/3,1/3,1/3). I have code that works using ternsurf. The problem is that the number of proportion points grows exponentially fast with the size of the domain. At the moment I can only plot a domain of size 10 (in each dimension) with unit spacing (ds = 1). However, I need a much larger domain than this (size 100 in each dimension) and much smaller than unit spacing (ideally as small as 0.1) - this would lead to 100^3 * (1/0.1)^3 points on the grid, which Matlab just cannot handle. Does anyone have any ideas about how to somehow bin the density function by the 3D proportions to reduce the number of points?
My working code with example:
a = 0; % start of domain
b = 10; % end of domain
ds = 1; % spacing
[x, y, z] = ndgrid((a:ds:b)); % generate 3D independent variables
n = size(x);
q = zeros(n); % generate 3D dependent variable with some norm distributed density
for i = 1:n(1)
for j = 1:n(2)
for k = 1:n(2)
q(i,j,k) = exp(-(((x(i,j,k) - 10)^2 + (y(i,j,k) - 10)^2 + (z(i,j,k) - 10)^2) / 20));
end
end
end
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
x(isnan(x)) = 0; % set coordinate (0,0,0) to 0
y(isnan(y)) = 0; % set coordinate (0,0,0) to 0
z(isnan(z)) = 0; % set coordinate (0,0,0) to 0
xP = reshape(x,[1, numel(x)]); % create a vector of the proportions of x
yP = reshape(y,[1, numel(y)]); % create a vector of the proportions of y
zP = reshape(z,[1, numel(z)]); % create a vector of the proportions of z
q = reshape(q,[1, numel(q)]); % create a vector of the dependent variable q
ternsurf(xP, yP, q); % plot the ternary surface of q against proportions
shading(gca, 'interp');
colorbar
view(2)
I believe you meant n(3) in your innermost loop. Here are a few tips:
1) Loose the loops:
q = exp(- ((x - 10).^2 + (y - 10).^2 + (z - 10).^2) / 20);
2) Loose the reshapes:
xP = x(:); yP = y(:); zP = z(:);
3) Check Total once, instead of doing three checks on x,y,z:
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
Total( abs(Total) < eps ) = 1;
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
PS: I just recognized your name.. it's Jonathan ;)
Discretization method probably depends on use of your plot, maybe it make sense to clarify your question from this point of view.
Overall, you probably struggling with an "Out of memory" error, a couple of relevant tricks are described here http://www.mathworks.nl/help/matlab/matlab_prog/resolving-out-of-memory-errors.html?s_tid=doc_12b?refresh=true#brh72ex-52 . Of course, they work only up to certain size of arrays.
A more generic solution is too save parts of arrays on hard drive, it makes processing slower but it'll work. E.g., you can define several q functions with the scale-specific ngrids (e.g. ngridOrder0=[0:10:100], ngridOrder10=[1:1:9], ngridOrder11=[11:1:19], etc... ), and write an accessor function which will load/save the relevant grid and q function depending on the part of the plot you're looking.