Xarray - how to regrid or sum up area variables for different grid resolutions? - netcdf

I have a dataset at a given resolution and its variable is an Area measure. When regridding to another resolution, the techniques are usually interpolation (bilinear, conservative, etc.), but this would only work for variables where the value is independent of the size of the grid (Think of temperature or precipitation). Because I'm using an Area variable, this would not work as if I want to upscale the resolution of the grid, the Area should be summed instead of interpolated. Therefore, I would like to upscale or group or sum my Area variable according to the change in coordinates (If I upscale 2x across lat and lon, the area would be multiplied by 4, as in the example below), but I do not know how to do it.
Example below:
What I currently have:
test_stack
Out[20]:
<xarray.DataArray 'Harvested_area' (time: 1, lat: 2, lon: 2)>
array([[[10, 10],
[10, 10]]])
Coordinates:
* time (time) int32 1981
* lat (lat) float64 6.246 6.237
* lon (lon) float64 -74.25 -74.24
What I would like to have:
sum_test_stack
Out[20]:
<xarray.DataArray 'Harvested_area' (time: 1, lat: 1, lon: 1)>
array([[[40]]])
Coordinates:
* time (time) int32 1981
* lat (lat) float64 6.246
* lon (lon) float64 -74.25
Thank you!

Try looking at xarray.DataArray.coarsen, using a simple sum as the function. https://docs.xarray.dev/en/stable/generated/xarray.DataArray.coarsen.html

Related

Getting limits on latitude and longitude

I have a service that looks for nearby locations(300m) from a user specified point.
I'm using the haversine formula to check if a location is near the point
https://en.wikipedia.org/wiki/Haversine_formula
My problem is that it's slow since it's checking against all of the points in my DB.
What I want to do is limit the initial query and apply the haversine formula to a list of points in a smaller bounded area
e.g.
results = (SELECT * FROM location WHERE location.latitude BETWEEN 14.223 AND 14.5 )
AND location.longitude BETWEEN 121.5 AND 122
haversine(results, user_point)
Is there a loose way of getting the bounds from a given point?
Or basically a dirty conversion of lat/long to meters?
If you can modify your database structure, there's one super-easy way to do it: instead of (or in addition to) storing latitude and longitude, convert your location coordinates into 3D space, with columns for x, y, and z in meters. Then you can just do
SELECT * FROM location
WHERE location.x BETWEEN center.x - 300 AND center.x + 300
AND location.y BETWEEN center.y - 300 AND center.y + 300
AND location.z BETWEEN center.z - 300 AND center.z + 300
That will trim down your list pretty well, and you can do the haversine calculation on the resulting set.
If you're stuck with using a database that has only longitude and latitude in it, you can still narrow down the search. It's easy for latitude: one degree of latitude due north or south always corresponds to 111 km of distance, as long as you ignore the complications that arise when you get close to the poles. That means a distance of 300 m is 0.0027... degrees of latitude, although you might as well be a bit conservative and use 0.003 or 0.004.
Longitude is a bit trickier because the conversion factor changes depending on how far north or south you are, but it's still not too complicated: you just multiply by the cosine of the latitude.
distance = cos(latitude) * 111.19... km/degree * delta_angle
At the equator, it's the same as with latitude: one degree change in longitude at the equator is 111 km. At 80 degrees north (or south), you multiply by a factor of cos(80 degrees) = 0.17..., with the result that 1 degree change in longitude is only 19.3 km. For your purposes, you could invert this and find the range of longitudes to select as 300 m / cos(latitude) / (111.19... km/degree) = (0.0027... degrees) / cos(latitude). That coefficient is the same quantity from the first paragraph; it's not a coincidence.
The tricky problems come up near the discontinuities of the coordinate system, for example when you get near the poles. You can see why when you start plugging in latitudes like 89.9996 degrees:
0.0027... degrees / cos(89.9996 degrees) = 386... degrees
Well, how can that be when there are only 360 degrees in a whole circle? This is an indicator that you've gotten to the point where your 300 m radius extends all the way around the pole and comes back to include your starting location, in a manner of speaking. At that point, you might as well just search all points in your database close enough to the pole. Of course you should really start doing this at 89.999 degrees or so, because that's where the 600 m diameter of the region you're searching just about encircles the pole completely.
There's another issue at (well, near) the International Date Line, or more precisely the "antimeridian", having to do with the jump from -180 to +180 degrees of longitude. A point at +179.9999 degrees and one at -179.9999 degrees, both on the equator, will have very different coordinates even though they are geographically just a few meters apart. Since you're just doing this as a preliminary filter for a more detailed search, it's probably easiest to just pass through every point within 0.006 degrees (that's roughly the diameter of a 300 m-radius circle) of the antimeridian, and then the haversine calculation will determine whether the points are actually close.
To sum up, you can use the bounds on latitude and longitude I mentioned above and just add special cases for the poles and the antimeridian. In some kind of pseudo-SQL/code hybrid:
IF abs(center.latitude) > 89.999
SELECT * FROM location WHERE abs(location.latitude - center.latitude) < 0.003
ELSE
IF abs(center.longitude) > 179.997
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND 180 - abs(location.longitude) < (0.006 / cos(center.latitude))
ELSE
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND abs(location.longitude - center.longitude) < (0.003 / cos(center.latitude))
ENDIF
ENDIF
If you want a pithy statement at the expense of having to test potentially twice as many points, you can only compare the absolute values of longitude:
SELECT * FROM location
WHERE abs(location.latitude - center.latitude) < 0.003
AND abs(abs(location.longitude) - abs(center.longitude)) <= min(0.003 / cos(center.latitude), 180)
Approximating the earth with a sphere, the distance between two consecutive latitudes can be calculated by
dPerLat = pi * r / 180°,
where r is the radius of the earth. This will be about 111 km.
So, if your reference point is (lat, long) and your search radius is d then you want to search for latitudes in the range
lat* \in [lat - d / dPerLat, lat + d / dPerLat]
Then, for a given latitude, the distance of consecutive longitudes is:
dPerLong = pi * r * cos(lat) / 180°
Again, the range of longitudes to search is +- d / dPerLong. You should use the lat value that gives you a conservative (maximal) range, i.e. the lat value with the highest absolute value.
Be careful at the poles.

Trying to find lat lon given original lat lon + 3 meters

I have this problem I have to solve.
I am given a coordinate lat/lon, and I need to find a random point within 3 meters of this original point. Approximations are good, but all I could find was this https://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters that has a 10 meter error. Thank you.
Not sure what "find" and "random" mean in this question.
The earth is about 10 million meters from equator to either pole (that's actually how they defined the size of the meter, at first; it's been modified slightly since). The width of latitude lines doesn't vary, so one meter north or south is always is one ten-millionth of 90 degrees, or 9e-6 degrees, so just multiply that by the north-south displacement in meters of your desired point from the initial point and you'll get the number to add to the initial point in degrees: delta_lat = y_meters * 9e-6.
The width of longitude lines does vary, but it works out as simply east-west displacement in meters * 9e-6 = delta_lon * cos(lat), which means you can use the distance from your initial point to figure the east-west difference in degrees: delta_lon = x_meters * 9e-6/cos(lat).
You'll have to be careful with that last part around the poles, because cos(lat) will approach zero. Navigational systems use quaternions to do these things because they don't have singularities in spherical coordinates.

Expand polygon envelop to square using decimal degrees(wgs 84)

I working in wgs64 gis.
I have the coordinates of polygon given by decimal degrees.
I trying to expand the polygon envelop from a rectangle to a square.
I understand that a rectangle of one degree of latitude and longitude on the sphere has not the same length in km unless it is situated on the equator.
But I don't understand the math behind how to fix my envelop.
I am doing this:
Envelope contextEnvelope = CurrElement.Envelope;
double Max = Math.Max(contextEnvelope.Width, contextEnvelope.Height);
contextEnvelope.Expand((Max * 15 - contextEnvelope.Width) / 2, (Max * 15 - contextEnvelope.Height) / 2);

Calculating angle from latitude and longitude

I have a set of latitudes and longitudes , so this is the data for an animal as it moves in time. what i want to do is to calculate turning angle, that is by what angle it turns between every movement. so say i have point 1, point 2 and point 3 with latitude and longitude value corresponding to each point(animal moves from point 1 to point 2 to point 3 and so on) and i want to calculate the angle between these 3 points, point 2 being the middle point. what should i do? my OS is windows and i am using R for analysis.
so here is my sample data:
longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863
they are in decimal degrees
Using the function trackAzimuth in maptools:
library(maptools)
trackAngle <- function(xy) {
angles <- abs(c(trackAzimuth(xy), 0) -
c(0, rev(trackAzimuth(xy[nrow(xy):1, ]))))
angles <- ifelse(angles > 180, 360 - angles, angles)
angles[is.na(angles)] <- 180
angles[-c(1, length(angles))]
}
The trackAzimuth function is a simple loop wrapper around gzAzimuth. See ?gzAzimuth for references on calculating directions on the sphere.
Using your data:
x <- read.table(text = "longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863", header = TRUE)
trackAngle(as.matrix(x))
[1] 10.12946 111.17211 135.88514 97.73801 89.74684
EDIT: I had to remove first/last angles from the function, something I was doing after the fact with this function elsewhere. Should be right now. :)
Also, the packages adehabitatLT and argosfilter contain functions to calculate track directions and angles.
Your data points vary over only a small range. We can look at one small patch of Earth's surface and pretend it's flat, two dimensional. You have to figure out the scale of how many km, meters, miles, whatever your favorite unit is, corresponds to one degree of latitude, and for one degree of longitude. The latter depends on latitude - it'll be the same as the scale for latitude when near the equator, but if you are standing within arm's length of the north pole, one step will take you through fifty degrees. Set up x,y coordinates where x=0 is at longitude 36.88000, and y=0 is latitude 0.29000.
So, now you have a series of (x,y) points. Take the differences from each point to the next: P2-P1, P3-P2, etc. These could be called "displacement vectors" but other terms may be used in other fields than where i'm from. Call them V1, V2, etc. Use dot products and norms: dot(V1,V2) = magnitude(V1)*magnitude(V2)*cos(a) where a is the angle by which V2 deviates from the direction of V1. Repeat for V3 and V2, and so on.
R has all the tools to do this, but I don't know enough syntax of R to give examples.

Maximum length of a decimal latitude/longitude Degree?

What is the maximum length (in kilometers or miles - but please specify) that one degree of latitude and longitude can have in the Earth surface?
I'm not sure if I'm being clear enough, let me rephrase that. The Earth is not a perfect circle, as we all know, and a change of 1.0 in the latitude / longitude on the equator (or in Ecuador) can mean one distance while the same change at the poles can mean another completely different distance.
I'm trying to shrink down the number of results returned by the database (in this case MySQL) so that I can calculate the distances between several points using the Great Circle formula. Instead of selecting all points and then calculating them individually I wish to select coordinates that are inside the latitude / longitude boundaries, e.g.:
SELECT * FROM poi
WHERE latitude >= 75 AND latitude <= 80
AND longitude >= 75 AND longitude <= 80;
PS: It's late and I feel that my English didn't came up as I expected, if there is something that you are unable to understand please say so and I'll fix/improve it as needed, thanks.
The length of a degree of latitude varies little, between about 110.6 km at the equator to about 111.7 near the poles. If the earth were a perfect sphere, it would be constant. For purposes like getting a list of points within say 10 km of a known (lat, lon), assuming a constant 111 km should be OK.
However it's quite a different story with longitude. It ranges from about 111.3 km at the equator, 55.8 km at 60 degrees latitude, 1.9 km at 89 degrees latitude to zero at the pole.
You asked the wrong question; you need to know the MINIMUM length to ensure that your query doesn't reject valid candidates, and unfortunately the minimum length for longitude is ZERO!
Let's say you take other folk's advice to use a constant of about 111 km for both latitude and longitude. For a 10 km query, you would use a margin of 10 / 111 = 0.09009 degrees of latitude or longitude. This is OK at the equator. However at latitude 60 (about where Stockholm is, for example) travelling east by 0.09 degrees of longitude gets you only about 5 km. In this case you are incorrectly rejecting about half of the valid answers!
Fortunately the calculations to get a better longitude bound (one that depends on the latitude of the known point) is very simple -- see this SO answer, and the article by Jan Matuschek that it references.
Originally, the definition of a nautical mile was the length of one minute of longitude on the equator. So, there were 360 * 60 = 21,600 nautical miles around the equator. Similarly, the original definition of a kilometer was that 10,000 km = length from pole to equator. Consequently, assuming a spherical earth, there would be:
40,000 ÷ 21,600 = 1.852 km per minute
1.852 × 60 = 111.11 km per degree
Allowing for a spheroidal earth instead of a spherical one will slightly adjust the factor, but not by all that much. You could be pretty confident the factor is less than 1.9 km per minute or 114 km per degree.
If you can use MySQL spatial extensions: http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html, you can use its operators and functions both to filter the points and calculate distances. See http://dev.mysql.com/doc/refman/5.0/en/functions-that-test-spatial-relationships-between-geometries.html, specifically the functions contains() and distance().
The reference ellipsoid used for the earth is the WGS84 system, meaning
that the earth radius for the equator has the length of
6 378 137 m or 3963.19 miles
The maximum length of longitude is reached at the equator and is approximately (upper bound)
111.3195 km or
69.1708 miles
The maximum length of one degree latitude is reached between the equator and 1°. It is almost exactly equal to the maximum length of longitude; a first approximation shows that the difference is less than 4.2 meters yielding
111.3153 km or
69.1682 miles

Resources