Extract constrained polygon using OSMnx - networkx

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.

Related

Find points where a polygon and the road network intersect

I want to find the intersecting points between a polygon and the road network and add them to the network as nodes.
import osmnx as ox
import folium
from shapely.geometry import Polygon
G = ox.graph_from_place('Lebanon, NH, USA', network_type='drive')
m1 = ox.plot_graph_folium(G, edge_color = "red")
polygon = Polygon([(-72.2460023,43.6225941), (-72.2547570,43.6063131),(-72.2329560,43.6007194),(-72.2272912,43.6136463),(-72.2460023,43.6225941)])
folium.GeoJson(data=polygon).add_to(m1)
The second part of what I seek to do can be accomplished in a pretty straightforward fashion - has previously been answered on Stack Overflow here.
I'm presuming I would have to get both the polygon and the road network as linestrings (perhaps by rounding the points in the line string to a number of significant digits) to find the common latitude and longitude points.
Here is an image of the points (encircled in black) I'd like to add to the network, as a minimalistic example.
The folium map is reproducible from the code above.
An alternative method that could also be useful in my case, is if I am able to say that there are two unconnected road network segments (in orange) within the polygon (might be more "unconnected" segments in some other road networks).
Thank you for your help in advance!

Intersection of points and polygons using geopandas

I am using the Australian Bureau of Statistics data (ABS) to visualize meshblocks and boundaries of buffer data from a centre of location with certain radius.
I want to create the following plot:
intersection plot
So far, I am able to create a function which can give me a circle with certain radius depending on the initial coordinates (lon, lat) I have provided.
I have used the following function to plot the circle around the required location on the map:
import geopandas as gpd
import pandas as pd
import leaflet
from osgeo import gdal
import shapefile as shp
def func_radius_around_point(point_list,m_list,crs_from,crs_to):
points_df = pd.DataFrame(point_list).reset_index()
points_df = points_df.rename(columns={0:'geometry'})
points_gpd = gpd.GeoDataFrame(points_df,geometry='geometry',crs=crs_from)
for m in m_list:
buffered= points_gpd.to_crs(epsg=crs_to).buffer(m).to_crs(epsg=crs_from)
col_name = 'buffered_{m}'.format(m=m)
points_gpd[col_name] = buffered
return points_gpd
I have the data for mesh block and statistical area 1. All I want to create is the intersection of points and polygon. How do I create this intersection using geopandas?
With R, it seems so much easier using the simple features library. Is there a simple features package in geopandas that I have missed out on?

Create circle around user inputted point and plot on map with custom latlon points

I have a question about if something is possible using Tableau.
I already have a coastline plotted on one map using custom LatLon coordinates and I would like to take a user inputted Lat and Lon and plot a circle around it with let's say radius 10 and display it on the same map.
I was using this tutorial before to plot a circle:
https://www.crowdanalytix.com/communityBlog/customers-within-n-miles-radius-analysis-using-tableau
But I don't think the same approach can work with user-inputted fields because then it would require restructuring the data..
Okay, a (much smarter LOL) coworker helped me figure this out....
So my goal was to graph distance band (like a distance of 5 miles around a coast) . In order to do this we can use the distance between two coastline points since they are connected by a line, not a curve...From there we can find the perpendicular point a certain distance away and connect those points. Much easier than my circle idea...

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

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

MATLAB: Failed to create geometry. The stl file is invalid, more than two facets share an edge

im trying to create a crater alpha shape.
this is what i wrote so far:
ddr=0.12;
a=1/ddr/2; %semi major axis. horizontal axes are equal
n=91; %number of points for x y vectors.
x = linspace(-a,a,n);
y = linspace(-a,a,n);
[X,Y] = meshgrid(x,y);
Z =real(sqrt(1-(X.^2)/a^2-(Y.^2)/a^2))*-1+1; % the plus 1 for Z>0
shp = alphaShape(X(:),Y(:),Z(:));
plot(shp);
[elements,nodes] = boundaryFacets(shp);
nodes = nodes';
elements = elements';
model = createpde();
geometryFromMesh(model,nodes,elements);
but im getting the following error:
Failed to create geometry. The stl file is invalid, more than two facets share an edge.
thank you for your help
I suspected that the problem comes only because of the interface of one object over the another (possibly there are more than one objects in your geometry), even though there are no overlaps. Try import a single object instead of importing the whole geometry.
Another solution is to convert your stl file to faces and vertices using stlread.m
and reconstruct the geometry.
Good luck!