Matlab finding if graphic object exist on figure on given coordinates - matlab

I need to find a way to check if a patch object I created (a rectangle for example) exists within certain X-Y coordinates I specify. As an example, I am using the following code:
a = figure
b = axes('Parent',a,'Xlim',[0 100],'Ylim',[0 100])
x = [0 10 10 0];
y = [0 0 10 10];
patch(x,y,'red')
Now I would like to know if there is an object in the figure in the point with coordinates x=6 and y=3. Is there a way to check this?

Use the findall () and inpolygon function.
hPatches = findall(b, 'type', 'patch');
tgtX = 5; tgtY = 7;
inside = zeros (1, numel(hPatches));
for patchCtr = 1:numel(hPatches)
vert = get (hPatches(patchCtr), 'Vertices');
inside(patchCtr) = inpolygon (tgtX, tgtY, vert(:,1), vert(:,2));
end

You can use findobj to find the objects of interest, in this case patch objects, and access their 'XData' property, then check if it falls within some range. You can do the same with the YData property as well.
Here is an example:
clc
clear
close all
a=figure;
b=axes('Parent',a,'Xlim',[0 30],'Ylim',[0 30]);
x1 = [0 10 10 0];
y1 = [0 0 10 10];
x2 = [15 25 25 15];
y2= [10 10 20 20];
patch(x1,y1,'red')
patch(x2,y2,'blue')
hPatches = findall(a,'Type','patch') %// find patch objects
InfoPatches = get(hPatches); %// Get info about the objects. Check for the XData property.
XDataArray = zeros(4,numel(InfoPatches));
for k = 1:numel(InfoPatches)
XDataArray(:,k) = InfoPatches(k).XData; %// Access the XData property, or any you want.
end
XDataArray
Figure:
And XDataArray look like this:
XDataArray =
15 0
25 10
25 10
15 0
Now there would be the part in which you check whether an object is at some position but that's quite easy to implement. Hope that helps!

I don't know if you are familiar with toolboxes, but the mpt-toolbox could come in handy here (from my Uni).
After you have installed it, you could define the rectangle as a polytope and simply check if a point is within the rectangle.
For your code example above:
Vertices = [0,0;10,0;10,10;0,10];
Rectangle = Polyhedron(Vertices);
TestPoint = [6;3];
Within = Rectangle.contains(Testpoint);
Were Within is a boolean variable (1 if point within Rectangle, 0 otherwise)
EDIT
Of course, the toolbox also works for intersections between your original Rectangle polygon and say another polygon Intersect.

Related

Color a voronoi diagram in MATLAB according to the color values of the initial points

I have a matrix of points named start_coord containing their x and y coordinates, as well as a column denoting their classification (1-5). I.e. the first row looks like [75, 100, 4].
I've calculated a voronoi diagram of this data using the code below
[vc_x, vc_y] = voronoi(start_coord(:,1), start_coord(:,2));
How would I go about coloring the resulting polygons by the classification value of the point contained within each polygon, i.e. the third column in start_coord?
EDIT
For quick plotting of polygons by color reference the answer in the comments below, which helped inform this edit. For getting the voronoi polygons for thousands of points written to an array that can be saved as an image refer to this code:
new_map = zeros(sm_size(1), sm_size(2));
start_coord = readmatrix(char(join([csv_path, '/', run_types(run), common_name_csv], "")));
sc_size = size(start_coord);
dt = delaunayTriangulation(start_coord(:,1:2));
[V,R] = voronoiDiagram(dt);
for i = 1:sc_size(1)
A=V(R{i},:);
B=A(any(~isinf(A),2),:); % omit points at infinity
bw = poly2mask(B(:,1), B(:,2), sm_size(1), sm_size(2));
new_map(bw == 1) = color_map(start_coord(i,3));
end
new_map can then be saved as an array or converted to RGB and saved as an image.
Use voronoiDiagram to get the polygons.
dt = delaunayTriangulation(start_coord(:,1:2));
[V,R] = voronoiDiagram(dt);
Then R{i} will be the vertices of polygon from start_coord(i,:)
So set the color to start_coord(i,3)'s color and:
A=V(R{i},:);
B=A(any(~isinf(A),2),:); % omit points at infinity
plot(polyshape(B));
The only hiccup there is that the vertices at infinity get chopped off. But maybe that will get you close enough to what you want. If you need to fill to the edge, check out the VoronoiLimit function (which I have not tested).
e.g.:
X = [-1.5 3.2; 1.8 3.3; -3.7 1.5; -1.5 1.3; ...
0.8 1.2; 3.3 1.5; -4.0 -1.0;-2.3 -0.7; ...
0 -0.5; 2.0 -1.5; 3.7 -0.8; -3.5 -2.9; ...
-0.9 -3.9; 2.0 -3.5; 3.5 -2.25];
X(:,3) = [ 1 2 1 3 1 2 2 2 2 3 3 3 3 3 3]';
ccode = ["red","green","blue"];
dt = delaunayTriangulation(X(:,1:2));
[V,R] = voronoiDiagram(dt);
figure
voronoi(X(:,1),X(:,2))
hold on
for i = 1:size(X,1)
A=V(R{i},:);
B=A(any(~isinf(A),2),:);
if(size(B,1)>2)
plot(polyshape(B),'FaceColor',ccode(X(i,3)));
end
end
Result:

interp2 with for loop

%I_Phase [0 51.1111 102.2222 153.3333 204.4444 255.5556 306.6667 357.7778 408.8889 460]
%Theta [-45 -30 -15 0 15 30 45 60 75 90]
%Torque_Matrix [0 0 0 0 0 0 0 0 0 0
28.6989 35.9452 41.1581 43.8173 43.5092 40.0174 33.4011 24.0388 12.6221 0.0940
52.6956 67.7241 79.8022 87.4465 89.2066 84.0131 71.5044 52.2439 27.7582 0.3762
71.9900 95.3367 115.9323 130.8876 137.0923 131.9869 114.3100 84.6153 45.4083 0.8464
86.5822 118.7830 149.5483 174.1406 187.1661 183.9389 161.8178 121.1530 65.5724 1.5047
96.4722 138.0630 180.6504 217.2055 239.4282 239.8691 214.0278 161.8569 88.2505 2.3511
101.6600 153.1768 209.2385 260.0824 293.8785 299.7776 270.9400 206.7272 113.4425 3.3856
102.1456 164.1242 235.3126 302.7711 350.5170 363.6642 332.5544 255.7637 141.1486 4.6082
97.9289 170.9054 258.8727 345.2718 409.3438 431.5290 398.8711 308.9666 171.3687 6.0188
89.0100 173.5203 279.9188 387.5844 470.3588 503.3720 469.8900 366.3357 204.1028 7.6176]
I have two vectors (I_Phase1, Theta1) and one matrix (Torque_Matrix), I need to do a interpolation with interp2, but my fuction and loop when running interp2, Theta_Int and I_Phase_Int values ​​are only 90 and 460 respectively, so I only have a value for Torque_Value and I need values ​​at -45: 90 and 0: 460, I need to create a new array with Torque_Values ​​values. I need help, please.
surf(Theta1,I_Phase1,Torque_Matrix);
hold on
Matrix_int = zeros(100);
index_Theta = 0;
index_I = 0;
for Theta_Int = -45:90;
for I_Phase_Int = 0:460;
Torque_Value = interp2(Theta1,I_Phase1,Torque_Matrix,Theta_Int,I_Phase_Int);
end
end
surf(Theta_Int,I_Phase_Int,Torque_Value,'.r');
You can use the interp2 function with vectors, but if it helps for a beginner as yourself to see what is going on in each step, for loops will still work. You just need to create vectors for Theta_Int and I_Phase_Int. Then when you call interp2, you index Theta_Int(j) and I_Phase_Int(k), as well as store the values in Torque_Value(k,j). I swapped the for loops around so when you do the surf it will plot along the same axis as above.
Theta_Int = -45:90;
I_Phase_Int = 0:460;
for k = 1:length(I_Phase_Int)
for j = 1:length(Theta_Int)
Torque_Value(k, j) = interp2(Theta,I_Phase,Torque_Matrix,Theta_Int(j),I_Phase_Int(k));
end
end
figure();
surf(Theta_Int, I_Phase_Int, Torque_Value);
Also created a new figure so both of your plots will be shown. So just replace your for loop down with this code and it should work.

Trying to apply a color map to a bar graph in MATLAB

I have a collection of data that I am trying to graph as a histogram. Additionally, I would like to color the individual bars as a function of the x axis location. CData, described here seems to do what I want but I can't get it to work.
Here is my code:
h = bar(new_edge,N,'hist','FaceColor','flat');
hold on
for n = 1:length(N)
if (x - x/1.09) - (x-1) > 0
probability(n) = 1 - ((x-x/1.09) - (x-1))/((x - 1/1.09)+(x/0.91 - x));
else
probability(n) = 1;
end
color_num = 30;
cm = jet(color_num);
min = 0.5450;
max = 1;
color_map_index = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
rbg = cm(color_map_index,:);
h.CData(n,:) = rbg;
end
Similar to the MATLAB example, I first create my bar graph. Next, I want to loop through and prescribe the color for each bar based on a calculation. I do this by creating a colormap with # of bins and a min/max, getting a color index, then finally retrieving the rbg value. I get the following error when I try to apply the color:
Subscript indices must either be real positive integers or logicals.
h.CData(n,:) = rbg;
If I dive into the h object, MATLAB tells me that CData has a size of (4x65). What's going on here? Both new_edge and N are 1x65 vectors.
Are you certain that the error you're getting ("Subscript indices must either be real positive integers or logicals") is coming from the following line?:
h.CData(n,:) = rbg;
Since we know n is a positive integer greater than or equal to one, the indexing here shouldn't have a problem. It's more likely that your error is coming from the line above it (i.e. the value for color_map_index is less than 1). I would double-check how you are computing color_map_index.
You could also try using function notation (i.e. get and set) instead of dot notation to update the property:
cData = get(h, 'CData');
cData(n, :) = rbg;
set(h, 'CData', cData);
Incidentally, you should also not be giving your variables the same name as existing functions, like you are doing here:
...
min = 0.5450;
max = 1;
...
This shadows the built-in min and max functions, which can also lead to the same error message under other conditions. Definitely rename those.
If you are still having trouble after trying those fixes, you could try setting the color using indexed color mapping instead, as illustrated in one of my other answers (near the bottom). As a simple example, the following plots 20 bars of 30 different possible values, then colors them based on their height:
color_num = 30;
N = randi(color_num, 1, 20);
hBar = bar(N, 'hist');
colormap(parula(color_num));
set(hBar, 'CData', N, 'CDataMapping', 'direct');
And the plot:
This could be a problem with your Matlab version.
When I test CData with bar on 2017b, this works:
openExample('graphics/ControlIndividualBarColorsExample')
When I try it on 2017a, it doesn't run.
Does the example work?
Given that this is a version control problem, there's really not a clean solution. In case anyone else comes along with a similar question and has the same version, here's a workaround that worked for me in 2017a.
Rather than creating a bar chart, you can simply draw rectangles. It's messy, but it does produce the desired result.
[N,edges] = histcounts(AB(AB<2));
probability = zeros(1,length(N));
new_edge = zeros(1,length(N));
for m = 1:length(N)
new_edge(m) = (edges(m) + edges(m+1))/2;
end
figure
hold on
for n = 1:length(N)
x = new_edge(n);
if ((x - x/1.09) - (x-1)) > 0
probability(n) = 1 - ((x-x/1.09) - (x-1))./((x - x/1.09)+(x/0.91 - x));
else
probability(n) = 1;
end
color_num = 100;
cm = jet(color_num);
min = 0;
max = 1;
color_map_index(n) = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
rbg = cm(color_map_index(n),:);
rectangle('Position',[edges(n),0,(edges(n+1)-edges(n)),N(n)],'Edgecolor','k','FaceColor',rbg)
end
set(gcf,'color','w');
blah = colorbar;

Summing Values based on Area in Matlab

Im trying to write a code in Matlab to calculate an area of influence type question. This is an exert from my data (Weighting, x-coord, y-coord):
M =
15072.00 486.00 -292
13269.00 486.00 -292
12843.00 414.00 -267
10969.00 496.00 -287
9907.00 411.00 -274
9718.00 440.00 -265
9233.00 446.00 -253
9138.00 462.00 -275
8830.00 496.00 -257
8632.00 432.00 -253
R =
-13891.00 452.00 -398
-13471.00 461.00 -356
-12035.00 492.00 -329
-11309.00 413.00 -353
-11079.00 467.00 -375
-10659.00 493.00 -333
-10643.00 495.00 -338
-10121.00 455.00 -346
-9795.00 456.00 -367
-8927.00 485.00 -361
-8765.00 467.00 -351
I want to make a function to calculate the sum of the weightings at any given position based on a circle of influence of 30 for each coordinate.
I have thought of using a for loop to calculate each point independently and summing the result but seems unnecessarily complicated and inefficient.
I also thought of assigning an intensity of color to each circle and overlaying them but I dont know how to change color intensity based on value here is my attempt so far (I would like to have a visual of the result):
function [] = Influence()
M = xlsread('MR.xlsx','A4:C310');
R = xlsread('MR.xlsx','E4:G368');
%these are my values around 300 coordinates
%M are negative values and R positive, I want to see which are dominant in their regions
hold on
scatter(M(:,2),M(:,3),3000,'b','filled')
scatter(R(:,2),R(:,3),3000,'y','filled')
axis([350 650 -450 -200])
hold off
end
%had to use a scalar of 3000 for some reason as it isnt correlated to the graph size
I'd appreciate any ideas/solutions thank you
This is the same but with ca. 2000 data points
How about this:
r_influence = 30; % radius of influence
r = #(p,A) sqrt((p(1)-A(:,2)).^2 + (p(2)-A(:,3)).^2); % distance
wsum = #(p,A) sum(A(find(r(p,A)<=r_influence),1)); % sum where distance less than roi
% compute sum on a grid
xrange = linspace(350,550,201);
yrange = linspace(-200,-450,201);
[XY,YX] = meshgrid(xrange,yrange);
map_M = arrayfun(#(p1,p2) wsum([p1,p2],M),XY,YX);
map_R = arrayfun(#(p1,p2) wsum([p1,p2],R),XY,YX);
figure(1);
clf;
imagesc(xrange,yrange,map_M + map_R);
colorbar;
Gives a picture like this:
Is that what you are looking for?

plot interpolate a curve between 2 different types of curves in matlab

I have the following data that predicts a curve in the middle of the two curves which has different equation and datas.I also need to spline and smothen the curve of the middle curve
I've tried searching other codes here in stackoverflow but this is the most close to the right solution. So far the plot for the two curve is right but the interpolated point gives me wrong plot.
Im trying to find the plot for val=30 given that (a25,vel25)=25 and (a50,vel50)=50. Please help me troubleshoot and get a table of data (x,y) for the generated interpolated curve. Thanks for your help
generated plot using this program
a50=[1.05
0.931818182
0.931818182
0.968181818
1.045454545
1.136363636
1.354545455
1.568181818
1.718181818
1.945454545
2.159090909
2.454545455
2.772727273
];
vel50=[0.85
0.705555556
0.605555556
0.533333333
0.472222222
0.45
0.427777778
0.45
0.477777778
0.533333333
0.611111111
0.711111111
0.827777778
];
a25=[0.5
0.613636364
0.686363636
0.795454545
0.918181818
0.963636364
1.090909091
1.236363636
1.304545455
1.431818182
1.545454545
1.659090909
1.818181818
];
vel25=[0.425555556
0.354444444
0.302222222
0.266666667
0.233333333
0.226666667
0.211111111
0.222222222
0.237777778
0.266666667
0.311111111
0.35
0.402222222
];
plot(a25,vel25,'b-');
hold on
plot(a50,vel50,'g-');
minX = min([a25 a50]);
maxX = max([a25,a50]);
xx = linspace(minX,maxX,100);
vel25_inter = interp1(a25,vel25,xx);
vel50_inter = interp1(a50,vel50,xx);
val = 30; % The interpolated point
interpVel = vel25_inter + ((val-25).*(vel50_inter-vel25_inter))./(50-25);
plot(xx,interpVel,'r-');
The question and answer linked in comment still apply and can be a solution.
In your case, it is not so direct because your data are not on the same grid and some are not monotonic, but once they are packaged properly, the easiest solution is still to use griddata.
By packaged properly, I mean finding the maximum common interval (on x, or what you call a), so the data can be interpolated between curve without producing NaNs.
This seems to work:
The red dashed line is the values interpolated at val=30, all the other lines are interpolations for values between 25 to 50.
The code to get there:
% back up original data, just for final plot
bkp_a50 = a50 ; bkp_vel50 = vel50 ;
% make second x vector monotonic
istart = find( diff(a50)>0 , 1 , 'first') ;
a50(1:istart-1) = [] ;
vel50(1:istart-1) = [] ;
% prepare a 3rd dimension vector (from 25 to 50)
T = [repmat(25,size(a25)) ; repmat(50,size(a50)) ] ;
% merge all observations together
A = [ a25 ; a50] ;
V = [vel25 ; vel50] ;
% find the minimum domain on which data can be interpolated
% (anything outside of that will return NaN)
Astart = max( [min(a25) min(a50)] ) ;
Astop = min( [max(a25) max(a50)] ) ;
% use the function 'griddata'
[TI,AI] = meshgrid( 25:50 , linspace(Astart,Astop,10) ) ;
VI = griddata(T,A,V,TI,AI) ;
% plot all the intermediate curves
plot(AI,VI)
hold on
% the original curves
plot(a25,vel25,'--k','linewidth',2)
plot(bkp_a50,bkp_vel50,'--k','linewidth',2)
% Highlight the curve at T = 30 ;
c30 = find( TI(1,:) == 30 ) ;
plot(AI(:,c30),VI(:,c30),'--r','linewidth',2)
There were quite a few issues with your code that's why it was not executing properly. I have just made very little changes to your code and made it running,
clc
%13
a50=[1.05
0.931818182
0.932
0.968181818
1.045454545
1.136363636
1.354545455
1.568181818
1.718181818
1.945454545
2.159090909
2.454545455
2.772727273
];
%13
vel50=[0.85
0.705555556
0.605555556
0.533333333
0.472222222
0.45
0.427777778
0.45
0.477777778
0.533333333
0.611111111
0.711111111
0.827777778
];
%13
a25=[0.5
0.613636364
0.686363636
0.795454545
0.918181818
0.963636364
1.090909091
1.236363636
1.304545455
1.431818182
1.545454545
1.659090909
1.818181818
];
%13
vel25=[0.425555556
0.354444444
0.302222222
0.266666667
0.233333333
0.226666667
0.211111111
0.222222222
0.237777778
0.266666667
0.311111111
0.35
0.402222222
];
plot(a25,vel25,'b-');
hold on
plot(a50,vel50,'g-');
minX = min([a25 a50])
maxX = max([a25 a50])
%xx = linspace(minX,maxX);
xx = linspace(0.5,2.7727,100);
vel25_inter = interp1(a25,vel25,xx);
vel50_inter = interp1(a50,vel50,xx);
val = 30; % The interpolated point
interpVel = vel25_inter + ((val-25).*(vel50_inter-vel25_inter))./(50-25);
plot(xx,interpVel,'r-');
There issues were
The interval on which you wanted to interpolate is xx = linspace(minX,maxX); but it gives an error of the type,
Matrix dimensions must agree.
Because you were assigning two values for the starting point and two for the ending point. So I replace it with xx = linspace(0.5,2.7727,100); where the starting point is being the minimum of the two minimum minX and the same for maxX
There are values of a50 (0.931818182) that repeat which was producing the following error
The grid vectors are not strictly monotonic increasing.
I change one of the value and replaced it with 0.932
The output is not that promising but is suppose the one you want?