Contour Line and Surface Matlab - matlab

I want to produce a surface plot with a predefined contour line on the surface, in Matlab. I have already produced the plot in Mathematica, and want to create the equivalent figure in Matlab.
With the following functions I defined a surface
k2[G_, V_] = Sqrt[G]*Exp[-V];
k1[G_] = Sqrt[G]*Exp[-10];
L1[G_, V_] = -0.5*(k1[G_] + 2*k2[G, V]) + 0.5*Sqrt[k1[G_]^2 + 4*k2[G, V]^2];
and a parametric curve over the surface
hike=ParametricPlot3D[{10, 0, 0} + {x^2, x, -(1/L1[10 + x^2, x])}, {x, 0, 12},PlotStyle -> Directive[Thick, Red]];
hikeHeight=ParametricPlot3D[{10, 0, 0} + {x^2,x, -z*(1/L1[10 + x^2, x])}, {x, 0, 12}, {z, 0, 1},PlotStyle -> Directive[Gray], Mesh -> None];
Then I plot the surface and the contour line together:
surf= Plot3D[-1/L1[G, V], {G, 10, 100}, {V, 0, 12}];
Show[surf, hike, hikeHeight, AxesLabel -> {G, V,Z}, Boxed -> False]
What is the process for evaluating the function and producing the same plot in Matlab?
This how far i get with my matlab attempt
[X,Y,Z] = peaks(25);
curvX=diag(X);
curvY=diag(Y);
curvZ=diag(Z);
nn = 401;
xi = linspace(-3.0, 3.0, nn);
yi = xi;
[xi, yi] = meshgrid(xi, yi);
zi = interp2(X, Y, Z, xi, yi, 'spline');
figure()
surf(xi, yi, zi,'LineStyle', 'none', 'FaceColor', 'interp')
colormap(parula)
alpha 0.7
hold on
surf(diag(curvX),diag(curvY),diag(curvZ),'LineStyle', 'none')
the surface and the parametric curve are obviously not the same but the idea is the same to plot an slice of the surface

Let's start by defining the functions, as inline, vectorised function handles:
k2 = #(g, v)sqrt(g).*exp(-v);
k1 = #(g)sqrt(g).*exp(-10);
l1 = #(g, v) -.5 .* (k1(g) + 2.*k2(g, v)) + 0.5 * sqrt(k1(g).^2 + 4.*k2(g, v).^2);
Now we need to define a mesh, since Matlab isn't smart enough to do automatic discretisation like Mathematica:
nMeshPoints = 50;
vfG = linspace(10, 100, nMeshPoints);
vfV = linspace(0, 12, nMeshPoints);
[mfG, mfV] = ndgrid(vfG, vfV);
Ok, now we can evaluate the surface over the mesh, and make a surface plot:
hSurf = surf(mfG, mfV, -1./l1(mfG, mfV));
shading interp;
hold on;
hSurf.FaceAlpha = 0.5;
Now we need to build and plot your parametric line, also via explicit discretisation:
vfX = linspace(0, 12, nMeshPoints);
vfZ = linspace(0, 1, nMeshPoints);
vfLX = 10 + vfX.^2;
vfLY = vfX;
vfLZ = -(1 ./ l1(10 + vfX.^2, vfX));
vfLHeight = vfLZ .* vfZ;
plot3(vfLX, vfLY, vfLZ, 'r-');
plot3(vfLX, vfLY, vfLHeight, 'k-');
Now we can make the plot a little more beautiful:
xlim([10 100]);
ylim([0 12]);
zlim([0 20000]);
caxis([0 20000]);
xlabel('G');
ylabel('V');
zlabel('Z');
view([60, 30]);
The result: not quite as beautiful as Mathematica, but at least equivalent.

Related

Rotate line to arbitary position around unit circle

I have a unit circle with n roots of unity marked. I would like to be able to rotate, translate, and scale a line resting on the x-axis (between -1 and 1) to connect any pair of marked roots. Currently my code can do this in some cases, but doesn't work in general. I want to avoid hard-coding how the line should move for each possible pair. Here's what I have so far:
clear
%% Roots of unity
n = 10;
roots = zeros(1, n);
for k = 1 : n
roots(k) = exp(2 * k* pi * 1i / n);
end
%% Move line
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
% Coordinates of pair of roots
x1 = real(point_1);
x2 = real(point_2);
y1 = imag(point_1);
y2 = imag(point_2);
d = sqrt((x1-x2)^2+(y1-y2)^2); % Euclidean distance between pair of roots
m = (y1 - y2) / (x1 - x2); % Gradient of line connecting pair of roots
c = y1 - m * x1; % y-intercept of line
int = -c / m; % x-coordinate that the rotation should occur at
shift = [int; 0];
x = linspace(-1, 1, 10); % Initial line lying purely on x-axis
y = 0 * x;
v = [x; y];
theta = atan((y2-shift(2))/(x2-shift(1))); % Angle by which to rotate
rot = [cos(theta), -sin(theta); sin(theta), cos(theta)]; % Rotation matrix
u = v * (d / 2); % Scale initial line
if m < 1e-3 % Horizontal case
shift = [0; 0];
end
w = (rot * (u - shift)) + shift; % Apply rotation
% Another shift that seems necessary
% This is definitely a problematic section
shift_x = w(1, 1) - x2;
shift_y = w(2, 1) - y2;
shift_2 = [shift_x; shift_y];
w = w - shift_2;
%% Plot
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
ax = gca;
tt = title(ax, 'Title');
tt.FontWeight = 'bold';
tt.FontSize = 20;
st = subtitle(ax, sprintf('More text here'));
st.FontAngle = 'italic';
st.FontSize = 15;
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
for i = 1 : n
x_point = real(roots(i));
y_point = imag(roots(i));
hPin = plot(x_point, y_point, 'Marker', 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
end
% Plot original and shifted line, split into colours so direction is easier to see
plot(v(1,1:4), v(2,1:4), 'b');
plot(v(1,4:7), v(2,4:7), 'r');
plot(v(1,7:end), v(2,7:end), 'g');
plot(w(1,1:4), w(2,1:4), 'b');
plot(w(1,4:7), w(2,4:7), 'r');
plot(w(1,7:end), w(2,7:end), 'g');
For example, keeping point_1 = roots(2); and changing only point_2 = roots(p); works as intended for only p=3, 4, 6, 7, 8.
Any guidance on how to get this working would be greatly appreciated, thanks!
Edit:
To give some more details, basically I have an array of numbers between 0 and 1 (rather than just a line) which I want to plot on the line that would connect two roots. E.g. if my array is x=[0.2, 0.5, 0.9], then I want three points between point_1 and point_2, the first being 0.2d down the connecting line away from point_1, the second 0.5d (i.e. halfway), and the final being 0.9d away.
First of all, since the points you want to connect are complex numbers, it is easier to work with complex coordinate directly.
Roots of unity
I have simplified your code a bit.
Some may raise a flag on naming a variable roots since roots is a built-in matlab function. I am fine with it, as long as the usage does not cause any confusion, namely, don't use roots as a variable and as a function in the same context.
As matlab provides so many built-in functions, it is impossible to avoid name collision unless one knows them all by heart or searches before naming every single variable.
n = 10;
k = 1:n;
roots = exp(2 * k * pi * 1i / n);
Scaling, rotating, and translating
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
d = abs(point_2 - point_1); % distance between pair of roots
theta = angle(point_2 - point_1); % rotation angle
p_on_line = linspace(-1, 1, 10); % Initial line lying on x-axis
p_on_line = p_on_line * d/2; % scale
p_on_line = p_on_line * exp(1i*theta); % rotate
p_on_line = p_on_line + (point_1 - p_on_line(1)); % translate
Plot
I added some scatter points and removed irrevelant parts (e.g. title, fonts).
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
hPin = plot(roots, 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
% Plot line connecting roots
plot(p_on_line(1:4), 'b.-', 'MarkerSize', 20);
plot(p_on_line(4:7), 'r.-', 'MarkerSize', 20);
plot(p_on_line(7:end), 'g.-', 'MarkerSize', 20);
% Plot original line
original_x = linspace(-1, 1, 10);
original_y = zeros(1, 10);
plot(original_x(1:4), original_y(1:4), 'b.-', 'MarkerSize', 20);
plot(original_x(4:7), original_y(4:7), 'r.-', 'MarkerSize', 20);
plot(original_x(7:end), original_y(7:end), 'g.-', 'MarkerSize', 20);
hold off
This should work for all combinations of root pairs.

Shaded plot in Matlab

I would like to plot a function in Matlab with a shaded area indicating the uncertainty over it (e.g., confidence interval). This can be achieved by using the fill function to create a color patch. For example
x = linspace(0, 2*pi, 100);
f = cos(x);
fUp = cos(x) + 1;
fLow = cos(x) - 1;
x2 = [x, fliplr(x)];
plot(x, f, 'k')
hold on
fill(x2, [f, fliplr(fUp)], 0.7 * ones(1, 3), 'linestyle', 'none', 'facealpha', 0.4);
fill(x2, [fLow, fliplr(f)], 0.7 * ones(1, 3), 'linestyle', 'none', 'facealpha', 0.4);
This creates a shaded gray area between the functions fLow and fUp, with f in the middle represented as a solid black line, as in the picture below.
I would like now to have the shaded area degrade its color when we approach the lower (resp. upper) bound of the confidence interval. In particular, I would like that while approaching its boundaries, the shaded area gets brighter and brighter. Is there a way to do it?
I'm doing two separate patches because I think it may be necessary for my purpose.
You can split your CI into n subarea:
x = linspace(0, 2*pi, 100);
f = cos(x);
n = 20; % step number
g = 0.3; % grayscale intensity
fUp = cos(x) + linspace(0,1,n).';
fLow = cos(x) - linspace(0,1,n).';
x2 = [x, fliplr(x)];
plot(x, f, 'k')
hold on
fill(x2, [repmat(f,n,1), fliplr(fUp)], g * ones(1, 3), 'linestyle', 'none', 'facealpha', [1/n]);
fill(x2, [fLow, repmat(fliplr(f),n,1)], g * ones(1, 3), 'linestyle', 'none', 'facealpha', [1/n]);
Which produce:
The subarea are overlapping and produce a maximum facealpha of n*(1/n) * g = g
Noticed that this method is not really memory efficient (since it produce n subarea on each side) and will only works with a linear shading.
If your CI is non linear then you should adjust this part:
% Prediction Linear CI
% ↓ ↓
cos(x) + linspace(0,1,n).';
cos(x) - linspace(0,1,n).';
to
% Prediction Non linear CI
% ↓ ↓
cos(x) + your_non_linear_CI_distribution;
cos(x) - your_non_linear_CI_distribution;

4D plot (3D+color) from 4 row vectors

I have 4 row vectors x, y, z and s, all of them have equal sizes 1*size. x, y, z should be the three Cartesian corodinate axes and s should be represented by colors (I want figure like below image). The statement Surf does not accept row vectors. I have read several stackoverflow post, but I could not find the answer. How can I plot such a figure?
I really appreciate any help you can provide.
I can't test it because you didn't provide any data, but you could try:
trisurf(x,y,z,s)
If that doesn't work then try:
DT = delaunayTriangulation(x,y,z);
tetramesh(DT,s);
You can try with this example of a 3D cube for a 3D meshgrid and it plots the "temperature".
L = 1;
dx = 0.25;
dy = dx;
dz = dy;
Nx = L/dx; Ny = Nx; Nz = Ny;
x = dx/2:dx:L-dx/2;
y = x; z = y;
[xx, yy, zz] = meshgrid(x,y,z);
theta = NaN(size(zz));
for jj=1:4;
for ii=1:4
for kk=1:4
theta(jj,ii,kk) = 273.15 + 5.*random('normal', 0, 1)
end
end
end
clf
isosurface(xx, yy, zz, theta)
colorbar
colormap jet
[fe, ve, ce] = isocaps(x, y, z, theta, 10);
p2 = patch('Faces', fe, 'Vertices', ve, 'FaceVertexCData', ce);
p2.FaceColor = 'interp';
p2.EdgeColor = 'none' ;
grid on
xlabel('X (m)');
ylabel('Y (m)');
zlabel('Z (m)');
title('Temperatures');
set(gca, 'clim', [273.15 273.15+5])
set(get(colorbar, 'title'), 'string', 'K', 'FontW', 'bold', 'fontname', 'Times New Roman', 'fontsize', 14);
view(3)

MATLAB - Smooth heat map from (x, y, z) points within a triangle?

I have many 3D scatter points (x, y, z) that are guaranteed to be within a triangle. I now wish to visualize z as one smooth 2D heat map, where positions are given by (x, y).
I can easily do it with meshgrid and mesh, if (x, y) together form a rectangle. Because I don't want anything falling outside of my triangle, I can't use griddate either.
Then how?
MWE
P = [0 1/sqrt(3); 0.5 -0.5/sqrt(3); -0.5 -0.5/sqrt(3)];
% Vertices
scatter(P(:, 1), P(:, 2), 100, 'ro');
hold on;
% Edges
for idx = 1:size(P, 1)-1
plot([P(idx, 1) P(idx+1, 1)], [P(idx, 2) P(idx+1, 2)], 'r');
end
plot([P(end, 1) P(1, 1)], [P(end, 2) P(1, 2)], 'r');
% Sample points within the triangle
N = 1000; % Number of points
t = sqrt(rand(N, 1));
s = rand(N, 1);
sample_pts = (1-t)*P(1, :)+bsxfun(#times, ((1-s)*P(2, :)+s*P(3, :)), t);
% Colors for demo
C = ones(size(sample_pts, 1), 1).*sample_pts(:, 1);
% Scatter sample points
scatter(sample_pts(:, 1), sample_pts(:, 2), [], C, 'filled');
colorbar;
produces
PS
As suggested by Nitish, increasing number of points will do the trick. But is there a more computationally cheap way of doing so?
Triangulate your 2D data points using delaunayTriangulation, evaluate your function with the points of the triangulation and then plot the resulting surface using trisurf:
After %Colors for demo, add this:
P = [P; sample_pts]; %// Add the edgepoints to the sample points, so we get a triangle.
f = #(X,Y) X; %// Defines the function to evaluate
%// Compute the triangulation
dt = delaunayTriangulation(P(:,1),P(:,2));
%// Plot a trisurf
P = dt.Points;
trisurf(dt.ConnectivityList, ...
P(:,1), P(:,2), f(P(:,1),P(:,2)), ...
'EdgeColor', 'none', ...
'FaceColor', 'interp', ...
'FaceLighting', 'phong');
%// A finer colormap gives more beautiful results:
colormap(jet(2^14)); %// Or use 'parula' instead of 'jet'
view(2);
The trick to make this graphic beautiful is to use 'FaceLighting','phong' instead of 'gouraud' and use a denser colormap than is usually used.
The following uses only N = 100 sample points, but a fine colormap (using the now default parula colormap):
In comparison the default output for:
trisurf(dt.ConnectivityList, ...
P(:,1), P(:,2), f(P(:,1),P(:,2)), ...
'EdgeColor', 'none', ...
'FaceColor', 'interp');
looks really ugly: (I'd say mainly because of the odd interpolation, but the jet colormap also has its downsides)
Why not just increase N to make the grid "more smooth"? It will obviously be more computationally expensive but is probably better than extrapolation. Since this is a simulation where s and t are your inputs, you can alternately create a fine grids for them (depending on how they interact).
P = [0 1/sqrt(3); 0.5 -0.5/sqrt(3); -0.5 -0.5/sqrt(3)];
% Vertices
scatter(P(:, 1), P(:, 2), 100, 'ro');
hold on;
% Edges
for idx = 1:size(P, 1)-1
plot([P(idx, 1) P(idx+1, 1)], [P(idx, 2) P(idx+1, 2)], 'r');
end
plot([P(end, 1) P(1, 1)], [P(end, 2) P(1, 2)], 'r');
% Sample points within the triangle
N = 100000; % Number of points
t = sqrt(rand(N, 1));
s = rand(N, 1);
sample_pts = (1-t)*P(1, :)+bsxfun(#times, ((1-s)*P(2, :)+s*P(3, :)), t);
% Colors for demo
C = ones(size(sample_pts, 1), 1).*sample_pts(:, 1);
% Scatter sample points
scatter(sample_pts(:, 1), sample_pts(:, 2), [], C, 'filled');
colorbar;

Multi dimensional (2d better 3d) scatter-plot with different errorbars in matlab

I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')