Setting a matrix to one on a list of incomplete rectangular grid points - matlab

I have a set of data in a text file which shows coordinates of a rectangular grid in size of 81x61. each row shows longitude and latitude of a grid point. Longitudes change from 50.00 to 80.00 (61 Values), and Latitudes change from 30.00 to 70.00 (81 Values) in an order like this:
50.00 30.00
51.50 30.00
52.00 30.00
.
.
.
79.50 30.00
80.00 30.00
50.00 31.00
50.50 31.00
51.00 31.00
.
.
.
79.00 70.00
79.50 70.00
80.00 70.00
I also have another text file consists of some random coordinates which are from the rectangular grid mentioned above.
I want to create a matrix of size 81x61 with elements of 0 and 1 in a way that 1s correspond to coordinates from second text file.
How can I write the code which does that in Matlab?
Example of what I need in a small scale:
Text File:
1 1
1 2
1 3
.
.
.
4 3
4 4
4 5
Corresponding Rectangular Grid of the above text file:
1,1 1,2 1,3 1,4 1,5
2,1 2,2 2,3 2,4 2,5
3,1 3,2 3,3 3,4 3,5
4,1 4,2 4,3 4,4 4,5
2nd Text File:
1 1
1 3
2 4
2 5
3 4
4 1
4 5
Corresponding Matrix of the above text file:
1 0 1 0 0
0 0 0 1 1
0 0 0 1 0
1 0 0 0 1

I myself found a way;
Assumptions: The minimum value among longitude values is 50.00 & the minimum value among latitude values is 30.00
%// First column of the files is Longitude and the second column is Latitude
fr = fopen('second_file.txt','r');
lon = textscan(fr,'%f %*[^\n]');
lon = lon{:};
fclose(fr);
fr = fopen('second_file.txt','r');
lat = textscan(fr,'%*f %f %*[^\n]');
lat = lat{:};
fclose(fr);
%// We know that the overall size of the target matrix is 81x61
overall = zeros(81,61);
%// We assume that the total number of lines in the second file is 1000 (don't know if there is a built-in command to determine that!)
for k = 1:1000
i = int16(( lat(k) - 30.00 ) / 0.5 + 1);
j = int16(( lon(k) - 50.00 ) / 0.5 + 1);
overall(i,j) = 1;
end

I want to create a matrix of size 81x61 with elements of 0 and 1 in a
way that 1s correspond to coordinates from second text file.
That's the relevant information in the question. The answer is the Matlab function sub2ind(documentation). It converts a list of x, y coordinates to a list of array indices which you can then conveniently set to one.
Suppose you have read the content of the second file in a Nx2 matrix called second_file and the size of the result matrix you have given in variable matrix_size (81x61). You then do:
x = second_file(:, 1);
y = second_file(:, 2);
result = zeros(matrix_size);
index = sub2ind(matrix_size, x, y);
result(index) = 1;

I am assuming the the minimum and maximum values in your first file in respective columns are the ranges of latitude and longitude. Also, in both the files the first column is Longitude values.
%// calculating the min and max of latitude and longitude
id1 = fopen('first_file.txt');
A = fscanf(id1,'%f %f',[2 Inf]);
long_min = min(A(1,:));
long_max = max(A(1,:));
lat_min = min(A(2,:));
lat_max = max(A(2,:));
%// calculating output matrix size
no_row = (lat_max-lat_min)*2+1;
no_col = (long_max-long_min)*2+1;
output = zeros(no_row,no_col);
id2 = fopen('second_file.txt');
A = fscanf(id2,'%f %f',[2 Inf]);
% // converting the values into corresponding indices
A(1,:) = A(1,:) - long_min;
A(2,:) = A(2,:) - lat_min;
A = A*2 +1;
linear_ind = sub2ind([no_row no_col],A(2,:),A(1,:));
output(linear_ind) = 1;
2nd approach
I am assuming that in your second text file first column entries are latitude and second column entries are longitude. You will have to hard code the following variables:
long_min : the minimum value among longitude values
lat_min : the minimum value among latitude values
long_max : maximum value among longitude values
lat_max : maximum value among latitude values
And here is the code (only considering the second text file)
no_row = (lat_max-lat_min)*2+1;
no_col = (long_max-long_min)*2+1;
output = zeros(no_row,no_col);
id2 = fopen('second_file.txt');
A = fscanf(id2,'%f %f',[2 Inf]);
% // converting the values into corresponding indices
A(1,:) = A(1,:) - long_min;
A(2,:) = A(2,:) - lat_min;
A = A*2 +1;
linear_ind = sub2ind([no_row no_col],A(2,:),A(1,:));
output(linear_ind) = 1;

Related

How do I compare elements of one array to a column of a matrix, then shorten the matrix correspondingly?

I have a matrix 'Z' sized 100000x2 and imported as an Excel file using readmatrix. I have a created array 'Time' (Time = [-200:0.1:300]'). I would like to compare all values in column 1 of 'Z' to 'Time' and eliminate all values of column 1 of 'Z' that do not equal a value of 'Time', thus shortening my 'Z' matrix to match my desired time values. Column 2 are pressure traces, so this would give me my desired time values and the corresponding pressure trace.
This sort of thing can be done without loops:
x = [1,2,3,4,1,1,2,3,4];
x = [x', (x+1)'] % this is your 'Z' data from the excel file (toy example here)
x =
1 2
2 3
3 4
4 5
1 2
1 2
2 3
3 4
4 5
y = [1,2]; % this is your row of times you want eliminated
z = x(:,1)==y % create a matrix logical arrays indicating the matches in the first column
z =
9×2 logical array
1 0
0 1
0 0
0 0
1 0
1 0
0 1
0 0
0 0
z = z(:,1)+z(:,2); % there is probably another summing technique that is better for your case
b = [x(z~=1,1), x(z~=1,2)] % use matrix operations to extract the desired rows
b =
3 4
4 5
3 4
4 5
All the entries of x where the first column did not equal 1 or 2 are now gone.
x = ismember(Z(:,1),Time); % logical indexes of the rows you want to keep
Z(~x,:) = []; % get rid of the other rows
Or instead of shortening Z you could create a new array to use downstream in your code:
x = ismember(Z(:,1),Time); % logical indexes of the rows you want to keep
Znew = Z(x,:); % the subset you want
You have to loop over all rows, use a nested if statement to check the item, and delete the row if it doesn't match.
Syntax for loops:
for n = 1:100000:
//(operation)//
end
Syntax for if statements:
if x == y
//(operation)//
Syntax for deleting a row: Z(rownum,:) = [];

convert unknown vector location into logical form of N

Let say i have a location of the vector=[3; 4 ;10]. I want to convert the vector into logical form of 20 row where row 3,4 and 10 equal to 1 and the rest is zero.
i put the argument like this
N=20;
LOC=[3;4;10]; %location of the original point
LOGIC= % 20 logical rows where only row 3,4 and 10 equal to 1
What will be the function of LOGIC?
iwant = zeros(20,1) ;
loc = [3 4 10] ;
iwant(loc) = 1 ;
iwant = logical(iwant) ;

How to compare columns of a binary matrix and compare elements in matlab?

i have [sentences*words] matrix as shown below
out = 0 1 1 0 1
1 1 0 0 1
1 0 1 1 0
0 0 0 1 0
i want to process this matrix in a way that should tell W1 & W2 in "sentence number 2" and "sentence number 4" occurs with same value i.e 1 1 and 0 0.the output should be as follows:
output{1,2}= 2 4
output{1,2} tells word number 1 and 2 occurs in sentence number 2 and 4 with same values.
after comparing W1 & W2 next candidate should be W1 & W3 which occurs with same value in sentence 3 & sentence 4
output{1,3}= 3 4
and so on till every nth word is compared with every other words and saved.
This would be one vectorized approach -
%// Get number of columns in input array for later usage
N = size(out,2);
%// Get indices for pairwise combinations between columns of input array
[idx2,idx1] = find(bsxfun(#gt,[1:N]',[1:N])); %//'
%// Get indices for matches between out1 and out2. The row indices would
%// represent the occurance values for the final output and columns for the
%// indices of the final output.
[R,C] = find(out(:,idx1) == out(:,idx2))
%// Form cells off each unique C (these will be final output values)
output_vals = accumarray(C(:),R(:),[],#(x) {x})
%// Setup output cell array
output = cell(N,N)
%// Indices for places in output cell array where occurance values are to be put
all_idx = sub2ind(size(output),idx1,idx2)
%// Finally store the output values at appropriate indices
output(all_idx(1:max(C))) = output_vals
You can get a logical matrix of size #words-by-#words-by-#sentences easily using bsxfun:
coc = bsxfun( #eq, permute( out, [3 2 1]), permute( out, [2 3 1] ) );
this logical array is occ( wi, wj, si ) is true iff word wi and word wj occur in sentence si with the same value.
To get the output cell array from coc you need
nw = size( out, 2 ); %// number of words
output = cell(nw,nw);
for wi = 1:(nw-1)
for wj = (wi+1):nw
output{wi,wj} = find( coc(wi,wj,:) );
output{wj,wi} = output{wi,wj}; %// you can force it to be symmetric if you want
end
end

Sort Coordinates Points in Matlab

What I want to do is to sort these coordinates points:
Measured coordinates (x,y)= (2,2),(2,3),(1,2),(1,3),(2,1),(1,1),(3,2),(3,3),(3 ,1)
I need to get sequences or trajectories of this points to follow them by iteration.
data = [2,2 ; 2,3 ; 1,2 ; 1,3 ; 2,1 ; 1,1 ; 3,2 ; 3,3 ; 3 ,1]
% corresponding sort-value, pick one out or make one up yourself:
sortval = data(:,1); % the x-value
sortval = data(:,2); % y-value
sortval = (data(:,1)-x0).^2 + (data(:,2)-y0).^2; % distance form point (xo,y0)
sortval = ...
[~,sortorder] = sort(sortval);
sorted_data = data(sortorder,:);
But from you comment, I understand you actually need something to reconstruct a path and iteratively find the closest neighbour of the last found point (of the reconstructed path so far).
The following is how I would solve this problem (using pdist2 for calculating the distances between all the points for easiness):
data = [2,2 ; 2,3 ; 1,2 ; 1,3 ; 2,1 ; 1,1 ; 3,2 ; 3,3 ; 3 ,1];
dist = pdist2(data,data);
N = size(data,1);
result = NaN(1,N);
result(1) = 1; % first point is first row in data matrix
for ii=2:N
dist(:,result(ii-1)) = Inf;
[~, closest_idx] = min(dist(result(ii-1),:));
result(ii) = closest_idx;
end
which results in:
result =
1 2 4 3 6 5 9 7 8
being the indices to consecutive points on the curve. Here's a plot of this result:
As #mathematician1975 already mentioned, there can be equal distances to a point. This is solved here by using min which just finds the first occurrence of the minimum in an array. This means that if you order your input data differently, you can get different results of course, this is inherent to the equal-distance issue.
2nd remark: I don't know how this will behave when using large input data matrices, probably a bit slow because of the loop, which you can't avoid. I still see room for improvement, but that's up to you ;)
Create a matrix from your points so that you have something like
A = [2 2 1 1 2 1 3 3 3;
2 3 2 3 1 1 2 3 1]';
then try
B = sortrows(A,1);
to get a matrix with rows that are your points ordered by xvalue or
B = sortrows(A,2)
to get a matrix with rows that are your points ordered by their 'y' value. If your points are ordered with respect to some other ordering parameter (such as time) then sorting will not work unless you remember the order that they were created in.

Append data from multiple files to matlab array

Hello i need you help to append all the data i read from many files into a matrix. I have made the following script
path='C:\Users\Kostas\Documents\MATLAB\';
filefolder=strcat(path,'MSL*.txt');
files=dir(filefolder);
k=0;
for i=1:length(files)
filename=strcat(path,files(i).name);
%load the filename and create vectors of height (Z),
%lat and lon
newData=importdata(filename,'\t', 1);
vars = fieldnames(newData);
for j = 1:length(vars)
assignin('base', vars{j}, newData.(vars{j}));
end
timeas=data(:,1);
lat=data(:,2);
lon=data(:,3);
Z=data(:,4);
% daten=(timeas/24)+doy;
k=k+1;
%append data to matrix Teff_series
Teff_series(k,:)= [timeas lat lon Z];
end
the error message i get when i run this script is
??? Subscripted assignment dimension mismatch.
Error in ==> te at 31
Teff_series(k,:)= [lat lon Z];
Thanks in advance
Let me give an example:
%# get the list of files
fpath = 'C:\Users\Amro\Desktop\';
files = dir( fullfile(fpath,'file*.dat') );
files = strcat(fpath,{files.name}');
%# read data from all files and store in cell array
Teff_series = cell(numel(files),1);
for i=1:numel(files)
newData = importdata(files{i}, '\t', 1);
Teff_series{i} = newData.data;
end
%# combine all into a matrix
data = vertcat(Teff_series{:});
colNames = newData.colheaders;
%# extract columns as vectors
t = data(:,1);
lat = data(:,2);
lon = data(:,3);
Z = data(:,4);
If I use these sample data files:
file1.dat
t lat lon Z
1 2 3 4
2 3 4 5
4 5 6 6
file2.dat
t lat lon Z
4 5 6 6
2 3 4 5
1 2 3 4
I get the following results:
>> colNames
colNames =
't' 'lat' 'lon' 'Z'
>> data
data =
1 2 3 4
2 3 4 5
4 5 6 6
40 50 60 60
20 30 40 50
10 20 30 40
The error indicates that the left hand side of the equal expression - in this case:
Teff_series(k, :)
is of a different size than the right hand side:
[lat lon Z]
One way to debug this issue is execute the command:
dbstop if all error
and then re-run your script. It will stop the debugger at the point where the error is thrown and then you can figure out the difference in sizes.
Hope this helps.