MATLAB contourf plot for an irregular domain - matlab

I am stuck with this problem for a long time now. I have a polygonal region (lets say, a hexagon). I can calculate the values of certain function at any point inside the polygon. Now I need to create a filled contour (using contourf in MATLAB) of this data. How do I go about it. I found some discussion on this topic at the link below (page 121)
http://www-personal.umich.edu/~jpboyd/eng403_chap4_contourplts.pdf
This works somewhat ok but it still produces jagged edges which I don't want. Anyone has any suggestion on this problem? Thanks. Here is my code
close all
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
[x,y] = meshgrid(-1:0.1:1,-1:0.1:1);
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
figure
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
clear IN i j p x y

You're using a square grid to sample a hexagonal area. This will indeed lead to boundary problems.
A better solution (but still not quite optimal) is to use a hexagonal grid:
%# define hexagon
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
%# Generate hexagonal grid
Rad3Over2 = sqrt(3) / 2;
[x, y] = meshgrid(0:51);
n = size(y,1);
x = Rad3Over2 * x;
y = y + repmat([0 0.5],[n,n/2]);
%# re-scale to -1..1
x = 2*x/max(x(:))-1;
y = 2*y/max(y(:))-1;
%# insode-polygon check
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
%# make contour plot
figure(1)
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
If you want even better coverage, you'll have to devise a grid that better covers your area and/or up the number of sample points.
For arbitrary irregular areas, you might want to experiment with irregular/random grids, distributed such that there are more points close to the boundaries, than there are in the middle of the area.

Suppose you have a function defined on a hexagon. Then take some square that contains the hexagon.
A simple first test could be to extend your function on the square to take the value = 0 for points outside of the hexagon.
Depending on the range of your function this may, or may not, give you a good answer.
If this doesn't work, then find the min of the function on the hexagon using min(min(A))) for an nxn matrix A. Then define the function to be min(min(A)) - 1.0 outside of the hexagon but in the square.
Then use contourf(x, y, z, v) where v is a vector of values for the output, so take v(1) = min(min(A)) - 1.0, and v(2:n) = linspace(min(min(A)), max(max(A)), n) for some integer n. You can probably specify the color of the level set min(min(A)) - 1.0 to be white, but I've never done this. I've had to do something like this before, and setting the function = 0 outside of he hexagon was enough.

If your function can only be evaluated inside the polygonal region, then my hexagonal grid answer still stands. However, if your function can be (or modified to be) evaluated outside the polygon, you might want to use a cheat:
figure(1), clf, hold on
%# External contour, square.
x1 = [-3 -3 +3 +3 -3]/2;
y1 = [-3 +3 +3 -3 -3]/2;
%# internal contour, some polygon
x2 = [1.0 0.5 -0.5 -1.0 -0.5 0.5];
y2 = [0 0.8660 0.8660 0 -0.8660 -0.8660];
%# convert to patches
[f, v] = poly2fv({x1, x2}, {y1, y2});
patch(...
'Faces' , f,...
'Vertices' , v,...
'FaceColor', get(0, 'defaultuicontrolbackgroundcolor'), ...
'EdgeColor', 'none'...
);
%# Generate function for contourplot
[x, y] = meshgrid(-2.8/2:0.1:2.8/2);
N = rand(size(x));
%# make contour plot
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal;
axis off; colorbar;
It basically creates your contour plot on a square region, and overlays a mask with a hexagonal hole in it, so it looks like it's only a contour of the hexagonal. I suspect it is a lot easier to tweak your function to allow function evaluations outside the region, then it is to (re-)invent some sort of grid that contains the boundaries.

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.

Applying 3D rotation matrix to x, y, z values obtained from surface function

Applying 3D rotation matrix to the x,y,z values obtained from surface function object. The error I get is due to the matrix not being nonconforment but how can I adjust the matrix correctly?
I know hgtransform / makehgtform can do rotations but I need to use rotation matrices since I plan on testing it using matrices created from quaternions.
I've created a little plane out of cylinders and the surface functions.
See code below:
clear all,clf
ax=axes('XLim',[-2 2],'YLim', [-2 10],'ZLim',[-1.5 1.5]);
grid on;
%axis equal;
xlabel('x');
ylabel('y');
zlabel('z');
ax
% rotate around
rot_mat = [.707 -.707 0;.707 .707 0; 0 0 1] %rotation matrix
[xc yc zc] = cylinder([0.1 0.0]); %cone
[x y z]= cylinder([0.2 0.2]);
h(1) = surface(xc,zc,-yc,'FaceColor', 'red'); %noise cone
h(2) = surface(z,y,0.5*x,'FaceColor', 'blue'); %right wing
h(3) = surface(-z,y,0.5*x,'FaceColor', 'yellow');%left wing
h(4) = surface(x,-1.5*z,0.5*y,'FaceColor', 'green'); %main body
h(5) = surface(xc,(1.5*yc)-1.3,z*.5,'FaceColor', 'red'); %tail
view(3);
x_temp = get(h(1),'xdata'); % get x values
y_temp = get(h(1),'ydata');
z_temp =get(h(1),'zdata');
xc_new=x_temp.*rot_mat;
%zc_new=
%yc_new=
I can get the x,y, and z value by using the commands
x_temp = get(h(1),'xdata');
y_temp = get(h(1),'ydata');
z_temp = get(h(1),'zdata');
The error I get is due to the matrix being nonconforment but how can I adjust the matrix correctly?
error: test_object_matrix_rot: product: nonconformant arguments (op1 is 2x21, op2 is 3x3).
The error is with the line xc_new=x_temp.*rot_mat;
PS: I'm using Octave 5.0.91 which is like Matlab
YOu are messing up a lot of things......in fact I would say, you have made your work complex. YOu should straight away work on matrices to rotate to new positons instead of arrays and picking them from the figure.
This line:
x_temp = get(h(1),'xdata'); % get x values
giving you a 2*21 array and your rot_mat is 3X3.....you cannot multiply them. YOu need to pick (x,y,z) and multiply this point with rotation matrix to get the point shifted. Check the below pseudo code.....yo can develop your logic with the below example code.
t = 0:0.1:1;
[X,Y,Z] = cylinder((t));
%% Rotation
th = pi/2 ;
Rx = [1 0 0 ; 0 cos(th) -sin(th) ; 0 sin(th) cos(th)] ;
P0 = [X(:) Y(:) Z(:)] ;
P1 = P0*Rx ;
X1 = reshape(P1(:,1),size(X)) ;
Y1 = reshape(P1(:,2),size(X)) ;
Z1 = reshape(P1(:,3),size(X)) ;
figure
hold on
surf(X,Y,Z)
surf(X1,Y1,Z1)
view(3)

Plot line between all the scattered points and adjust the thickness of line according to the distance between points

Here are the coordinates that I am planning to plot, filename is Coords:
x y
0.0110 0.1105
-0.2730 0.2559
0.3610 0.1528
-0.0077 -0.2520
-0.2412 -0.1979
0.0444 -0.0526
0.0543 -0.0076
-0.1710 0.1170
0.12741 -0.0448
0.0949 -0.0811
Here is my code that plots the scatter graph first:
Hold on
%Plot Coordinate
For i=1:10
dot_size = 100;
scatter ( Coords(i,1) ,Coords(i,2), dot_size, 'filled', 'MarkerEdgeColor', 'k' );
end
%Draw line distance between each points
for i=1:10
for j=1:10
plot( [Coords(i,1) Coords(i,2)], [Coords(j,1) Coords(j,2)] );
end
end
Hold off
%Sets the size of the y and x axis
xlim( [ min( Coords(:,1)) max( Coords(:,1)) ] );
ylim( [ min( Coords(:,2)) max( Coords(:,2)) ] );
axis off;
Here is the result I get:
I don't know why the lines are being drawn everywhere. I also notice that even when plot(x,y) = 0, the line is still being drawn.
I also would like to change the thickness and opacity of the line depending on the distance between the two points: E.g. thicker and darker line for short distance between points. And thinner /lighter line if the distance between two points are long.
I want my plot to look something like this:
The reason your lines do not match the scattered points is the coordinates you give to plot; The coordinates are in wrong order and therefore they do not define the lines correctly.
I modified your code to correct this issue. I replaced plot with line, but you can also do the same with plot. In addition, I defined the anonymous functions f and g to define the color and thickness of each line based on distance of the two ends, d. You can modify these functionalities to get different graphical behaviors.
n = 10; % number of points
dot_size = 100;
Coords = rand(n, 2);
% maximum possible length in your coordination plane:
L = norm([max(Coords(:,1))-min(Coords(:,1)),max(Coords(:,2))-min(Coords(:,2))]);
% this function defines the line width:
f = #(x) L / (x + 0.1); % 0.1 avoids huge line widths in very small distances
% this function defines the color:
g = #(x) x * [1 1 1] / L;
figure
hold on
for ii = 1:n-1
for jj = ii+1:n
d = norm([Coords(ii,1)-Coords(jj,1), Coords(ii,2)-Coords(jj,2)]);
line([Coords(ii,1) Coords(jj,1)], [Coords(ii,2) Coords(jj,2)], ...
'LineWidth', f(d), 'Color', g(d));
end
end
scatter (Coords(:,1), Coords(:,2), dot_size, 'filled', 'MarkerEdgeColor', 'k');
axis tight
axis off
With this output:
Notes:
axis tight is a command that sets the limits to the tightest possible. It is equivalent to your xlim( [ min( Coords(:,1)) max( Coords(:,1)) ] ); and the next line.
In the for-loops you should try to avoid choosing one pair of points twice or same point as both sides of a line.
For scattering you do not need a loop. It could all be done at once.
I brought scatter after plotting the lines, so the circles are drawn on top.
There is also a specialized MATLAB function for generating plots like this: gplot.
data = [
0.0110 0.1105
-0.2730 0.2559
0.3610 0.1528
-0.0077 -0.2520
-0.2412 -0.1979
0.0444 -0.0526
0.0543 -0.0076
-0.1710 0.1170
0.12741 -0.0448
0.0949 -0.0811]; % Coordinates
adjM = squareform(pdist(data)); %
adjM (adjM > 0) = 1; % Form adjacency matrix based on Euclidean distances
figure; gplot(adjM, data, '-o') % Plot figure based on coordinates and adjacency matrix
Then, customize to your liking, e.g. if you want to change marker type, remove the axis, add labels etc.

Plotting a zplot using Matlab

I am trying to plot a zplot in Matlab that displays a unit circle, centered at 0 along with the poles and zeros of the plot. I am not allowed to use any other matlab function such as zplane or pzplot to do this. So far I am able to plot a unit circle just fine but I am having trouble getting my plot to display more of the axis without warping my circle. I also am having a heard time finding the poles and zeros of my function and also how to display the poles as little x's and the zeros as little o's on my plot. Any help would be greatly appreciated! My assignment looks like this and must correctly handle cases such as
zplot([0 1 1], [0 1]);
zplot([0 1 1], [0 0 1]);
function zplot(b, a)
% ZPLOT Plot a zero-pole plot.
-1 -nb
B(z) b(1) + b(2)z + .... + b(nb+1)z
H(z) = ---- = ---------------------------------
-1 -na
A(z) a(1) + a(2)z + .... + a(na+1)z
% zplot(b, a) plots the zeros and poles which determined by vectors b and a
% The plot includes the unit circle and axes for reference, plotted in black.
% Each zero is represented with a blue 'o' and each pole with a red 'x' on the
%plot.
xmin;
xmax;
ymin;
ymax;
% vector of angles at which points are drawn
angle = 0:2*pi/100:2*pi;
% Unit radius
R = 1;
% Coordinates of the circle
x = R*cos(angle);
y = R*sin(angle);
% Plot the circle
plot(x,y);
axis ([xmin, xmax, ymin, ymax]);
grid on;
end
If you can't use pzplot() it is not hard. Here is a hint:
num = [1 4 1];%numerator coefficients of transfer function
den = [1 2 1];%denominator coefficients
z = roots(num)%zeros
p = roots(den)%poles
angle = 0:2*pi/100:2*pi;
xp = cos(angle);
yp = sin(angle);
figure(1)
scatter(z,zeros(length(z),1),'o');
hold on
scatter(p,zeros(length(p),1),'x');
plot(xp,yp);
axis equal
The output
Note that I haven't dealt with imaginary poles/zeros in this example. You'll need to calculate the proper x,y coordinates for a given imaginary pole or zero. (all the poles/zeros in this example are real, not imaginary)
Given a transfer function G, you can use the pzplot() command and add a circle to it.
G = tf([1 4 1],[1 2 1]);
angle = [0:0.1:2*pi+0.1];
xp = cos(angle);
yp = sin(angle);
figure(1)
hold on
pzplot(G);
plot(xp,yp);
axis equal;
This should give you the pole-zero plot with x's for poles, o's for zeros, and the unit circle.
Here is the result.

How to plot a intersection operation on two vectors MatLab

I'm trying to represent a the intersection of two fuzzy sets as a 3d mesh in MatLab.
Here are my sets of vectors:
x = [0.3 0.5 0.7]
y = [0.5 0.7 0.1]
Followed by these statements:
[u,v] = meshgrid(x,y)
w = min(u,v)
mesh(u,v,w)
The x and y ticks seem to be all over the place and do not correlate to the actual index number of each vector i.e. 1 to 3, and the graph should represent the shape of a small triangle/T-norm.
At the moment it looks like this:
Here is an example out of my book I'm following:
Ignore what looks like fractions, they are delimiters. Here is the resulting graph:
After looking up fuzzy sets and intersections, here's what I've come up with. First, let's reproduce the textbook example:
% possible values and associated degrees of truth for F
Fv = 1 : 5;
Ft = [0 0.5 1 0.5 0];
% possible values and associated degrees of truth for D
Dv = 2 : 4;
Dt = [0 1 0];
% determine degrees of truth for fuzzy intersection
It = bsxfun(#min, Ft', Dt);
% plot
h = mesh(Dv, Fv, It);
set(h, 'FaceColor', 'none')
set(h, 'EdgeColor', 'k')
xlim([0 4.5])
ylim([0 5])
xlabel D
ylabel F
view(37.5, 30)
The result is:
Not as pretty as in your book, but the same thing.
Applying the same code to your example yields:
Via the arguments u,v you are telling mesh to use the values in them, i.e. the values from x and y, for the positioning of the data points and corresponding ticks. If you just want positions and ticks at 1, 2, 3, leave these arguments out.
mesh(w)