MATLAB how to plot contour with special LineWidth for certain value - matlab

I have the following script:
close all; clear all; clc;
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
values = -10:0.5:10;
figure
[C,hh] = contour(X, Y, Z, values,'r', 'LineWidth',1);
clabel(C, hh, values, 'fontsize',7)
As you can see in the contour lines, all of the lines are plotted with LineWidth = 1. I would like to plot special line for the value = 0, with LineWidth = 2, how to set it? Thanks a lor for your help.

You will need to make a secondary contour plot to highlight the desired contour levels. The MathWorks has an example of this in the documentation.
For your case we'll have something like the following:
% Generate sample data
x = linspace(-2*pi,2*pi);
y = linspace(0,4*pi);
[X,Y] = meshgrid(x,y);
Z = sin(X)+cos(Y);
values = -10:0.5:10;
% Generate initial contour plot
figure
[C,hh] = contour(X, Y, Z, values,'r', 'LineWidth',1);
clabel(C, hh, values, 'fontsize',7)
% Generate second contour plot with desired contour level highlighted
hold on
contour(X, Y, Z, [0 0], 'b', 'LineWidth', 2);
hold off
Which returns the following:
Not that I've specified the single contour level as a vector. This is explained by the documentation for contour:
contour(Z,v) draws a contour plot of matrix Z with contour lines at the data values specified in the monotonically increasing vector v. To display a single contour line at a particular value, define v as a two-element vector with both elements equal to the desired contour level. For example, to draw contour lines at level k, use contour(Z,[k k])
If you want to highlight multiple levels then this does not apply (e.g. contour(X, Y, Z, [-1 0], 'b', 'LineWidth', 2) to highlight -1 and 0)

Related

Edit the x limits of least squares line

I created two scatter plots and then used lsline to add regression lines for each plot. I used this code:
for i=1:2
x = ..;
y = ..;
scatter(x, y, 50, 'MarkerFaceColor',myColours(i, :));
end
h_lines = lsline;
However, the darker line extends far beyond the last data point in that scatter plot (which is at around x=0.3):
lsline doesn't seem to have properties that allow its horizontal range to be set. Is there a workaround to set this separately for the two lines, in Matlab 2016a?
For a single data set
This is a workaround rather than a solution. lsline internally calls refline, which plots a line filling the axis as given by their current limits (xlim and ylim). So you can change those limits to the extent you want for the line, call lsline, and then restore the limits.
Example:
x = randn(1,100);
y = 2*x + randn(1,100); % random, correlated data
plot(x, y, '.') % scatter plot
xlim([-1.5 1.5]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
For several data sets
In this case you can apply the same procedure for each data set sequentially, but you need to keep only one data set visible when you call lsline; otherwise when you call it to create the second line it will also create a new version of the first (with the wrong range).
Example:
x = randn(1,100); y = 2*x + randn(1,100); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
hold on
x = 2*randn(1,100) - 5; y = 1.2*x + randn(1,100) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
set(h, 'HandleVisibility', 'off'); % hide previous plot
lsline % plot line
set(h, 'HandleVisibility', 'on'); % restore visibility
xlim auto % restore axis limit
Yet another solution: implement your own hsline. It's easy!
In MATLAB, doing a least squares fit of a straight line is trivial. Given column vectors x and y with N elements, b = [ones(N,1),x] \ y; are the parameters to the best fit line. [1,x1;1,x2]*b are the y locations of two points along the line with x-coordinates x1 and x2. Thus you can write (following Luis' example, and getting the exact same output):
N = 100;
x = randn(N,1); y = 2*x + randn(N,1); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
hold on
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'b-')
x = 2*randn(N,1) - 5; y = 1.2*x + randn(N,1) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'r-')
You can get the points that define the line using
h_lines =lsline;
h_lines(ii).XData and h_lines(ii).YData will contain 2 points that define the lines for each ii=1,2 line. Use those to create en equation of a line, and plot the line in the range you want.

How to customize contour lines in Matlab?

I am preparing a contour map where I am supposed to highlight the contour line for a specific level. For Example, my contour line values are lying between -1 and 1 and I want to highlight the line corresponding to the value 0. I tried to do this using the following procedure,
[M,c]=contourf(longitude,latitude,delta',-1:0.2:1);
s=size(c.LevelList,2);
for i=1:s
if (c.LevelList(i)==0)
c.LevelWidth=2;
end;
end;
However, it does nothing to the contour map. Can anyone please help me with the appropriate procedure?
I would suggest simply using contour on your desired levels to highlight after the initial contourf, like so:
% Input.
x = linspace(-2*pi, 2*pi, 101);
y = x + pi;
[X, Y] = meshgrid(x, y);
Z = 0.5 * (sin(X) + cos(Y));
% Levels to plot with contourf.
levelsf = -1:0.2:1;
% Levels to highlight.
levels = [0 0.3];
figure(1);
hold on;
% Contourf all levels.
contourf(X, Y, Z, levelsf);
% Highlight levels with simple contour.
contour(X, Y, Z, levels, 'r', 'LineWidth', 2);
hold off;
For highlighting levels = [0 0.3], you'll get:

Issue with scatter3

Probably it's scatter3 what I don't understand. I have a matrix of which all slices but the last are NaNed (M(:,:,1:10) = NaN;) and then it's permuted switching first and last dimension. So there are only values in M(11,:,:). I expect all plotted values to be in the Y-Z plane at x==11, but the plot looks differently (see code and picture below). Any explanations?
M = rand(22,55,11);
M(:,:,1:10) = NaN;
M = permute(M,[3 2 1]);
shape = size(M)
[x, y, z] = meshgrid(1:shape(1), 1:shape(2), 1:shape(3));
scatter3(x(:), y(:), z(:), 4, M(:), 'fill');
view([60 60]);
xlabel('X ', 'FontSize', 16);
ylabel('Y ', 'FontSize', 16);
zlabel('Z ', 'FontSize', 16);
The explanation is that meshgrid switches x and y:
From meshgrid documentation:
MESHGRID is like NDGRID except that the order of the first two input
and output arguments are switched (i.e., [X,Y,Z] = MESHGRID(x,y,z)
produces the same result as [Y,X,Z] = NDGRID(y,x,z)).
At first sight, this should result in a plot with values in the X-Z plane at y==11 (i.e. x and y interchanged with respect to what you initially expected). But note that your code treats x and y sizes incorrectly (because of meshgrid). This has the additional effect that the x and y coordinates get "shuffled" and you don't see a plane (even in X-Z), but rather a lattice.
So the solution is to use ndgrid, which doesn't do any switching. Just replace "meshgrid" by "ndgrid" in your code. The resulting figure is now as expected:

Adding space between cells in Matlab imagesc output

I am creating a 2D plot in Matlab by calling this command: imagesc(vector1, vector2, mat_weights). Then, I run the colorbar command.
I now have a smooth 2D plot, but I want to add space between the cells. Here's how I want it to look:
How do I add such spacing between the cells/boxes?
You can add spaces between patches of color using another function than imagesc. Here, scatter provides a straightforward solution when used with option 'filled' and marker 'square'.
Note that you need to transform your 2-D matrix into a vector, but you don't have to scale your data: scatter takes the min and max values from your data and assign them to the min and max colors of the colormap.
The code
% 2-D in 1-D:
Z = diag(1:10); %example of 2-D matrix to be plotted
C = reshape(Z,1,[]); %1-D transform for vector color
% input definition
sz_matrix = 10;
X = repmat( (1:sz_matrix), 1, sz_matrix);
Y = kron(1:sz_matrix,ones(1,sz_matrix));
S = 1000; % size of marker (handle spaces between patches)
%C = (X.^2 + Y.^2); % second color scheme
%plot
figure('Color', 'w', 'position', [10 10 600 400]);
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 11], 'YLim', [0 11]);
axis square;
colormap summer
colorbar
will give
EDIT
Here is a piece of code for a rectangular matrix. Please note the inversion of the Y axis direction so that the graphical representation matches disp(Z). To have similar (x,y) proportion in the white area separating color patches, one may try to resize manually the figure.
Z = diag(1:10); %example of 2-D matrix to be plotted
Z = Z(1:end-2,:); %trim for rectangular
% input definition
X = repmat(1:size(Z,2), 1, size(Z,1));
Y = kron(1:size(Z,1),ones(1,size(Z,2)));
C = reshape(Z',1,[]); %1-D transform for vector color
S = 1000; % size of marker (handle spaces between patches)
%plot
figure('Color', 'w');
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 size(Z,2)+1], 'YLim', [0 size(Z,1)+1]);
colormap jet
colorbar
set(gca, 'YDir','reverse');
The ouput:

Texture mapping in MATLAB

I have points in 3D space and their corresponding 2D image points. How can I make a mesh out of the 3D points, then texture the triangle faces formed by the mesh?
Note that the function trisurf that you were originally trying to use returns a handle to a patch object. If you look at the 'FaceColor' property for patch objects, you can see that there is no 'texturemap' option. That option is only valid for the 'FaceColor' property of surface objects. You will therefore have to find a way to plot your triangular surface as a surface object instead of a patch object. Here are two ways to approach this:
If your data is in a uniform grid...
If the coordinates of your surface data represent a uniform grid such that z is a rectangular set of points that span from xmin to xmax in the x-axis and ymin to ymax in the y-axis, you can plot it using surf instead of trisurf:
Z = ... % N-by-M matrix of data
x = linspace(xmin, xmax, size(Z, 2)); % x-coordinates for columns of Z
y = linspace(ymin, ymax, size(Z, 1)); % y-coordinates for rows of Z
[X, Y] = meshgrid(x, y); % Create meshes for x and y
C = imread('image1.jpg'); % Load RGB image
h = surf(X, Y, Z, flipdim(C, 1), ... % Plot surface (flips rows of C, if needed)
'FaceColor', 'texturemap', ...
'EdgeColor', 'none');
axis equal
In order to illustrate the results of the above code, I initialized the data as Z = peaks;, used the built-in sample image 'peppers.png', and set the x and y values to span from 1 to 16. This resulted in the following texture-mapped surface:
If your data is non-uniformly spaced...
If your data are not regularly spaced, you can create a set of regularly-spaced X and Y coordinates (as I did above using meshgrid) and then use one of the functions griddata or TriScatteredInterp to interpolate a regular grid of Z values from your irregular set of z values. I discuss how to use these two functions in my answer to another SO question. Here's a refined version of the code you posted using TriScatteredInterp (Note: as of R2013a scatteredInterpolant is the recommended alternative):
x = ... % Scattered x data
y = ... % Scattered y data
z = ... % Scattered z data
xmin = min(x);
xmax = max(x);
ymin = min(y);
ymax = max(y);
F = TriScatteredInterp(x(:), y(:), z(:)); % Create interpolant
N = 50; % Number of y values in uniform grid
M = 50; % Number of x values in uniform grid
xu = linspace(xmin, xmax, M); % Uniform x-coordinates
yu = linspace(ymin, ymax, N); % Uniform y-coordinates
[X, Y] = meshgrid(xu, yu); % Create meshes for xu and yu
Z = F(X, Y); % Evaluate interpolant (N-by-M matrix)
C = imread('image1.jpg'); % Load RGB image
h = surf(X, Y, Z, flipdim(C, 1), ... % Plot surface
'FaceColor', 'texturemap', ...
'EdgeColor', 'none');
axis equal
In this case, you have to first choose the values of N and M for the size of your matrix Z. In order to illustrate the results of the above code, I initialized the data for x, y, and z as follows and used the built-in sample image 'peppers.png':
x = rand(1, 100)-0.5; % 100 random values in the range -0.5 to 0.5
y = rand(1, 100)-0.5; % 100 random values in the range -0.5 to 0.5
z = exp(-(x.^2+y.^2)./0.125); % Values from a 2-D Gaussian distribution
This resulted in the following texture-mapped surface:
Notice that there are jagged edges near the corners of the surface. These are places where there were too few points for TriScatteredInterp to adequately fit an interpolated surface. The Z values at these points are therefore nan, resulting in the surface point not being plotted.
If your texture is already in the proper geometry you can just use regular old texture mapping.
The link to the MathWorks documentation of texture mapping:
http://www.mathworks.com/access/helpdesk/help/techdoc/visualize/f0-18164.html#f0-9250
Re-EDIT: Updated the code a little:
Try this approach (I just got it to work).
a=imread('image.jpg');
b=double(a)/255;
[x,y,z]=peaks(30); %# This is a surface maker that you do have
%# The matrix [x,y,z] is the representation of the surface.
surf(x,y,z,b,'FaceColor','texturemap') %# Try this with any image and you
%# should see a pretty explanatory
%# result. (Just copy and paste) ;)
So [x,y,z] is the 'surface' or rather a matrix containing a number of points in the form (x,y,z) that are on the surface. Notice that the image is stretched to fit the surface.