Selecting the maximum matched pairs - matlab

I have two groups with different IDs, I got the possible matches by running a code that looked into cases that achieved the criteria, however, it returned for example for one ID from Group A, I have more than one match from Group B. I would like to get rid of the repetition and choose the matched pair randomly that achieved the maximum number of matched pairs at the end. Any Idea of how to solve this?
Here is my code:
SH = readtable('contol_parameters.xlsx','Sheet','m');
%% check if crieria met
numElementsX = length(rmmissing(SH.Ages1));
numElementsY = length(rmmissing(SH.Ages2));
U1 = [];
U2= [];
for r=1:numElementsX
for s=1:numElementsY
if (abs(rmmissing(SH.Ages1(r))-rmmissing(SH.Ages2(s)))<=10) && (abs(rmmissing(SH.vol_1(r))-rmmissing(SH.vol_2(s)))<=10)
U1(end+1)= SH.ID1(r);
U2(end+1)= SH.ID2(s);
end
end
end
%generated list
U_TS=[U1', U2'];
%results
Group A Group B
216 217
216 221
216 222
216 234
216 256
216 262
216 266
216 330
216 390
225 217
225 222
225 234
225 239
225 256
225 257
225 260
225 263
225 266
225 277
225 302
225 324
225 330
225 333
225 341
225 359
225 381
225 386
225 390
225 423
225 435
225 436
225 442
225 466
225 470
225 478
227 257
227 260
227 263
227 277
227 302

If I understand your objective I would try the following:
uA = unique(A);
uB = unique(B);
iCnt = zeros(length(uA),length(uB);
for ii = 1:length(uA)
for jj = 1:length(uB)
iCnt(ii,jj) = sum((A==uA(ii) & B==uB(jj));
end
end
[~,ind] = sort(sum(iCnt),'ascend');
uB = uB(ind);
iCnt = iCnt(:,ind);
%you now have a matrix (iCnt) where the least common members of groupB will be in the leftmost columns of iCnt and for each row (which represents the unique members of GroupA in vector uA) you can find the first non-zero column of iCnt to pick the least common member of GroupB. If that member of B has already been selected previously, you could go to the next non-zero column for another candidate

Related

changing the range / limits on a polar chart in octave / matlab

I'm using Octave 4.0 using Linux which is similar to Matlab
Is it possible to have a different range of numbers on a polar chart and have them show up along with the degrees also?
The normal polar plot goes from 0-359 degrees shown in black in image, I would like the range and tick values to be from 0 to 100 shown in red in the image is this possible? If so can two ranges be shown on a polar plot at the same time (0-359 and 0-100) almost like plotting 2 y axis using plotyy on the same plot?
See image below of polar plot
Here's the the numbers 0-359 and there corresponding numbers 0-100 matching up.
0 0
1 0.27855
2 0.5571
3 0.83565
4 1.11421
5 1.39276
6 1.67131
7 1.94986
8 2.22841
9 2.50696
10 2.78552
11 3.06407
12 3.34262
13 3.62117
14 3.89972
15 4.17827
16 4.45682
17 4.73538
18 5.01393
19 5.29248
20 5.57103
21 5.84958
22 6.12813
23 6.40669
24 6.68524
25 6.96379
26 7.24234
27 7.52089
28 7.79944
29 8.07799
30 8.35655
31 8.6351
32 8.91365
33 9.1922
34 9.47075
35 9.7493
36 10.0279
37 10.3064
38 10.585
39 10.8635
40 11.1421
41 11.4206
42 11.6992
43 11.9777
44 12.2563
45 12.5348
46 12.8134
47 13.0919
48 13.3705
49 13.649
50 13.9276
51 14.2061
52 14.4847
53 14.7632
54 15.0418
55 15.3203
56 15.5989
57 15.8774
58 16.156
59 16.4345
60 16.7131
61 16.9916
62 17.2702
63 17.5487
64 17.8273
65 18.1058
66 18.3844
67 18.663
68 18.9415
69 19.2201
70 19.4986
71 19.7772
72 20.0557
73 20.3343
74 20.6128
75 20.8914
76 21.1699
77 21.4485
78 21.727
79 22.0056
80 22.2841
81 22.5627
82 22.8412
83 23.1198
84 23.3983
85 23.6769
86 23.9554
87 24.234
88 24.5125
89 24.7911
90 25.0696
91 25.3482
92 25.6267
93 25.9053
94 26.1838
95 26.4624
96 26.7409
97 27.0195
98 27.2981
99 27.5766
100 27.8552
101 28.1337
102 28.4123
103 28.6908
104 28.9694
105 29.2479
106 29.5265
107 29.805
108 30.0836
109 30.3621
110 30.6407
111 30.9192
112 31.1978
113 31.4763
114 31.7549
115 32.0334
116 32.312
117 32.5905
118 32.8691
119 33.1476
120 33.4262
121 33.7047
122 33.9833
123 34.2618
124 34.5404
125 34.8189
126 35.0975
127 35.376
128 35.6546
129 35.9331
130 36.2117
131 36.4903
132 36.7688
133 37.0474
134 37.3259
135 37.6045
136 37.883
137 38.1616
138 38.4401
139 38.7187
140 38.9972
141 39.2758
142 39.5543
143 39.8329
144 40.1114
145 40.39
146 40.6685
147 40.9471
148 41.2256
149 41.5042
150 41.7827
151 42.0613
152 42.3398
153 42.6184
154 42.8969
155 43.1755
156 43.454
157 43.7326
158 44.0111
159 44.2897
160 44.5682
161 44.8468
162 45.1253
163 45.4039
164 45.6825
165 45.961
166 46.2396
167 46.5181
168 46.7967
169 47.0752
170 47.3538
171 47.6323
172 47.9109
173 48.1894
174 48.468
175 48.7465
176 49.0251
177 49.3036
178 49.5822
179 49.8607
180 50.1393
181 50.4178
182 50.6964
183 50.9749
184 51.2535
185 51.532
186 51.8106
187 52.0891
188 52.3677
189 52.6462
190 52.9248
191 53.2033
192 53.4819
193 53.7604
194 54.039
195 54.3175
196 54.5961
197 54.8747
198 55.1532
199 55.4318
200 55.7103
201 55.9889
202 56.2674
203 56.546
204 56.8245
205 57.1031
206 57.3816
207 57.6602
208 57.9387
209 58.2173
210 58.4958
211 58.7744
212 59.0529
213 59.3315
214 59.61
215 59.8886
216 60.1671
217 60.4457
218 60.7242
219 61.0028
220 61.2813
221 61.5599
222 61.8384
223 62.117
224 62.3955
225 62.6741
226 62.9526
227 63.2312
228 63.5097
229 63.7883
230 64.0669
231 64.3454
232 64.624
233 64.9025
234 65.1811
235 65.4596
236 65.7382
237 66.0167
238 66.2953
239 66.5738
240 66.8524
241 67.1309
242 67.4095
243 67.688
244 67.9666
245 68.2451
246 68.5237
247 68.8022
248 69.0808
249 69.3593
250 69.6379
251 69.9164
252 70.195
253 70.4735
254 70.7521
255 71.0306
256 71.3092
257 71.5877
258 71.8663
259 72.1448
260 72.4234
261 72.7019
262 72.9805
263 73.2591
264 73.5376
265 73.8162
266 74.0947
267 74.3733
268 74.6518
269 74.9304
270 75.2089
271 75.4875
272 75.766
273 76.0446
274 76.3231
275 76.6017
276 76.8802
277 77.1588
278 77.4373
279 77.7159
280 77.9944
281 78.273
282 78.5515
283 78.8301
284 79.1086
285 79.3872
286 79.6657
287 79.9443
288 80.2228
289 80.5014
290 80.7799
291 81.0585
292 81.337
293 81.6156
294 81.8942
295 82.1727
296 82.4513
297 82.7298
298 83.0084
299 83.2869
300 83.5655
301 83.844
302 84.1226
303 84.4011
304 84.6797
305 84.9582
306 85.2368
307 85.5153
308 85.7939
309 86.0724
310 86.351
311 86.6295
312 86.9081
313 87.1866
314 87.4652
315 87.7437
316 88.0223
317 88.3008
318 88.5794
319 88.8579
320 89.1365
321 89.415
322 89.6936
323 89.9721
324 90.2507
325 90.5292
326 90.8078
327 91.0864
328 91.3649
329 91.6435
330 91.922
331 92.2006
332 92.4791
333 92.7577
334 93.0362
335 93.3148
336 93.5933
337 93.8719
338 94.1504
339 94.429
340 94.7075
341 94.9861
342 95.2646
343 95.5432
344 95.8217
345 96.1003
346 96.3788
347 96.6574
348 96.9359
349 97.2145
350 97.493
351 97.7716
352 98.0501
353 98.3287
354 98.6072
355 98.8858
356 99.1643
357 99.4429
358 99.7214
359 100
Here's an image of the numbers 0-359 and there corresponding numbers 0-100 matching up.
Numbers matching up
The polar plot object in Octave adds the rtick and ttick properties to the parent axes which allows you to change the location of the ticks, however, there is unfortunately no tticklabel property that we can use to easily find and modify the theta tick marks.
Instead, we can plot your plot that you want the theta range to be 0 - 100 by first transforming your data to instead be 0 - 2*pi (as is expected by polar). Then after plotting both, we can use findall to locate all text objects, figure out which ones are the theta ticks, create a copy of them and modify one of the sets to appear to be 0 - 100.
% Your first plot is going to use the 0 - 2pi range for theta
theta1 = linspace(0, 2*pi, 1000);
rho1 = sin(theta1 * 5);
plot1 = polar(theta1, rho1);
hold on
% For your second plot, just transform your 0 - 100 range to be 0 - 360 instead
theta2 = 0:100;
rho2 = linspace(0, 1, numel(theta2));
modtheta2 = 2*pi * (theta2 ./ 100);
plot2 = polar(modtheta2, rho2);
% Now we need to modify all of the labels
% Find all of the original labels
labels = findall(gca, 'type', 'text');
% Figure out which ones are the radial labels. To do this we compute the distance
% from the center of the plot and find the most common distance
distances = cellfun(#(x)norm(x(1:2)), get(labels, 'Position'));
% Figure out the most common
[~, ~, b] = unique(round(distances * 100));
h = hist(b, 1:max(b));
labels = labels(b == find(h == max(h)));
% Make a copy of these labels (have to use arrayfun for 4.0.x compatibility)
blacklabels = arrayfun(#(L)copyobj(L, gca), labels);
% Shift these labels outward by 15%
arrayfun(#(x)set(x, 'Position', get(x, 'Position') * 1.15), blacklabels);
% Now set the other labels to red and change their values
set(labels, 'COlor', 'red')
for k = 1:numel(labels)
value = str2num(get(labels(k), 'String'))
% Convert the value to be between 0 and 100
newvalue = 100 * (value / 360);
set(labels(k), 'String', sprintf('%0.2f', newvalue))
end

How to compute the distance of a set points

I have a problem about computing the distance of points. Let see my definition. I have a finite set points:
S={a_i=(a_i1,a_i2) ∈ Ω, 1<=i<=k }
where Ω is image domain, i is index of pixel.
The distance function d is tuned by parameter sigma that allows adjustment according to the number of points to be fitted:
Let I:Ω->R given by
I= [200 219 226 228 228 240 243 245 245
212 222 229 233 241 247 248 252 252
220 226 234 239 247 250 250 255 253
225 231 244 248 249 248 247 253 250
233 238 251 252 254 249 242 242 235
243 250 255 246 250 244 230 216 200
252 255 250 231 225 211 187 166 153
250 249 234 213 192 164 129 111 114
236 226 195 168 138 119 93 84 91]
Now, I want to compute distance d with a given sigma=3, I want to compute the distance d that follows the above equation. Could you help me implement it by matlab code? Thank you in advance.
If I'm interpreting the equation right, you have k row/column coordinates. For each pair of row/column coordinates you have ai1,ai2, you wish to compute the term inside the brackets of the expression in your post. This results in k matrices, and you'll then have a matrix d such that it's the same size as your image and it computes the product of all of these matrices together.
However, for numerical stability, if you take the logarithmic sum, add up the terms, and then take the exponential of the result, you'll get the same thing and it's actually much quicker (tip of the hat goes to Nikos M. for the tip).
I'd like to note that x seems to be dealing with image coordinates and has nothing to do with the intensities of the image itself. This makes sense given from what I read from the paper. The paper seems to stress that this distance measure looks at spatial locality of pixel locations.
In terms of ease, the quickest way to get something running would be to have a for loop that accumulates all of the results together.
Something like this:
ai1 = [3, 5, 7]; %// Example row coordinates
ai2 = [6, 8, 9]; %// Example column coordinates
%// Image defined by you
I= [200 219 226 228 228 240 243 245 245
212 222 229 233 241 247 248 252 252
220 226 234 239 247 250 250 255 253
225 231 244 248 249 248 247 253 250
233 238 251 252 254 249 242 242 235
243 250 255 246 250 244 230 216 200
252 255 250 231 225 211 187 166 153
250 249 234 213 192 164 129 111 114
236 226 195 168 138 119 93 84 91];
sigma = 3; %// Defined by you
out = zeros(size(I)); %// Define output image
%// Define 2D grid of points
[x1,x2] = ndgrid(1:size(I,1), 1:size(I,2));
for idx = 1 : numel(ai1) %// Or numel(ai2) as it's the same size
%// Compute internal function
p = 1 - exp(-(x1 - ai1(idx)).^2 / (2*sigma^2)).*exp(-(x2 - ai2(idx)).^2 / (2*sigma^2));
%// Accumulate
out = out + log(p);
end
%// Take anti-log
out = exp(out);
Bear in mind that the above notation is with respect to 1-indexing as MATLAB starts indexing things at 1. Traditionally, image indexing starts at 0, so if you want to start at 0, simply offset ai1 and ai2 by 1, and also in the ndgrid call, subtract the values by 1.
So, modify here:
ai1 = [3, 5, 7] - 1; %// Example row coordinates
ai2 = [6, 8, 9] - 1; %// Example column coordinates
... and here:
%// Define 2D grid of points
[x1,x2] = ndgrid(1:size(I,1), 1:size(I,2));
x1 = x1 - 1; x2 = x2 - 1;
I'm assuming that the zero-indexing is what is desired. As such, with the above code, I get this as the output:
out =
Columns 1 through 8
1.6849 1.1763 0.7129 0.3843 0.2042 0.1387 0.1508 0.2215
1.5092 0.9580 0.4959 0.2025 0.0633 0.0242 0.0372 0.0784
1.4192 0.8515 0.4004 0.1353 0.0236 0 0.0089 0.0249
1.4240 0.8534 0.4032 0.1427 0.0348 0.0084 0.0057 0.0056
1.5171 0.9519 0.4857 0.2003 0.0682 0.0208 0.0047 0
1.6802 1.1341 0.6418 0.3054 0.1241 0.0424 0.0110 0.0029
1.8866 1.3832 0.8733 0.4735 0.2227 0.0903 0.0304 0.0073
2.1040 1.6730 1.1773 0.7265 0.3965 0.1940 0.0855 0.0342
2.3020 1.9666 1.5312 1.0730 0.6811 0.4020 0.2315 0.1446
Column 9
0.3566
0.1563
0.0594
0.0180
0.0056
0.0036
0
0.0199
0.1250
As you can see, the row and column coordinates of what we specified in ai1 and ai2 are zero in the distance matrix while the rest of the points reflect the rough distance from each of the anchor points. It honestly looks like a watered down version of the distance transform. The zero coefficients make perfect sense. Remember, we are taking the product of all of the k matrices together for the final output, and what's going to happen is that x1 and x2 will certainly have a ai1 / ai2 pair and so the subtraction in the exponent thus leads to a 1 output, and 1 - 1 = 0, and the product of anything (except infinity) with 0 is 0.... hence the reason why there's a 0 coefficient there!

MATLAB accessing conditional values and performing operation in single column

Just started MATLAB 2 days ago and I can't figure out a non-loop method (since I read they were slow/inefficient and MATLAB has better alternatives) to perform a simple task.
I have a matrix of 5 columns and 270 rows. What I want to do is:
if the value of an element in column 5 of matrix goodM is below 90, I want to take that element and and subtract it from 90.
So far I tried:
test = goodM(:,5) <= 90;
goodM(test) = 999;
It changes all goodM values within column 1 not 5 into 999, in addition this method doesn't allow me to perform operations on the elements below 90 in column 5. Any elegant solution to doing this?
edit:: goodM(:,5)(test) = 999; doesn't seem to work either so I have no idea to specify the target column.
I am assuming you are looking to operate on elements that have values below 90 as your text in the question reads, rather than 'below or equal to' as represented by '<=' as used in your code. So try this -
ind = find(goodM(:,5) < 90) %// Find indices in column 5 that have values less than 90
goodM(ind,5) = 90 - goodM(ind,5) %// Operate on those elements using indices obtained from previous step
Try this code:
b=90-a(a(:,5)<90,5);
For example:
a =
265 104 479 13 176
26 110 447 208 144
379 163 179 366 464
301 48 274 391 26
429 374 174 184 297
495 375 312 373 82
465 272 399 447 420
205 170 373 122 84
1 417 63 65 252
271 277 412 113 500
then,
b=90-a(a(:,5)<90,5);
b =
64
8
6

Comparing 2 different image

I am trying to compare multiple image using corr2 to see the similarity in correlation.
for i=1:2
first_img = imread(sprintf('%g.jpg',i));
first_size = size(first_img);
size_temp = size(first_size);
max_size = max(size_temp);
if max_size == 3
first_img = rgb2gray(first_img);
first_size = size(first_img);
end
for j=i+1:2
second_img = imread(sprintf('%g.jpg',j));
second_size = size(second_img);
size_temp = size(second_size);
max_size = max(size_temp);
if max_size == 3
second_img = rgb2gray(second_img);
second_size = size(second_img);
end
if i == j
continue;end
if first_size ~= second_size
continue;end
if first_size == second_size
correlation_fs = corr2(first_img,second_img);
if correlation_fs == 1
fprintf('%g is the same as %g\n',first_img,second_img);
end
end
end
end
now, the problem show up when the first image compared to the 3rd dummy image which is exactly the same as the first image.
219 is the same as 219
220 is the same as 220
221 is the same as 221
221 is the same as 222
224 is the same as 223
222 is the same as 221
221 is the same as 222
223 is the same as 224
218 is the same as 236
242 is the same as 232
217 is the same as 219
226 is the same as 228
220 is the same as 229
241 is the same as 251
254 is the same as 253
250 is the same as 247
253 is the same as 253
252 is the same as 248
237 is the same as 224
217 is the same as 218
225 is the same as 219
219 is the same as 223
219 is the same as 214
222 is the same as 237
I don't know why this is showing up, it should print that image 1 is the same as image 3, at least is what i want it to.
You are printing out the entire image matrices instead of the image number. Try:
fprintf('%g is the same as %g\n',i,j)
Think about what first_img is, it's a matrix of pixel intensities. So you're printing out all the pixel values.
fprintf('%g is the same as %g\n',first_img,second_img);
Here you are passing two images as arguments. You should have passed the image numbers instead.
fprintf('%g is the same as %g\n', i, j);

Matlab getting point coordinates

How can I get the coordinates at a specific point?
I want to get the X coordinate of the points with Y = 18.1 ; Y = 33; Y = 70
Those points need to lie on the function that I plot.
Sample Code
t = [0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180];
y = [0 5 9 19 25 32 46 65 79 90 100 115 123 141 153 159 160 171 181 185 193 200 205 211 215 220 223 222 225 224 228 231 231 228 235 234 231];
plot(t,y) , grid on
Unfortunately, you are trying to find the values of t associated with a y, and your function is not monotonic so we need to actually code up a mock linear interpolation. Note, there may be a better way, but I do not know of it right now. Try the following code where yVals are the values you want an associated t for, and possArray will include all values of t that may satisfy those conditions.
clc; close all; clear all;
t = [0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180];
y = [0 5 9 19 25 32 46 65 79 90 100 115 123 141 153 159 160 171 181 185 193 200 205 211 215 220 223 222 225 224 228 231 231 228 235 234 231];
plot(t,y)
grid on
hold on
yVals = [18.1,33,70,222.5,230];
possArray = cell(1,numel(yVals));
iter = 1;
for val = yVals;
poss = [];
possNum = 1;
for i = 1:numel(y)-1
if y(i) <= val && y(i+1) >= val
minDiff = val-y(i);
yDiff = y(i+1)-y(i);
percAlong = minDiff/yDiff;
poss(possNum) = (t(i+1)-t(i))*percAlong+t(i);
possNum = possNum+1;
end
end
possArray{iter} = poss;
iter = iter + 1;
end
colors = hsv(numel(yVals));
legendCell = cell(numel(yVals)+1,1);
legendCell{1} = 'Original Line';
for i = 1:numel(yVals)
plot(possArray{i},yVals(i)*ones(size(possArray{i})),...
'x','MarkerSize',10,'LineWidth',2,'Color',colors(i,:))
legendCell{i+1} = ['Values for Y = ' ,num2str(yVals(i))];
end
legend(legendCell)
hold off
As stated previously, this is linear interpolation, so if you need it to be more complicated that is on you, the concept should however be similar
UPDATE
Updated code above to be a little more clean, and added a plot indicating that multiple possibilities may arise for a single value, and that the code will return all possibilities.