how to plot a node on osmnx with known latitude and longtitude - networkx

is there anyone know what is the relationship between ['x'], ['y'] and ['lon'] and ['lat']? If I know a node's ['lon'] and ['lat'], how I can plot this node on the street map?
I can use the G.node[22258] find the detail information of a node, like
{
'x':319101.513
'y': 4427916
'osmid':
'ref':
'lon':'-81.11861'
'lat':'39.982066'
}
But I would like to plot a node on the map. I know the latitude and longtitude of this node, but it seems I need to know the 'x' and 'y'.

You can use ox.get_nearest_node to get the node from lat/long.
Use ox.get_nearest_node(G, (39.982066, -81.11861)) to get a nearest node
Use ox.plot_graph_route(G, [ox.get_nearest_node(G, (39.982066, -81.11861))]) to plot the node on map

As far as my knowledge goes, x-y are projected coordinates while lat-long is geographic coordinates expressed in decimal degrees. The projected coordinates are dependent on the projection itself which varies from place to place. What is needed here, I believe, is a transformation of the lat long into the desired projected coordinate system.
Here is a piece of code that does this transformation (from WGS 84 to Spherical Mercator).
While these do not reveal your x and y, I am sure this is the sort of calculation one needs to apply to get their desired result. You may try out other projections relevant to, say the US. For example, I transform to epsg 3112 for Australia. When I do that, I can directly apply euclidian geometry to obtain distances in metres.
Links: https://spatialreference.org/ref/epsg/wgs-84/, https://epsg.io/3857
from pyproj import Proj, transform
inProj = Proj(init='epsg:4326')
outProj = Proj(init='epsg:3857')
x1,y1 = -81.11861,39.982066
x2,y2 = transform(inProj,outProj,x1,y1)
print (x2,y2)
Output:
-9030082.35905815 4863336.501637128

Related

Extract constrained polygon using OSMnx

I'm playing around with OSMnx package in order to solve the following task:
- there is a point X on the map defined by latitude and longitude
- we need to detect a polygon that contains that point X and is constrained by the neighboring roads
- so basically the point X is inside the polygon and the neighboring roads will be borders of that polygon.
So far I've managed only to plot the visualization of the graph on the map and find the closest edge/node to point X.
In the attached image I've highlighted the area I want to extract in red.
As you are trying to find a polygon containing your point, you first need to generate polygons out of multilinestring geometry. As you did not provide your data I am downloading a sample from OSM using OSMnx.
import osmnx as ox
import geopandas as gpd
import shapely
point = (40.742623, -73.977857)
streets_graph = ox.graph_from_point(point, distance=500, network_type='drive')
streets_graph = ox.project_graph(streets_graph)
I have reprojected it as it is way more convenient than working with degrees, especially if you want to measure anything.
You then have to convert OSMnx graph to geopandas GeoDataFrame.
streets = ox.save_load.graph_to_gdfs(streets_graph, nodes=False, edges=True,
node_geometry=False, fill_edge_geometry=True)
To get some point I can work with, I'll just use the one in the centre of this geodataframe.
point = streets.unary_union.centroid
This is what it looks like.
Next you need to get polygons of your blocks defined by streets, using shapely.ops.polygonize as I suggested in the comment above and store them as GeoSeries.
polygons = shapely.ops.polygonize(streets.geometry)
polygons = gpd.GeoSeries(polygons)
The only thing you have to do next is to find which polygon contains your point.
target = polygons.loc[polygons.contains(point)]
Plotting it again:
ax = target.plot()
gpd.GeoSeries([point]).plot(ax=ax, color='r')
If you want to know which streets are forming the boundary of this polygon, just intersect it with the original network. I am filtering for MultiLineString to exclude streets which intersects the polygon only in one point.
target_streets = streets.loc[streets.intersection(target.iloc[0]).type == 'MultiLineString']
This is how the result of that looks like.
ax = target_streets2.plot()
gpd.GeoSeries([point]).plot(ax=ax, color='r')
Hope it helps.

Use $within with a buffered MondoDB Linestring

I need to evaluate the proximity of a Point to a LineString using MongoDB.
Because the $near operator can only compare a Point to another Point, I need to generate a polygon out of the LineString, so I can use the $within operator. The distance between the LineString and the edges of the polygon should represent the radius I want to search in, such as represented in red below:
What might be a useful algorithm in order to accomplish this?
I think much easier would be to write your own function
To find (perpendicular) distance between point and line and then creating thickness of poly-line by polygon means.
Where:
P0,P1 are line endpoints
P is point
d is distance between them
Line is defined as: p(t)=P0+(P1-P0)*t where t=<0.0,1.0>
So the function should do this:
create perpendicular line
q(t)=P+DQ*u where u=(-inf,+inf)
DQ is perpendicular vector to (P1-P0)
In 2D you can obtain it easily like this (x,y) -> (y,-x). In higher dimensions use cross product with some non coplanar vectors.
compute line vs. line intersection
there are tons of stuff about this so google or solve the equation yourself here you can extract mine implementation.
now after successful intersection
just compute d as distance between P and intersection point. Do not forget that parameter t must be in range. If not (or if no intersection) then return min(|P-P0|,|P-P1|)
[hints]
t and u parameters can be obtained directly from intersection test so if the perpendicular vector to (P1-P0) is normalized to size = 1 then the abs(u) parameter of intersection point is the distance
[notes]
I am not familiar with mongodb so if you have no means to use own tests inside then this answer is of coarse obsolete.
Unfortunately, MongoDB provides very basic geospatial query, so you should create the buffer by your own. You can read how to do it here: Computing a polygon that surrounds a multi-point line
If you have longitude/latitude coordinates like WGS84 you must adjust this code; Read here how to calculate distance between point on a sphere https://en.wikipedia.org/wiki/Haversine_formula

Dividing a geographic region

I have a certain geographic region defined by the bottom left and top right coordinates. How can I divide this region into areas of 20x20km. I mean in practial the shape of the earth is not flat it's round. The bounding box is just an approximation. It's not even rectangular in actual sense. It's just an assumption. Lets say the bottomleft coordinate is given by x1,y1 and the topright coordinate is given by x2,y2, the length of x1 to x2 at y1 is different than that of the length between x1 to x2 at y2. How can I overcome this issue
Actually, I have to create a spatial meshgrid for this region using matlab's meshgrid function. So that the grids are of area 20x20km.
meshgrid(x1:deltaY:x2,y1:deltaX:y2)
As you can see I can have only one deltaX and one deltaY. I want to choose deltaX and deltaY such that the increments create grid of size 20x20km. However this deltaX and deltaY are supposed to vary based upon the location. Any suggestions?
I mean lets say deltaX=del1. Then distance between points (x1,y1) to (x1,y1+del1) is 20km. BUt when I measure the distance between points (x2,y1) to (x2, y1_del1) the distance is < 20km. The meshgrid function above does creates mesh. But the distances are not consistent. Any ideas how to overcome this issue?
Bear in mind that 20km on the surface of the earth is a REALLY short distance, about .01 radians - so the area you're looking at would be approximated as flat for anything non-scientific. Assuming it is scientific...
To get something other than monotonic steps in meshgrid you should create a function which takes as its input your desired (x,y) and maps it relative to (x_0,y_0) and (x_max,y_max) in your units of choice. Here's an inline function demonstrating the idea of using a function for meshgrid steps
step=inline('log10(x)');
[x,y]=meshgrid(step(1:10),step(1:10));
image(255*x.*y)
colormap(gray(255))
So how do you determine what the function should be? That's hard for us to answer exactly without a little more information about what your data set looks like, how you're interacting with it, and what your accuracy requirements are. If you have access to the actual location at every point, you should vary one dimension at a time (if your data grid is aligned with your latitude grid, for example) and use a curve fit with model selection techniques (akaike/bayes criterion) to find the best function for your data.

Trouble understanding MKMapPoint(s)

Can anyone point me in the right direction when it comes to understanding MKMapPoint?
I understand that it has to do with laying suface of the globe on a 2D surface. But I don't understand how each "point" is measured?
Can anyone give me an example in code?
There is nothing much to it.. just a structure to display point on a 2D map... here is what the documentation says..
MKMapPoint A point on a two-dimensional map projection.
typedef struct {
double x;
double y; } MKMapPoint;
Fields x The location of the point along the x-axis of the
map. y The location of the point along the y-axis of
the map. Discussion If you project the curved surface of the globe
onto a flat surface, what you get is a two-dimensional version of a
map where longitude lines appear to be parallel. Such maps are often
used to show the entire surface of the globe all at once. An
MKMapPoint data structure represents a point on this two-dimensional
map.
The actual units of a map point are tied to the underlying units used
to draw the contents of an MKMapView, but you should never need to
worry about these units directly. You use map points primarily to
simplify computations that would be complex to do using coordinate
values on a curved surface. By converting to map points, you can
perform those calculations on a flat surface, which is generally much
simpler, and then convert back as needed. You can map between
coordinate values and map points using the MKMapPointForCoordinate and
MKCoordinateForMapPoint functions.
When saving map-related data to a file, you should always save
coordinate values (latitude and longitude) and not map points.
Availability Available in iOS 4.0 and later. Declared In MKGeometry.h
If you want to draw something over a map that has a certain real-world size, for example, a scale, then in your calculations you would multiply any given length in meters with the result of MKMapPointsPerMeterAtLatitude(...) to get the size in MKMapPoint units.
If your map displays only of small portion of the globe, MKMapPointsPerMeterAtLatitude(...) will deliver roughly the same constant value for all the latitudes involved in your map. In this case, you can simply use the latitude in the middle of your map as the argument of this function.
Also read in the documentation that a Mercator projection is used for the transformation. Here is an additional observation: northing (y) axis direction seems to be in reverse direction of standard mercator projections (positive direction is down instead of up).

How to determine if a latitude & longitude is within an ellipse

I have data describing a rotated ellipse (the center of the ellipse in latitude longitude coordinates, the lengths of the major and minor axes in kilometers, and the angle that the ellipse is oriented). I do not know the location of the foci, but assume there is a way to figure them out somehow. I would like to determine if a specific latitude longitude point is within this ellipse. I have found a good way to determine if a point is within an ellipse on a Cartesian grid, but don't know how to deal with latitude longitude points.
Any help would be appreciated.
-Cody O.
The standard way of doing this on a Cartesian plane would be with a ray-casting algorithm. Since you're on a sphere, you will need to use great circle distances to accurately represent the ellipse.
EDIT: The standard ray-casting algorithm will work on your ellipse, but its accuracy depends on a) how small your ellipse is, and b) how close to the equator it is. Keep in mind, you'd have to be aware of special cases like the date line, where it goes from 179 -> 180/-180 -> -179.
Since you already have a way to solve the problem on a cartesian grid, I would just convert your points to UTM coordinates. The points and lengths will all be in meters then and the check should be easy. Lots of matlab code is available to do this conversion from LL to UTM. Like this.
You don't mention how long the axes of the ellipse are in the description. If they are very long (say hundreds of km), this approach may not work for you and you will have to resort to thinking about great circles and so on. You will have to make sure to specify the UTM zone to which you are converting. You want all your points to end up in the same UTM zone or you won't be able to relate the points.
After some more research into my problem and posting in another forum I was able to figure out a solution. My ellipse is relatively small so I assumed it was a true (flat) ellipse. I was able to locate the lat lon of the foci of the ellipse then if the sum of the distances from the point of interest to each focus is less than 2a (the major axis radius), then it is within the ellipse. Thanks for the suggestions though.
-Cody