I'm trying get a basic circular temperature contour graph in MATLAB.
Instead, I'm getting a straight line and doesn't resemble at all to
MATLAB's examples for contour maps. I want 4 circular zones
representing 90 degrees, 80 degrees, 70 degrees, and 60 degrees.
Here is my code:
long = [0 1 2 3; 4 5 6 7; 8 9 10 11; 12 13 14 15];
lat = [15 16 17 18; 19 20 21 22; 23 24 25 26; 27 28 29 30];
temp = [98 95 94 92; 85 82 81 80; 72 75 74 71; 65 62 61 69];
figure;
contour(long,lat,temp,4)
The problem is that you've only provided a line of data and not a matrix. You need to provide a temperature for each pair of long and lat. So if long and lat are both 1x15 then temp should be 15x15.
For example:
x = 1:3
y = 1:3
z = [1 2 1; 2 3 2; 1 2 1];
contour(x,y,z);
Related
Take a 4-D matrix A with s1=size(A,1), s2=size(A,2), s3=size(A,3), s4=size(A,4).
Consider
B=reshape(A, s1*s2*s3*s4,1)
For example,
s1=2;
s2=3;
s3=2;
s4=4;
A(:,:,1,1)=[1 2 3; 4 5 6];
A(:,:,1,2)=[7 8 9; 10 11 12];
A(:,:,1,3)=[13 14 15; 16 17 18];
A(:,:,1,4)=[19 20 21; 22 23 24];
A(:,:,2,1)=[25 26 27; 28 29 30];
A(:,:,2,2)=[31 32 33; 34 35 36];
A(:,:,2,3)=[37 38 39; 40 41 42];
A(:,:,2,4)=[43 44 45; 46 47 48];
B=reshape(A, s1*s2*s3*s4,1);
%B=[1;4;2;5;3;6;25;28;26;29;27;30;7;10;8;11;9;12;...];
Given coordinates (i,j,h,k), I would like your help to write a function that gives me the position of A(i,j,h,k) in B.
I know how to do that when A is a 3-D matrix. In that case,
position_in_B= i + ( j-1 + (h-1)*s2 ) * s1;
How can I extend this result to 4-D matrices?
Here you can use sub2ind , for example:
B(sub2ind(size(A),1,1,1,4))
or you can continue with the extension you wrote:
position_in_B= #(i,j,h,k) i + ( j-1 + ( h-1 + (k-1) *s3 ) *s2 ) * s1;
B(position_in_B(1,1,1,4))
I have a 500x500 matrix with values ranging from 1-100.
I need to look at 5 rows at a time and see if those 5 rows contain values that are greater than 75. I then need to get the index of the first column where the value is greater than 75 and the index of the last column where the value is greater than 75.
So far, I have the following:
i = 1;
while i < size(data,1)
if (i + 5) <= size(data,1)
if any(envNoClutterscansV(i:i + 5, 1:500) > 75)
% do something
end
end
i = i + 5;
end
The idea here is that I am looking at 5 rows at a time. For every 5 rows, I'm looking through all the columns to see if there are values that meet my criteria. So far, this doesn't find any values, even though I'm sure that my dataset contains the values. Additionally, I am not sure what to do from here.
I think the trouble might be that the result of any in the above code is a vector of 500 true and false values. You should sum them if you e=want to respond every time there are larger than 75 values:
if sum(any(envNoClutterscansV(i:i + 5, 1:500) > 75))
If you want to speed it up, you can avoid the loop and vectorize it, for example like this:
data = [
11 76 25 44 55 75;
11 75 95 44 85 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 44 55 0;
11 0 25 44 55 0;
11 90 25 44 55 88;
11 0 25 44 55 0;
91 0 25 44 55 80;
];
% Geting the number of rows
nRows=size(data,1);
% Retting a logical matrix with all the cells that are above the treshold
cellsOverTreshold=data>75;
% Getting a logical index to all the rows that contain values above
% treshold
matchingRows=any(cellsOverTreshold,2);
% In nexy line of code "reshape" rearange the data to put in columns the
% values associated to each goup of 5 rows
% So colum 1 have group one corresponding to data columns 1,2,3,4,5
% colum 2 have group two corresponding to data columns 6,7,8,9,10
% and so on
% Now we can get all the row groups that have velues above threshold
matchingRowGroups=find(any(reshape(matchingRows,5,[])));
% Now e put each row of on a cell array to be able to operate row-wise
cellRows = num2cell(cellsOverTreshold, 2);
% We now get the first and last column over the threshold for each row
firstColumOfRow = cellfun(#(x)find(x,1,'first'), cellRows,'UniformOutput',false);
lastColumOfRow = cellfun(#(x)find(x,1,'last'), cellRows,'UniformOutput',false);
% We replace the empty cells with NaNs so we can convert them to vectors
% without losing the indexing
firstColumOfRow(~matchingRows)={NaN};
lastColumOfRow(~matchingRows)={NaN};
% We rearrange the data as above and get the minimum of the first columns
% of each group, that is the first colum of the group above the threshold
firstColInGroup=nanmin(reshape([firstColumOfRow{:}]',5,[]));
% With the maximum of the last colums we get the last column of each group
lastColInGroup=nanmax(reshape([lastColumOfRow{:}]',5,[]));
% We finaly keep only the data of the groups with at that have at least one
% element above the threshold
firstColInGroup=firstColInGroup(matchingRowGroups);
lastColInGroup=lastColInGroup(matchingRowGroups);
In this way the variable "matchingRowGroups" have the indexes of each group of 5 rows that matchs. The variable "firstColInGroup" have the first column matching for each group and "lastColInGroup" the last one.
In addition to my previous answer, here is another option of vectorization, avoiding to transform data into cell arrays and avoiding using cellfun too, therefore, it is probably faster. Here it is:
data = [
11 76 25 44 55 75;
11 75 95 44 85 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 44 55 0;
11 0 25 44 55 0;
11 90 25 44 55 88;
11 0 25 44 55 0;
91 0 25 44 55 80;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 84 55 0;
11 0 25 44 55 0;
];
% Geting the number of rows
[nRows, nCols]=size(data);
% Retting a logical matrix with all the cells that are above the treshold
cellsOverTreshold=data>75;
% Getting a logical index to all the rows that contain values above
% treshold
matchingRows=any(cellsOverTreshold,2);
% In nexy line of code "reshape" rearange the data to put in columns the
% values associated to each goup of 5 rows
% So colum 1 have group one corresponding to data columns 1,2,3,4,5
% colum 2 have group two corresponding to data columns 6,7,8,9,10
% and so on
% Now we can get all the row groups that have velues above threshold
matchingRowGroups=find(any(reshape(matchingRows,5,[])))
%We find the rows and columns of all the first and last columns of each row
% that have values above threshold
[firstRow, firstCol]=find(cumsum(cumsum(cellsOverTreshold,2),2)==1);
[lastRow, lastCol]=find(cumsum(cumsum(cellsOverTreshold,2,'reverse'),2,'reverse')==1);
% Sort this data in vectors with one value per row, leaving NANs for rows
% with no element above threshold
firstColumOfRow=NaN(nRows,1);
lastColumOfRow=NaN(nRows,1);
firstColumOfRow(firstRow)=firstCol;
lastColumOfRow(lastRow)=lastCol;
% We rearrange the data as above and get the minimum of the first columns
% of each group, that is the first colum of the group above the threshold
firstColInGroup=nanmin(reshape(firstColumOfRow,5,[]));
% With the maximum of the last colums we get the last column of each group
lastColInGroup=nanmax(reshape(lastColumOfRow,5,[]));
% We finaly keep only the data of the groups with at that have at least one
% element above the threshold
firstColInGroup=firstColInGroup(matchingRowGroups)
lastColInGroup=lastColInGroup(matchingRowGroups)
This code looks 5 rows a time. Use find to locate the values > 75 and ind2sub to convert the indices returned by find to rows (ignored) and columns cols.
data = [
11 76 25 44 55 78;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 44 55 0;
11 0 25 44 55 0;
11 0 25 44 55 88;
11 0 25 44 55 0;
11 0 25 44 55 0;
];
for row = 1:5:size(data, 1)
fprintf('Row %d - %d\n', row, row+4);
indices = find(data(row:row+4,:) > 75);
if ~isempty(indices)
[~, cols] = ind2sub([5 size(data, 2)], indices);
col_min = min(cols);
col_max = max(cols);
fprintf('Column: %d and %d\n', col_min, col_max);
end
end
After thinking a bit more, here you have yet another simpler, faster and more compact solution. See my first solution for more datils on the naming of variables, but they are quite self explanatory
data = [
11 76 25 44 55 75;
11 75 95 44 85 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 44 55 0;
11 0 25 44 55 0;
11 90 25 44 55 88;
11 0 25 44 55 0;
91 0 25 44 55 80;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 75 25 44 55 75;
11 0 25 84 55 0;
11 0 25 44 55 0;
];
% Geting the number of rows and columns
[nRows, nCols]=size(data);
%We create arrays with rows and column numbers of each element
[colNum,rowNum]=meshgrid(1:nCols,1:nRows);
% Set NaN the column numbers that do not match the treshold
colNum(data<=75)=NaN;
% Get the group number of each element
groupNum=ceil(rowNum/5);
%The matching groups are those that have at least one non-NaN element
matchingRowGroups = accumarray(groupNum(:),colNum(:),[],#(x)any(~isnan(x)))
%We get the minimum of the column numbers matching thershold on each group
firstColumOfGroup = accumarray(groupNum(:),colNum(:),[],#nanmin)
%We get the maximum of the column numbers matching thershold on each group
lastColumOfGroup = accumarray(groupNum(:),colNum(:),[],#nanmax)
The only difference with the previous solutions is that matchingRowGroups is a logical index, and firstColumOfGroup and lastColumOfGroup have one entry per group, instead of entries only for groups with elements above the threshold. Groups with no entry above threshold have NaN values
I need to find the difference between positive and negative peaks where the difference is greater than +-3.
I am using findpeaks function in MATLAB to find the positive and negative peaks of the data.
In an example of my code:
[Ypos, Yposloc] = findpeaks(YT0);
[Yneg, Ynegloc] = findpeaks(YT0*-1);
Yneg = Yneg*-1;
Yposloc and Ynegloc return the locations of the positive and negative peaks in the data.
I want to concatenate Ypos and Yneg based on the order of the peaks.
For example, my peaks are
Ypos = [11 6 -10 -10 6 6 6 6 6 -5]
Yneg = [-12 -14 -11 -11 -11 5 5 5 -6]
Locations in YT0
Yposloc = [24 63 79 84 93 95 97 100 156]
Ynegloc = [11 51 78 81 85 94 96 99 154]
In this case, where both Yposloc and Ynegloc are 9x1, I can do the following;
nColumns = size(Yposs,2);
YTT0 = [Yneg, Ypos]';
YTT0 = reshape(YTT0(:),nColumns,[])';
YTT0 = diff(YTT0)
YT0Change = numel(YTT0(YTT0(:)>=3 | YTT0(:)<=-3));
Total changes that I am interested is 6
However, I need to concatenate Yneg and Ypos automatically, based on their locations. So I think I need to to do an if statement to figure out if my positive or negative peaks come first? Then, I am not sure how to tackle the problem of when Ypos and Yneg are different sizes.
I am running this script multiple times where data changes and the negative/positive peak order are constantly changing. Is there a simple way I can compare the peak locations or am I on the right track here?
I would check each minimum with both the previous and the next maxima. In order to do that you can first combine positive and negative peaks according to their order:
Y = zeros(1, max([Yposloc, Ynegloc]));
Yloc = zeros(size(Y));
Yloc(Yposloc) = Yposloc;
Yloc(Ynegloc) = Ynegloc;
Y(Yposloc) = Ypos; % I think you inserted one extra '6' in your code!
Y(Ynegloc) = Yneg;
Y = Y(Yloc ~= 0) % this is the combined signal
Yloc = Yloc(Yloc ~= 0) % this is the combined locations
% Y =
%
% -12 11 -14 6 -11 -10 -11 -10 -11 6 5 6 5 6 5 6 -6 -5
%
% Yloc =
%
% 11 24 51 63 78 79 81 84 85 93 94 95 96 97 99 100 154 156
And then calculate the differences:
diff(Y)
% ans =
%
% 23 -25 20 -17 1 -1 1 -1 17 -1 1 -1 1 -1 1 -12 1
If you want changes of at least 6 units:
num = sum(abs(diff(Y)) > 6)
% num =
%
% 6
Ypos = [11 6 -10 -10 6 6 6 6 -5];
Yneg = [-12 -14 -11 -11 -11 5 5 5 -6];
Yposloc = [24 63 79 84 93 95 97 100 156];
Ynegloc = [11 51 78 81 85 94 96 99 154];
TOTAL=[Yposloc Ynegloc;Ypos Yneg];
%creatin a vector with positions in row 1 and values in row 2
[~,position]=sort(TOTAL(1,:));
%resort this matrix so the values are in the orginial order
TOTAL_sorted=TOTAL(:,position);
%look at the changes of the values
changes=diff(TOTAL_sorted(2,:));
if changes(1)>0
disp('First value was a Minimum')
else
disp('First value was a MAximum')
end
%same structure at the TOTAL matrix
%abs(changes)>3 produces a logical vector that shows where the absolute values was bigger
%than 3, in my opinon its rather intresting where the end is then were the start is
% thats why i add +1
Important_changes=TOTAL_sorted(:,find(abs(changes)>3)+1);
plot(TOTAL_sorted(1,:),TOTAL_sorted(2,:))
hold on
plot(Important_changes(1,:),Important_changes(2,:),...
'Marker','o','MarkerSize',10, 'LineStyle','none');
hold off
I have a matrix of measured angles between M planes
0 52 77 79
52 0 10 14
77 10 0 3
79 14 3 0
I have a list of known angles between planes, which is an N-by-N matrix which I name rho. Here's is a subset of it (it's too large to display):
0 51 68 75 78 81 82
51 0 17 24 28 30 32
68 17 0 7 11 13 15
75 24 7 0 4 6 8
78 28 11 4 0 2 4
81 30 13 6 2 0 2
82 32 15 8 4 2 0
My mission is to find the set of M planes whose angles in rho are nearest to the measured angles.
For example, the measured angles for the planes shown above are relatively close to the known angles between planes 1, 2, 4 and 6.
Put differently, I need to find a set of points in a distance matrix (which uses cosine-related distances) which matches a set of distances I measured. This can also be thought of as matching a pattern to a mold.
In my problem, I have M=5 and N=415.
I really tried to get my head around it but have run out of time. So currently I'm using the simplest method: iterating over every possible combination of 3 planes but this is slow and currently written only for M=3. I then return a list of matching planes sorted by a matching score:
function [scores] = which_zones(rho, angles)
N = size(rho,1);
scores = zeros(N^3, 4);
index = 1;
for i=1:N-2
for j=(i+1):N-1
for k=(j+1):N
found_angles = [rho(i,j) rho(i,k) rho(j,k)];
score = sqrt(sum((found_angles-angles).^2));
scores(index,:)=[score i j k];
index = index + 1;
end
end;
end
scores=scores(1:(index-1),:); % was too lazy to pre-calculate #
scores=sortrows(scores, 1);
end
I have a feeling pdist2 might help but not sure how. I would appreciate any help in figuring this out.
There is http://www.mathworks.nl/help/matlab/ref/dsearchn.html for closest point search, but that requires same dimensionality. I think you have to bruteforce find it anyway because it's just a special problem.
Here's a way to bruteforce iterate over all unique combinations of the second matrix and calculate the score, after that you can find the one with the minimum score.
A=[ 0 52 77 79;
52 0 10 14;
77 10 0 3;
79 14 3 0];
B=[ 0 51 68 75 78 81 82;
51 0 17 24 28 30 32;
68 17 0 7 11 13 15;
75 24 7 0 4 6 8;
78 28 11 4 0 2 4;
81 30 13 6 2 0 2;
82 32 15 8 4 2 0];
M = size(A,1);
N = size(B,1);
% find all unique permutations of `1:M`
idx = nchoosek(1:N,M);
K = size(idx,1); % number of combinations = valid candidates for matching A
score = NaN(K,1);
idx_triu = triu(true(M,M),1);
Atriu = A(idx_triu);
for ii=1:K
partB = B(idx(ii,:),idx(ii,:));
partB_triu = partB(idx_triu);
score = norm(Atriu-partB_triu,2);
end
[~, best_match_idx] = min(score);
best_match = idx(best_match_idx,:);
The solution of your example actually is [1 2 3 4], so the upperleft part of B and not [1 2 4 6].
This would theoretically solve your problem, and I don't know how to make this algorithm any faster. But it will still be slow for large numbers. For example for your case of M=5 and N=415, there are 100 128 170 583 combinations of B which are a possible solution; just generating the selector indices is impossible in 32-bit because you can't address them all.
I think the real optimization here lies in cutting away some of the planes in the NxN matrix in a preceding filtering part.
Assume we have the following data:
H_T = [36 66 21 65 52 67 73; 31 23 19 33 36 39 42]
P = [40 38 39 40 35 32 37]
Using MATLAB 7.0, I want to create three new matrices that have the following properties:
The matrix H (the first part in matrix H_T) will be divided to 3 intervals:
Matrix 1: the 1st interval contains the H values between 20 to 40
Matrix 2: the 2nd interval contains the H values between 40 to 60
Matrix 3: the 3rd interval contains the H values between 60 to 80
The important thing is that the corresponding T and P will also be included in their new matrices meaning that H will control the new matrices depending on the specifications defined above.
So, the resultant matrices will be:
H_T_1 = [36 21; 31 19]
P_1 = [40 39]
H_T_2 = [52; 36]
P_2 = [35]
H_T_3 = [66 65 67 73; 23 33 39 42]
P_3 = [38 40 32 37]
Actually, this is a simple example and it is easy by looking to create the new matrices depending on the specifications, BUT in my values I have thousands of numbers which makes it very difficult to do that.
Here's a quick solution
[~,bins] = histc(H_T(1,:), [20 40 60 80]);
outHT = cell(3,1);
outP = cell(3,1);
for i=1:3
idx = (bins == i);
outHT{i} = H_T(:,idx);
outP{i} = P(idx);
end
then you access the matrices as:
>> outHT{3}
ans =
66 65 67 73
23 33 39 42
>> outP{3}
ans =
38 40 32 37