Errors converting lat and long values to sf coordinates - coordinates

I have a series of coordinates that I am trying to plot on simple maps. I have two columns containing latitude and longitude for each point, respectively. I am attempting to use the st_as_sf function to convert this data into sf points but I keep getting numerous errors, most recently
"Error in UseMethod("st_as_sf") :
no applicable method for 'st_as_sf' applied to an object of class "c('double', 'numeric')"
I have tried changing the class of the data to numeric, double, integer, etc. and I continue to get this error.
Below is an example of my data
point lat long
1 38.254 -76.712
2 38.123 -76.710
3 38.438 -76.699
4 38.254 -76.712
5 38.232 -76.733
st_as_sf(coords=c(lat, long), crs=4326)

You need to work on the arguments of sf::st_as_sf() function; in the first place must be your data object, most likely a data frame with columns named lat and long.
In the second place you specify coords, which should be a string vector of variable names, contained in your data object - so the names "lat" and "long" are expected enclosed in quotation marks (these are not R variables, but column names).
In the third place is expected a coordinate reference system to make sense of the coordinates provided in the second step; in case of WGS84 this will be 4326.
So consider this piece of code; it is formally correct, but places your points somewhere in Antarctica (should you flip the coordinates to long-lat the points would be placed in Washington, DC).
library(sf)
raw_pts <- data.frame(point = 1:5,
lat = c(38.254, 38.123, 38.438, 38.254, 38.232),
long = c(-76.712, -76.710, -76.699, -76.712, -76.733))
points <- st_as_sf(raw_pts, # first argument = data frame with coordinates
coords = c("lat", "long"), # name of columns, in quotation marks
crs = 4326) # coordinate reference system to make sense of the numbers
points
# Simple feature collection with 5 features and 1 field
# Geometry type: POINT
# Dimension: XY
# Bounding box: xmin: -76.733 ymin: 38.123 xmax: -76.699 ymax: 38.438
# Geodetic CRS: WGS 84
# point geometry
# 1 1 POINT (38.254 -76.712)
# 2 2 POINT (38.123 -76.71)
# 3 3 POINT (38.438 -76.699)
# 4 4 POINT (38.254 -76.712)
# 5 5 POINT (38.232 -76.733)

Related

How to obtain the x and y vectors for those whose state is set to i in MATLAB

I have a MATLAB function called nearInfectious2, which represents six people. It takes in parameters of an array of x coordinates, an array of y coordinates, different states relating to those coordinates "s" for susceptible, "i" for infectious and "r" for recovered and lastly a radius. I want to store an array or array(s) of the x and y coordinates for those people whose state is "i". This is what I have thus far, but it is also including the other coordinates which is not what I want. How can I get it to just return arrays with coordinates relating to those whose state is "i"? This is what I have thus far:
[x,y]=nearInfectious2([3,350,150,20,204,103],[92,9,200,5,350,34],["s","i","s","r","i","i"],20);
function [x,y] = nearInfectious2(x,y,states,radius)
for j=1:6
if states(j) == "i"
x(j)=x(j);
y(j)=y(j);
end
end
disp([x])
disp([y])
end
After I have the array of coordinates relating to the people who's states are "i", I want to calculate the distance (using the normal distance formula sqrt((x2 - x1)^2 + (y2 - y1)^2)) between any individuals whose state is "s", to those whose state is "i" to see if it less than radius apart. Any help is greatly appreciated.
Well, your problem is that your input variables are the same as output and also x(j)=x(j) means nothing. You are assigning a value of an array to the same place in the same array.
You should be creating a new array with only the values that match. A quick fix to your code could look like this:
function [x_out, y_out] = nearInfectious2(x_in, y_in, states, radius)
x_out = []
y_out = []
for j=1:length(states)
if states(j) == "i"
x_out(end + 1) = x_in(j); % append after the end of the array
y_out(end + 1) = y_in(j);
end
end
disp([x_out])
disp([y_out])
end

Extracting data from array (interpolation)

I need some advice regarding a problem I encountered in MATLAB:
I have 4 variables, I'm not sure what is the best methodology to go about doing this. I initially thought about just computing the GreatCircle distance from each grid point to the specified location and return the corresponding row/column index that has the minimum distance. But doing it this way, I'm not sure how I can compute the interpolation.
I tried reshaping the data into a vector data of 4 columns and running meshgrid to possibly utilize interp2. But I ended up with this error:
Requested 109620x109620 (44.8GB) array exceeds maximum array size preference
What could be the most efficient way to do this?
You are working on large arrays. If interp2 cannot handle it, work on a subarray instead:
% Create data
format shortG
[Latitude,Longitude] = meshgrid(1:12,1:12);
Altitude = floor(1000+sortrows(rand(12,12))*1000);
Temperature = 10+20*rand(12,12);
Lat = 2.1;
Lon = 11.8;
% Find closest match point
[~,i_Lat] = min(abs(Latitude(1,:)-Lat));
[~,i_Lon] = min(abs(Longitude(:,1)-Lon));
% Select subarrays around this point.
% Minimum size of these matrices depend on the type of interpolation you perform
ia1 = max(1,i_Lat-5);
ia2 = min(size(Latitude,1),i_Lat+5);
io1 = max(1,i_Lon-5);
io2 = min(size(Latitude,2),i_Lon+5);
subLatitude = Latitude(io1:io2,ia1:ia2);
subLongitude = Longitude(io1:io2,ia1:ia2);
subAltitude = Altitude(io1:io2,ia1:ia2);
subTemperature = Temperature(io1:io2,ia1:ia2);
% Interpolate on these small arrays, and evaluate at target (Lat, Lon) point
A_out = interp2(subLatitude, subLongitude, subAltitude, Lat, Lon)
T_out = interp2(subLatitude, subLongitude, subTemperature, Lat, Lon)

Detecting if values are within range of each other and taking a midpoint - MATLAB

Following on from: Detecting if any values are within a certain value of each other - MATLAB
I am currently using randi to generate a random number from which I then subtract and add a second number - generated using poissrnd:
for k=1:10
a = poissrnd(200,1);
b(k,1) = randi([1,20000]);
c(k,1:2) = [b(k,1)-a,b(k,1)+a];
end
c = sort(c);
c provides an output in this format:
823 1281
5260 5676
5372 5760
5379 5779
6808 7244
6869 7293
9203 9653
12197 12563
14411 14765
15302 15670
Which are essentially the boundaries +/- a around the point chosen in b.
I then want to set an additional variable (i.e. d = 2000) which is used as the threshold by which values are matched and then merged. The boundaries are taken into consideration for this - the output of the above value when d = 2000 would be:
1052
7456
13933
The boundaries 823-1281 are not within 2000 of any other value so the midpoint is taken - reflecting the original value. The next midpoint taken is between 5260 and 9653 because as you go along, each successive values is within 2000 of the one before it until 9653. The same logic is then applied to take the midpoint between 12197 and 15670.
Is there a quick and easy way to adapt the answer give in the linked question to deal with a 2 column format?
EDIT (in order to make it clearer):
The values held in c can be thought of as demarcating the boundaries of 'blocks' that sit on a line. Every single boundary is checked to see if anything lies within 2000 of it (the black lines).
As soon as any black line touches a red block, that entire red block is incorporated into the same merge block - in full. This is why the first midpoint value calculated is 1052 - nothing is touched by the two black lines emanating from the first two boundaries. However the next set of blocks all touch one another. This incorporates them all into the merge such that the midpoint is taken between 9653 and 5260 = 7456.
The block starting at 12197 is out of reach of it's preceding one so it remains separate. I've not shown all the blocks.
EDIT 2 #Esteban:
b =
849
1975
8336
9599
12057
12983
13193
13736
16887
18578
c =
662 1036
1764 2186
8148 8524
9386 9812
11843 12271
12809 13157
12995 13391
13543 13929
16687 17087
18361 18795
Your script then produces the result:
8980
12886
17741
When in fact it should be:
1424
8980
12886
17741
So it is just missing the first value - if no merge is occurring, the midpoint is just taken between the two values. Sometimes this seems to work - other times it doesn't.
For example here it works (when value is set to 1000 instead of 2000 as a test):
c =
2333 2789
5595 6023
6236 6664
10332 10754
11425 11865
12506 12926
12678 13114
15105 15517
15425 15797
19490 19874
result =
2561
6129
11723
15451
19682
See if this works for you -
th = 2000 %// threshold
%// Column arrays
col1 = c(:,1)
col2 = c(:,2)
%// Position of "group" shifts
grp_changes = diff([col2(1:end-1,:) col1(2:end,:)],[],2)>th
%// Start and stop positions of shifts
stops = [grp_changes ; 1]
starts = [1 ; stops(1:end-1)]
%// Finally the mean of shift positions, which is the desired output
out = floor(mean([col1(starts~=0) col2(stops~=0)],2))
Not 100% sure if it will work for all your samples... but this is the code I came up with which works with at least the data in your example:
value=2000;
indices = find(abs(c(2:end,1)-c(1:end-1,2))>value);
indices = vertcat(indices, length(c));
li = indices(1:end-1)+1;
ri = indices(2:end);
if li(1)==2
li=vertcat(1,li);
ri=vertcat(1,ri);
end
result = floor((c(ri,2)+c(li,1))/2)
it's not very clean and could surely be done in less lines, but it's easy to understand and it works, and since your c will be small, I dont see the need to further optimize this unless you will run it millions of time.

MATLAB XYZ to Grid

I have a tab separated XYZ file which contains 3 columns, e.g.
586231.8 2525785.4 15.11
586215.1 2525785.8 14.6
586164.7 2525941 14.58
586199.4 2525857.8 15.22
586219.8 2525731 14.6
586242.2 2525829.2 14.41
Columns 1 and 2 are the X and Y coordinates (in UTM meters) and column 3 is the associated Z value at the point X,Y; e.g. the elevation (z) at a point is given as z(x,y)
I can read in this file using dlmread() to get 3 variables in the workspace, e.g. X = 41322x1 double, but I would like to create a surface of size (m x n) using these variables. How would I go about this?
Following from the comments below, I tried using TriScatteredInterp (see commands below). I keep getting the result shown below (it appears to be getting some of my surface though):
Any ideas what is going on to cause this result? I think the problem lies with themeshgrid command, though I'm not sure where (or why). I am currently putting in the following set of commands to calculate the above figure (my X and Y columns are in meters, and I know my grid size is 8m, hence ti/tj going up in 8s):
F = TriScatteredInterp(x,y,z,'nearest');
ti = ((min(x)):8:(max(x)));
tj = ((min(y)):8:(max(y)));
[qx,qy] = meshgrid(ti,tj);
qz = F(qx,qy);
imagesc(qz) %produces the above figure^
I think you want the griddata function. See Interpolating Scattered Data in MATLAB help.
Griddata and tirscattteredinterp are extremely slow. Use the utm2deg function on the file exchange and from there a combination of both vec2mtx to make a regular grid and then imbedm to fit the data to the grid.
I.E.
for i = 1:length(X)
[Lat,Lon ] = utm2deg(Easting ,Northing ,Zone);
end
[Grid, R] = vec2mtx(Lat, Lon, gridsize);
Grid= imbedm(Lat, Lon,z, Grid, R);
Maybe you are looking for the function "ndgrid(x,y)" or "meshgrid(x,y)"

Matlab, graphing functions

I have a homework problem, I think I did it correctly but need to make sure 100%. Can anyone check for me, before I hand it in?
Thank you.
Question:
Plot the function given by f (x) = 2 sin(2x) − 3 cos(x/2) over the in-
terval [0, 2π] using steps of length .001 (How?). Use the commands max and min to estimate the maximum and minimum points. Include the maximum and minimum points as tick marks on the x-axis and the maximum and minimum values as tick marks on the y-axis.
My code:
x=linspace(0,2*pi,6280);
f=#(x)...
2.*sin(2.*x)-3.*cos(x./2);
%f = #(x)2.*sin(2.*x)-3.*cos(x./2)
g=#(x)...
-1*(2.*sin(2.*x)-3.*cos(x./2));
%g = #(x)-1*(2.*sin(2.*x)-3.*cos(x./2))
[x3,y5]=fminbnd(g,0,2*pi);
%x3 = 4.0968
%y3 = -3.2647
[x2,y4]=fminbnd(f,0,2*pi);
%x2 =2.1864
%y2 = -3.2647
y2=max(f(x));
y3=min(f(x));
plot(x,f(x));
set(gca,'XTick',[x2 x3]);
set(gca,'YTick',[y2 y3]);
(*after I paste this code here, it appeared not as nice as I had it in my program, don't know why)
To create a vector with certain step do
x=0:0.001:2*pi;
Why do you have g(x) function and why are you using fminbind? Use MIN and MAX, return index of those values and find related x values.
[ymin, minindex] = min(f(x));
xmin = x(minindex);
For general case if you have multiple min/max values, index will contain only the first occurrence. Instead you can do:
minindex = find(y==ymin);
Or for real values to avoid precision error:
minindex = find(abs(y-ymin)<=eps);
Also your last statement returns error Values must be monotonically increasing. To avoid it sort your tick values.
set(gca,'XTick',sort([xmin xmax]));
set(gca,'YTick',sort([ymin ymax]));