Coloring sectors in MATLAB - matlab

I am trying to animate a ball bouncing but having trouble creating a basic multicolor ball i can then rotate as a whole in each frame. I have 512 points on the circumference of the ball split into 8 sectors, each a separate color. So far I have 2 matrices that are 8x64, representing the x and the y coordinates of points along the circumference of the ball, each of the rows being the its own sector.
I want to know how to fill these "ranges" along the circle such that it will look like a beach ball, creating a function to do this with the two x and y coordinate matrices as inputs. Your help would be greatly appreciated!
Basic skeleton function:
% Expects 8xN x and y point matrices
function draw_ball(x,y)
% Draw the 8 sectors filling them with unique colors
end

You want to create a PATCH with draw_ball. The nicest way to do this would require you to have the data stored as faces and vertices, but you if you like to keep your 8xN arrays, you can instead create 8 patches that describe the ball.
This way, your function would look like this:
function pH = drawBall(x,y)
%# count sectors
nSectors = size(x,1);
%# create a colormap
ballColors = jet(nSectors);
%# set hold-state of current axes to 'on'
set(gca,'nextPlot','add')
%# initialize array of plot handles
pH = zeros(nSectors,1);
%# add [0,0] to every sector
x = [x,zeros(nSectors,1)];
y = [y,zeros(nSectors,1)];
%# plot patches
for s = 1:nSectors
%# plot sectors with black lines. If there shouldn't be lines, put 'none' instead of 'k'
pH(s) = patch(x(s,:),y(s,:),ballColors(s,:),'EdgeColor','k');
end

The function could begin by transforming the (x,y) coordinate system (Cartesian) into the polar coordinate system, where an angle of each point is available. The associated matlab function is cart2pol
After tranforming to polar, you could use floor to split the points into 8 sectors... something along the line of floor(polar_anle_in_radians/(2*pi)*8)

Related

How to create a smoother heatmap

I'd like to create a heat map to analyze the porosity of some specimens that I have 3D-printed. the X-Y coordinates are fixed since they are the positions in which the specimens are printed on the platform.
Heatmap:
Tbl = readtable('Data/heatmap/above.csv');
X = Tbl(:,1);
Y = Tbl(:,2);
porosity = Tbl(:,3);
hmap_above = heatmap(Tbl, 'X', 'Y', 'ColorVariable', 'porosity');
The first question is: how can I sort the Y-axis of the plot? since it goes from the lower value (top) to the higher value (bottom) and I need it the other way around.
The second question is: I only have around 22 data points and most of the chart is without color, so I'd like to get a smoother heatmap without the black parts.
The data set is quite simple and is shown below:
X
Y
porosity
74.4615
118.3773
0.039172163
84.8570
69.4699
0.046314637
95.2526
20.5625
0.041855213
105.6482
-28.3449
0.049796110
116.0438
-77.2522
0.045010692
25.5541
107.9817
0.038562053
35.9497
59.0743
0.041553065
46.3453
10.1669
0.036152061
56.7408
-38.7404
0.060719664
67.1364
-87.6478
0.037756115
-23.3533
97.5861
0.052840845
-12.9577
48.6787
0.045216851
-2.5621
-0.2286
0.033645353
7.8335
-49.1360
0.030670865
18.2290
-98.0434
0.024952472
-72.2607
87.1905
0.036199237
-61.8651
38.2831
0.026725885
-51.4695
-10.6242
0.029212058
-41.0739
-59.5316
0.028572611
-30.6783
-108.4390
0.036796151
-121.1681
76.7949
0.031688096
-110.7725
27.8876
0.034619855
-100.3769
-21.0198
0.039070101
-89.9813
-69.9272
NaN
-79.5857
-118.8346
NaN
If you want to assign color to the "black parts" you will have to interpolate the porosity over a finer grid than you currently have.
The best tool for 2D interpolation over a uniformly sampled grid is griddata
First you have to define the X-Y grid you want to interpolate over, and choose a suitable mesh density.
% this will be the number of points over each side of the grid
gridres = 100 ;
% create a uniform vector on X, from min to max value, made of "gridres" points
xs = linspace(min(X),max(X),gridres) ;
% create a uniform vector on Y, from min to max value, made of "gridres" points
ys = linspace(min(Y),max(Y),gridres) ;
% generate 2D grid coordinates from xs and ys
[xq,yq]=meshgrid(xs,ys) ;
% now interpolate the pososity over the new grid
InterpolatedPorosity = griddata(X,Y,porosity,xq,yq) ;
% Reverse the Y axis (flip the `yq` matrix upside down)
yq = flipud(yq) ;
Now my version of matlab does not have the heatmap function, so I'll just use pcolor for display.
% now display
hmap_above = pcolor(xq,yq,InterpolatedPorosity);
hmap_above.EdgeColor = [.5 .5 .5] ; % cosmetic adjustment
colorbar
colormap jet
title(['Gridres = ' num2str(gridres)])
And here are the results with different grid resolutions (the value of the gridres variable at the beginning):
Now you could also ask MATLAB to further graphically smooth the domain by calling:
shading interp
Which in the 2 cases above would yield:
Notes: As you can see on the gridres=100, you original data are so scattered that at some point interpolating on a denser grid is not going to produce any meaningful improvment. No need to go overkill on your mesh density if you do not have enough data to start with.
Also, the pcolor function uses the matrix input in the opposite way than heatmap. If you use heatmap, you have to flip the Y matrix upside down as shown in the code. But if you end up using pcolor, then you don't need to flip the Y matrix.
The fact that I did it in the code (to show you how to do) made the result display in the wrong orientation for a display with pcolor. Simply comment the yq = flipud(yq) ; statement if you stick with pcolor.
Additionally, if you want to be able to follow the isolevels generated by the interpolation, you can use contour to add a layer of information:
Right after the code above, the lines:
hold on
contour(xq,yq,InterpolatedPorosity,20,'LineColor','k')
will yield:

multiple matlab contour plots with one level

I have a number of 2d probability mass functions from 2 categories. I am trying to plot the contours to visualise them (for example at their half height, but doesn't really matter).
I don't want to use contourf to plot directly because I want to control the fill colour and opacity. So I am using contourc to generate xy coordinates, and am then using fill with these xy coordinates.
The problem is that the xy coordinates from the contourc function have strange numbers in them which cause the following strange vertices to be plotted.
At first I thought it was the odd contourmatrix format, but I don't think it is this as I am only asking for one value from contourc. For example...
contourmatrix = contourc(x, y, Z, [val, val]);
h = fill(contourmatrix(1,:), contourmatrix(2,:), 'r');
Does anyone know why the contourmatrix has these odd values in them when I am only asking for one contour?
UPDATE:
My problem seems might be a failure mode of contourc when the input 2D matrix is not 'smooth'. My source data is a large set of (x,y) points. Then I create a 2D matrix with some hist2d function. But when this is noisy the problem is exaggerated...
But when I use a 2d kernel density function to result in a much smoother 2D function, the problem is lessened...
The full process is
a) I have a set of (x,y) points which form samples from a distribution
b) I convert this into a 2D pmf
c) create a contourmatrix using contourc
d) plot using fill
Your graphic glitches are because of the way you use the data from the ContourMatrix. Even if you specify only one isolevel, this can result in several distinct filled area. So the ContourMatrix may contain data for several shapes.
simple example:
isolevel = 2 ;
[X,Y,Z] = peaks ;
[C,h] = contourf(X,Y,Z,[isolevel,isolevel]);
Produces:
Note that even if you specified only one isolevel to be drawn, this will result in 2 patches (2 shapes). Each has its own definition but they are both embedded in the ContourMatrix, so you have to parse it if you want to extract each shape coordinates individually.
To prove the point, if I simply throw the full contour matrix to the patch function (the fill function will create patch objects anyway so I prefer to use the low level function when practical). I get the same glitch lines as you do:
xc = X(1,:) ;
yc = Y(:,1) ;
c = contourc(xc,yc,Z,[isolevel,isolevel]);
hold on
hp = patch(c(1,1:end),c(2,1:end),'r','LineWidth',2) ;
produces the same kind of glitches that you have:
Now if you properly extract each shape coordinates without including the definition column, you get the proper shapes. The example below is one way to extract and draw each shape for inspiration but they are many ways to do it differently. You can certainly compact the code a lot but here I detailed the operations for clarity.
The key is to read and understand how the ContourMatrix is build.
parsed = false ;
iShape = 1 ;
while ~parsed
%// get coordinates for each isolevel profile
level = c(1,1) ; %// current isolevel
nPoints = c(2,1) ; %// number of coordinate points for this shape
idx = 2:nPoints+1 ; %// prepare the column indices of this shape coordinates
xp = c(1,idx) ; %// retrieve shape x-values
yp = c(2,idx) ; %// retrieve shape y-values
hp(iShape) = patch(xp,yp,'y','FaceAlpha',0.5) ; %// generate path object and save handle for future shape control.
if size(c,2) > (nPoints+1)
%// There is another shape to draw
c(:,1:nPoints+1) = [] ; %// remove processed points from the contour matrix
iShape = iShape+1 ; %// increment shape counter
else
%// we are done => exit while loop
parsed = true ;
end
end
grid on
This will produce:

Arc between two 3d vectors

How I can simply make an arc with a label in 3D Matlab plot? I have two 3D vectors (plot::Arrow3d)and I want to name an angle between them and I want to show it on 3D plot.
Edit1:
I use MuPad to render my drawing, I suppose to draw the arc between two vectors by plot::Arc3d(1, [0,0,0], n, al..bet). where n is simple to find. But I completely don't understand where the arc angle starts in 3D. Does somobody can show me how to find the zero angle.
Short answer, use the text function.
See if this gets you started:
%A couple of random points in 3 space
xyz1 = randn(3,1);
xyz2 = randn(3,1);
%Set up a figure, and create "arrow" plots within
figure(3781);
clf;
hold on
quiver3(0,0,0,xyz1(1), xyz1(2), xyz1(3),0,'b')
quiver3(0,0,0,xyz2(1), xyz2(2), xyz2(3),0,'r')
view(3)
%Add a line connecting teh arrows, and a text label
plot3([xyz1(1) xyz2(1)], [xyz1(2) xyz2(2)], [xyz1(3) xyz2(3)],'k:')
xyzCenter = mean([xyz1 xyz2],2);
h = text(xyzCenter(1), xyzCenter(2), xyzCenter(3), 'Label text here');
set(h,'Color','b')
get(h); %For more properties to set

How to assign values to particular point in 3D rectangle in matlab

I want to animate the varying temperature gradient in 3D rectangle. I have temperature values at specified points in a real container. I am not been able to figure out how to pass the temperature values as specified point in 3D container in Matlab.Lets say I have 10 points on one side of rectangle and same as on other remaining five sides.
any suggestions
Let's assume that your rectangular container is oriented in space with one vertex at (0,0,0) and sides along x, y and z axis. And you have set of points each with 3-point coordinate (x,y,z). In MATLAB it's probably represented by 3 vectors X, Y and Z. You also have a vector of temperature values (say T) for each points.
Then you can use SCATTER3 function to plot the points:
scatter3(X,Y,Z,[],T,'.')
You can change the size of points substituting the empty parameter with a value.
If you have point only on the faces of the container, it means one of the coordinate is either 0 or the size of corresponding side.
the colors are controlled by current color map. You can change it with COLORMAP function. For temperature the good one is 'hot' or 'cool'. Show the color scale with COLORBAR.
Here is an example with random data:
%# random coordinates
X = rand(60,1,1);
Y = rand(60,1,1);
Z = rand(60,1,1);
%# put the points into faces
X(1:10) = 0;
X(10:20) = 1;
Y(20:30) = 0;
Y(30:40) = 1;
Z(40:50) = 0;
Z(50:60) = 1;
%# temperature vector
T = rand(60,1,1) * 100;
%# plot
scatter3(X,Y,Z,[],T,'.')
grid off
box on
colormap hot
colorbar
Temp=zeros(10,10,10);
Temp(5,2,4)=25;

MATLAB, Filling in the area between two sets of data, lines in one figure

I have a question about using the area function; or perhaps another function is in order...
I created this plot from a large text file:
The green and the blue represent two different files. What I want to do is fill in the area between the red line and each run, respectively. I can create an area plot with a similar idea, but when I plot them on the same figure, they do not overlap correctly. Essentially, 4 plots would be on one figure.
I hope this makes sense.
Building off of #gnovice's answer, you can actually create filled plots with shading only in the area between the two curves. Just use fill in conjunction with fliplr.
Example:
x=0:0.01:2*pi; %#initialize x array
y1=sin(x); %#create first curve
y2=sin(x)+.5; %#create second curve
X=[x,fliplr(x)]; %#create continuous x value array for plotting
Y=[y1,fliplr(y2)]; %#create y values for out and then back
fill(X,Y,'b'); %#plot filled area
By flipping the x array and concatenating it with the original, you're going out, down, back, and then up to close both arrays in a complete, many-many-many-sided polygon.
Personally, I find it both elegant and convenient to wrap the fill function.
To fill between two equally sized row vectors Y1 and Y2 that share the support X (and color C):
fill_between_lines = #(X,Y1,Y2,C) fill( [X fliplr(X)], [Y1 fliplr(Y2)], C );
You can accomplish this using the function FILL to create filled polygons under the sections of your plots. You will want to plot the lines and polygons in the order you want them to be stacked on the screen, starting with the bottom-most one. Here's an example with some sample data:
x = 1:100; %# X range
y1 = rand(1,100)+1.5; %# One set of data ranging from 1.5 to 2.5
y2 = rand(1,100)+0.5; %# Another set of data ranging from 0.5 to 1.5
baseLine = 0.2; %# Baseline value for filling under the curves
index = 30:70; %# Indices of points to fill under
plot(x,y1,'b'); %# Plot the first line
hold on; %# Add to the plot
h1 = fill(x(index([1 1:end end])),... %# Plot the first filled polygon
[baseLine y1(index) baseLine],...
'b','EdgeColor','none');
plot(x,y2,'g'); %# Plot the second line
h2 = fill(x(index([1 1:end end])),... %# Plot the second filled polygon
[baseLine y2(index) baseLine],...
'g','EdgeColor','none');
plot(x(index),baseLine.*ones(size(index)),'r'); %# Plot the red line
And here's the resulting figure:
You can also change the stacking order of the objects in the figure after you've plotted them by modifying the order of handles in the 'Children' property of the axes object. For example, this code reverses the stacking order, hiding the green polygon behind the blue polygon:
kids = get(gca,'Children'); %# Get the child object handles
set(gca,'Children',flipud(kids)); %# Set them to the reverse order
Finally, if you don't know exactly what order you want to stack your polygons ahead of time (i.e. either one could be the smaller polygon, which you probably want on top), then you could adjust the 'FaceAlpha' property so that one or both polygons will appear partially transparent and show the other beneath it. For example, the following will make the green polygon partially transparent:
set(h2,'FaceAlpha',0.5);
You want to look at the patch() function, and sneak in points for the start and end of the horizontal line:
x = 0:.1:2*pi;
y = sin(x)+rand(size(x))/2;
x2 = [0 x 2*pi];
y2 = [.1 y .1];
patch(x2, y2, [.8 .8 .1]);
If you only want the filled in area for a part of the data, you'll need to truncate the x and y vectors to only include the points you need.