MeshGrid for Triangle Elements - matlab

I want to build a contourf plot of a certain aspect in my Plate. The plate is divided in triangle elements, which I have the coordinates (x,y) of each knot of the triangle.
So, How can I make a meshgrid for my knots so I can make my contourf plot?? I have the coordinates of everything and have the value of my function Z in each knot. (I'm a beginner in Matlab, sorry for this "basic" question)

If your goal is just to visualise the triangles then there is another way that's probably simpler and more robust (see the end of this post).
If you definitely need to generate contours then you will need to interpolate your triangular mesh over a grid. You can use the scatteredInterpolant class for this (documentation here). It takes the X and Y arguments or your triangular vertices (knots), as well as the Z values for each one and creates a 'function' that you can use to evaluate other points. Then you create a grid, interpolate your triangular mesh over the grid and you can use the results for the countour plot.
The inputs to the scatteredInterpolanthave to be linear column vectors, so you will probably need to reshape them using the(:)`notation.
So let's assume you have triangular data like this
X = [1 4; 8 9];
Y = [2 3; 4 5];
Z = [0.3 42; 16 8];
you would work out the upper and lower limits of your range first
xlimits = minmax(X(:));
ylimits = minmax(Y(:));
where the (:) notation serves to line up all the elements of X in a single column.
Then you can create a meshgrid that spans that range. You need to decide how fine that grid should be.
spacing = 1;
xqlinear = xlimits(1):spacing:xlimits(2);
yqlinear = ylimits(1):spacing:ylimits(2);
where linspace makes a vector of values starting at the first one (xlimits(1)) and ending at the third one (xlimits(2)) and separated by spacing. Experiment with this and look at the results, you'll see how it works.
These two vectors specify the grid positions in each dimension. To make an actual meshgrid-style grid you then call meshgrid on them
[XQ, YQ] = meshgrid(xqlinear, yqlinear);
this will produce two matrices of points. XQ holds the x-coordinates of every points in the grid, arranged in the same grid. YQ holds the y-coordinates. The two need to go together. Again experiment with this and look at the results, you'll see how it works.
Then you can put them all together into the interpolation:
F = scatteredInterpolant(X(:), Y(:), Z(:));
ZQ = F(XQ, YQ);
to get the interpolated values ZQ at each of your grid points. You can then send those data to contourf
contourf(XQ, YQ, ZQ);
If the contour is too blocky you will probably need to make the spacing value smaller, which will create more points in your interpolant. If you have lots of data this might cause memory issues, so be aware of that.
If your goal is just to view the triangular mesh then you might find trimesh does what you want or, depending on how your data is already represented, scatter. These will both produce 3D plots with wireframes or point clouds though so if you need contours the interpolation is the way to go.

Related

Using streamslice/quiver and inpolygon crop

Suppose we have quiver field i.e. we have a meshgrid and then we assign a vector to each point. Is it possible to plot only the quiver field within some polygon?
So in the figure below, we want everything outside the triangle to be cropped out.
Ideally the code will also be helpful for the next step of having multiple such polygons and cropping out everything on their complement.
Some approaches:
A direct way is to figure out the meshgrid for the particular polygon and then assign a vector to each point. But that will take a lot of time to figure out as polygons get more complicated. In other words, the regular meshgrid is the square polygon, so we must modify the meshgrid matrix depending on our polygon. A friend informed me of a mesh generator matlab code.
Use inpolygon. The input of inpolygon are points in (x,y). But in our case we only have the vector field assigned to a meshgrid. One idea is to solve the ode system to obtain concrete solution pairs (x,y) to plug into the polygon. But solving them takes a lot longer and the pictures are not as nice.
Here's some sample code which I think will generate the kind of plot you want. It uses inpolygon to "filter" out the points inside the polygon. The vector field is still evaluated at the original meshgrid points. It easily extends to multiple polygons too.
clear
clc
x = linspace(0, 1, 21);
[X,Y] = meshgrid(x,x);
U = -Y; %some velocity field
V = X;
hold off
quiver(X,Y,U,V); %quiver on all points
polygon = [0.2,0.2;
0.7,0.5;
0.5,0.8]; %polygon vertices
ind = inpolygon(X,Y,polygon(:,1),polygon(:,2)); %get indices of points inside polygon
hold on
quiver(X(ind),Y(ind),U(ind),V(ind)); %quiver of points inside polygon

Matlab Surface Plot

I have a set of data points, x, y, and z contained in a matrix, record.
In record, each row is a data-point where the first value is the x-coordinate, the second is the y-coordinate, and the third is the z-coordinate. I would like to represent this as a surface plot. I tried:
surf([record(:,1), record(:,2)], record(:,3))
But the results were not what I expected. Any advice?
Try this code for instance.
[x,y,z]=sphere(n);
surf(x,y,z);
axis equal
This code plots with 3 parameters surf the surface of a sphere. As far as I understood from your code you want to utilize the 2 parameters surf for your application.
According to surf help when utilizing 2 parameters surf:
surf(Z) and surf(Z,C) use x = 1:n and y = 1:m. In this case,
the height, Z, is a single-valued function, defined over a
geometrically rectangular grid.
where:
The color scaling is determined
by the range of C
It just doesn't look like you want to utilize C as the color scaling parameter. For better understanding, can you send the contents of record for reference?

Draw evenly-spaced height lines of a function in MATLAB

I would like to draw height lines of a function (represented by matrices, of course), using MATLAB.
I'm familiar with contour, but contour draws lines at even-spaced heights, while I would like to see lines (with height labels), in constant distance from one another when plotted.
This means that if a function grows rapidly in one area, I won't get a plot with dense height lines, but only a few lines, at evenly spaced distances.
I tried to find such an option in the contour help page, but couldn't see anything. Is there a built in function which does it?
There is no built-in function to do this (to my knowledge). You have to realize that in the general case you can't have lines that both represent iso-values and that are spaced with a fixed distance. This is only possible with plots that have special scaling properties, and again, this is not the general case.
This being said, you can imagine to approach your desired plot by using the syntax in which you specify the levels to plots:
...
contour(Z,v) draws a contour plot of matrix Z with contour lines at the data values specified in the monotonically increasing vector v.
...
So all you need is the good vector v of height values. For this we can take the classical Matlab exemple:
[X,Y,Z] = peaks;
contour(X,Y,Z,10);
axis equal
colorbar
and transform it in:
[X,Y,Z] = peaks;
[~, I] = sort(Z(:));
v = Z(I(round(linspace(1, numel(Z),10))));
contour(X,Y,Z,v);
axis equal
colorbar
The result may not be as nice as what you expected, but this is the best I can think of given that what you ask is, again, not possible.
Best,
One thing you could do is, instead of plotting the contours at equally spaces levels (this is what happens when you pass an integer to contour), to plot the contours at fixed percentiles of your data (this requires passing a vector of levels to contour):
Z = peaks(100); % generate some pretty data
nlevel = 30;
subplot(121)
contour(Z, nlevel) % spaced equally between min(Z(:)) and max(Z(:))
title('Contours at fixed height')
subplot(122)
levels = prctile(Z(:), linspace(0, 100, nlevel));
contour(Z, levels); % at given levels
title('Contours at fixed percentiles')
Result:
For the right figure, the lines have somewhat equal spacing for most of the image. Note that the spacing is only approximately equal, and it is impossible to get the equal spacing over the complete image, except in some trivial cases.

Use Matlab trisurf to plot element-wise quantity

Usually, trisurf is used to plot nodal quantity on a triangular mesh. However, I would like to plot some element-wise quantity using the following command.
trisurf(t,p(:,1),p(:,2),elewise_quantity,'edgecolor','k','facecolor','interp');
Where elewise_quantiy should be of the same dimension as p(:,1) or p(:,2), so I create elewise_quantity by associating the element-wise quantity to each node of that element.
In this specific case, the 8 triangular element in the middle are associated with 1 and all other elements are 0-valued. There are 10*10 little squares and 10*10*2 little triangulars.
The problem is, as shown in the picture, trisurf can't produce the effect I want. What I expect is an "exact element-wise description", i.e sharp transition at the edge
Also notice that at each corner, the display is different, this's due to the specific orientation of the triangular, is there an elegant way to deal with it?
If you need sharp discontinuities across elements, I'd recommend not displaying nodal values. Calculate element values at internal integration points (e.g. element average at centroid) and assign that value to the element. Ask Matlab to color each element according to its centroidal or integration point value.
You can set per-triangle colors using this method:
%// Example data
X = rand(100,1);
Y = rand(100,1);
Z = X+Y;
T = delaunay(X,Y);
C = mean(Z(T),2);
%// Plot the data
hh = trisurf(T,X,Y,Z);
set(gca, 'CLim', [min(C), max(C)]);
set(hh,'FaceColor', 'flat', ...
'FaceVertexCData', C, ...
'CDataMapping', 'scaled');
If you also don't want the see the triangles that appear at the boundary, you won't get this behavior from a single call to trimesh. You would need to compute a per-triangle quantity and then drop those you don't want to plot according to the per-triangle quantity.

Getting intermediate points generated by plot() in MATLAB

I've got a series of XY point pairs in MATLAB. These pairs describe points around a shape in an image; they're not a function, meaning that two or more y points may exist for each x value.
I can plot these points individually using something like
plot(B(:,1),B(:,2),'b+');
I can also use plot to connect the points:
plot(B(:,1),B(:,2),'r');
What I'm trying to retrieve are my own point values I can use to connect the points so that I can use them for further analysis. I don't want a fully connected graph and I need something data-based, not just the graphic that plot() produces. I'd love to just have plot() generate these points (as it seems to do behind the scenes), but I've tried using the linseries returned by plot() and it either doesn't work as I understand it or just doesn't give me what I want.
I'd think this was an interpolation problem, but the points don't comprise a function; they describe a shape. Essentially, all I need are the points that plot() seems to calculate; straight lines connecting a series of points. A curve would be a bonus and would save me grief downstream.
How can I do this in MATLAB?
Thanks!
Edit: Yes, a picture would help :)
The blue points are the actual point values (x,y), plotted using the first plot() call above. The red outline is the result of calling plot() using the second approach above. I'm trying to get the point data of the red outline; in other words, the points connecting the blue points.
Adrien definitely has the right idea: define a parametric coordinate then perform linear interpolation on the x and y coordinates separately.
One thing I'd like to add is another way to define your parametric coordinate so you can create evenly-spaced interpolation points around the entire shape in one pass. The first thing you want to do, if you haven't already, is make sure the last coordinate point reconnects to the first by replicating the first point and adding it to the end:
B = [B; B(1,:)];
Next, by computing the total distance between subsequent points then taking the cumulative sum, you can get a parametric coordinate that makes small steps for points close together and larger steps for points far apart:
distance = sqrt(sum(diff(B,1,1).^2,2)); %# Distance between subsequent points
s = [0; cumsum(distance)]; %# Parametric coordinate
Now, you can interpolate a new set of points that are evenly spaced around the edge along the straight lines joining your points using the function INTERP1Q:
sNew = linspace(0,s(end),100).'; %'# 100 evenly spaced points from 0 to s(end)
xNew = interp1q(s,B(:,1),sNew); %# Interpolate new x values
yNew = interp1q(s,B(:,2),sNew); %# Interpolate new y values
These new sets of points won't necessarily include the original points, so if you want to be sure the original points also appear in the new set, you can do the following:
[sAll,sortIndex] = sort([s; sNew]); %# Sort all the parametric coordinates
xAll = [B(:,1); xNew]; %# Collect the x coordinates
xAll = xAll(sortIndex); %# Sort the x coordinates
yAll = [B(:,2); yNew]; %# Collect the y coordinate
yAll = yAll(sortIndex); %# Sort the y coordinates
EXAMPLE:
Here's an example to show how the above code performs (I use 11 pairs of x and y coordinates, one of which is repeated for the sake of a complete example):
B = [0.1371 0.1301; ... %# Sample data
0.0541 0.5687; ...
0.0541 0.5687; ... %# Repeated point
0.0588 0.5863; ...
0.3652 0.8670; ...
0.3906 0.8640; ...
0.4090 0.8640; ...
0.8283 0.7939; ...
0.7661 0.3874; ...
0.4804 0.1418; ...
0.4551 0.1418];
%# Run the above code...
plot(B(:,1),B(:,2),'b-*'); %# Plot the original points
hold on; %# Add to the plot
plot(xNew,yNew,'ro'); %# Plot xNew and yNew
I'd first define some parametric coordinate along the different segments (i.e. between the data points)
s = 1:size(B,1);
Then, just use interp1 to interpolate in s space. e.g. If you want to generate 10 values on the line between data point 5 and 6 :
s_interp = linspace(5,6,10); % parametric coordinate interpolation values
x_coord = interp1(s,B(:,1),s_interp,'linear');
y_coord = interp1(s,B(:,2),s_interp,'linear');
This should do the trick.
A.
Actually there is a MATLAB function "improfile", which might help you in your problem. Lets say these are the 4 coordinates which you want to find the locations between these coordinates.
xi=[15 30 20 10];
yi=[5 25 30 50];
figure;
plot(xi,yi,'r^-','MarkerSize',12)
grid on
Just generate a random image and run the function
n=50; % total number of points between initial coordinates
I=ones(max([xi(:);yi(:)]));
[cx,cy,c] = improfile(I,xi,yi,n);
hold on, plot(cx,cy,'bs-','MarkerSize',4)
Hope it helps