osmnx: project point to street segments - line

I have a point given by lat and lon and I want to find the nearest edge to the point by minimum Euclidean distance. For example
import osmnx as ox
track = [(40.7052, -74.0069)]
fig, ax = ox.plot_graph(G, show=False, close=False)
for pairs in track:
ax.scatter(pairs[1], pairs[0], c='red')
plt.show()
ox.distance.get_nearest_edge(G, track, return_geom=True, return_dist=True)
and I get
(2350521192,2350521202,0,
<shapely.geometry.linestring.LineString at 0x16569aa30>,
162.22242578930698)
It outputs the vertices of the edge and its geometry. The distance between the point and nearest edge is 162. But how do I find the the projection of my point onto this nearest edge?

Here's a complete minimal working example:
import osmnx as ox
from shapely.geometry import Point
ox.config(use_cache=True, log_console=True)
# create point tuple as (lat, lng)
point = (40.7052, -74.0069)
G = ox.graph_from_point(point, network_type='drive')
u, v, k, edge_geom, dist = ox.distance.get_nearest_edge(G, point, return_geom=True, return_dist=True)
# create shapely point geometry object as (x, y), that is (lng, lat)
point_geom = Point(reversed(point))
# use shapely to find the point along the edge that is closest to the reference point
nearest_point_on_edge = edge_geom.interpolate(edge_geom.project(point_geom))
nearest_point_on_edge.coords[0]

Related

Get US State for given location coordinates

I want to figure out which state a lat long belongs to. And for this I am using the shape files provided by US Census and shapely library. This is what I tried so far:
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
df_poly = gpd.read_file("data/tl_2019_us_state.shp")
df_poly = df_poly[['GEOID', 'geometry']].set_index('GEOID')
display(df_poly.head(5))
geometry
GEOID
54 POLYGON ((-81.74725 39.09538, -81.74635 39.096...
12 MULTIPOLYGON (((-86.38865 30.99418, -86.38385 ...
17 POLYGON ((-91.18529 40.63780, -91.17510 40.643...
27 POLYGON ((-96.78438 46.63050, -96.78434 46.630...
24 POLYGON ((-77.45881 39.22027, -77.45866 39.220...
p1 = Point(map(float, (29.65, -95.17)))
any(df_poly['geometry'].contains(p1))
False
But it is somehow returning False for any coordinate that I try. For example the above coordinate is from Texas but still its returning False, so what am I missing here?
Here are a few things you should check:
Did you use the correct order for the point? Shapely points use (x, y) coordinates, which are in the opposite order of (lat, lon) coordinates. I'd try flipping the coordinates and seeing if that works.
For example, I see one of your coordinates is this: "-81.74725 39.09538" If you interpret that in (lat, lon) order, it's in Antartica. If you interpret it in (x, y) order, it's in Ohio.
Are you using the correct SRID? The census data usually uses NAD83, but this is a good thing to check:
print(df_poly.crs)
Another good sanity check is to look at the centroid of each polygon, and verify that it's reasonable:
df.geometry.centroid
In the past, I've seen people who had data which was in the wrong SRID, and had to convert it.

Draw a point at the mean peak of a distplot or kdeplot in Seaborn

I'm interested in automatically plotting a point just above the mean peak of a distribution, represented by a kdeplot or distplot with kde. Plotting points and lines manually is simple, but I'm having difficulty deriving this maximal coordinate point.
For example, the kdeplot generated below should have a point drawn at about (3.5, 1.0):
iris = sns.load_dataset("iris")
setosa = iris.loc[iris.species == "setosa"]
sns.kdeplot(setosa.sepal_width)
This question is serving the ultimate goal to draw a line across to the next peak (two distributions in one graph) with a t-statistic printed above it.
Here is one way to do it. The idea here is to first extract the x and y-data of the line object in the plot. Then, get the id of the peak and finally plot the single (x,y) point corresponding to the peak of the distribution.
import numpy as np
import seaborn as sns
iris = sns.load_dataset("iris")
setosa = iris.loc[iris.species == "setosa"]
ax = sns.kdeplot(setosa.sepal_width)
x = ax.lines[0].get_xdata() # Get the x data of the distribution
y = ax.lines[0].get_ydata() # Get the y data of the distribution
maxid = np.argmax(y) # The id of the peak (maximum of y data)
plt.plot(x[maxid],y[maxid], 'bo', ms=10)

How to create volume from point cloud in spherical coordinates?

I have two sets of discrete points in spherical coordinates, each representing top and bottom surfaces of an object.
I am trying to create volume from these points to separate points which lies inside and outside the object. Any suggestions where to look or which library to use?
Blue and red points represents top and bottom surfaces. Red points are generated by shifting top surface radially downwards with some constant radius.
If I am right, the blue and red surfaces are meshed (and watertight). So for every point you can draw the line from the sphere center and look for intersections with the mesh. This is done by finding the two triangles such that the line pierces them (this can be done by looking at the angular coordinates only, using a point-in-triangle formula), then finding the intersection points. Then it is an easy matter to classify the point as before the red surface, after the blue or in between.
Exhaustive search for the triangles can be costly. You can speed it up for instance using a hierarchy of bounding boxes or similar device.
Here is a custom tinkered method which may works at the condition that the average distance between points in the original surface is much smaller than the thickness of the volume and than the irregularities on the surface contour. In other words, that there are a lot of points describing the blue surfaces.
import matplotlib.pylab as plt
import numpy as np
from scipy.spatial import KDTree
# Generate a test surface:
theta = np.linspace(3, 1, 38)
phi = np.zeros_like(theta)
r = 1 + 0.1*np.sin(8*theta)
surface_points = np.stack((r, theta, phi), axis=1) # n x 3 array
# Generate test points:
x_span, y_span = np.linspace(-1, 0.7, 26), np.linspace(0.1, 1.2, 22)
x_grid, y_grid = np.meshgrid(x_span, y_span)
r_test = np.sqrt(x_grid**2 + y_grid**2).ravel()
theta_test = np.arctan2(y_grid, x_grid).ravel()
phi_test = np.zeros_like(theta_test)
test_points = np.stack((r_test, theta_test, phi_test), axis=1) # n x 3 array
# Determine if the test points are in the volume:
volume_thickness = 0.2 # Distance between the two surfaces
angle_threshold = 0.05 # Angular threshold to determine for a point
# if the line from the origin to the point
# go through the surface
# Get the nearest point: (replace the interpolation)
get_nearest_points = KDTree(surface_points[:, 1:]) # keep only the angles
# This is based on the cartesian distance,
# and therefore not enterily valid for the angle between points on a sphere
# It could be better to project the points on a unit shpere, and convert
# all coordinates in cartesian frame in order to do the nearest point seach...
distance, idx = get_nearest_points.query(test_points[:, 1:])
go_through = distance < angle_threshold
nearest_surface_radius = surface_points[idx, 0]
is_in_volume = (go_through) & (nearest_surface_radius > test_points[:, 0]) \
& (nearest_surface_radius - volume_thickness < test_points[:, 0])
not_in_volume = np.logical_not(is_in_volume)
# Graph;
plt.figure(figsize=(10, 7))
plt.polar(test_points[is_in_volume, 1], test_points[is_in_volume, 0], '.r',
label='in volume');
plt.polar(test_points[not_in_volume, 1], test_points[not_in_volume, 0], '.k',
label='not in volume', alpha=0.2);
plt.polar(test_points[go_through, 1], test_points[go_through, 0], '.g',
label='go through', alpha=0.2);
plt.polar(surface_points[:, 1], surface_points[:, 0], '.b',
label='surface');
plt.xlim([0, np.pi]); plt.grid(False);plt.legend();
The result graph, for 2D case, is:
The idea is to look for each test point the nearest point in the surface, by considering only the direction and not the radius. Once this "same direction" point is found, it's possible to test both if the point is inside the volume along the radial direction (volume_thickness), and close enough to the surface using the parameter angle_threshold.
I think it would be better to mesh (non-convex) the blue surface and perform a proper interpolation, but I don't know Scipy method for this.

Cartopy plot high/low sea level pressure on map

I'm migrating from basemap to cartopy. One thing I would like to do is plot high/low pressure on a map, such as in basemap. There is a good example on this page of how to do this: https://matplotlib.org/basemap/users/examples.html ("Plot sea-level pressure weather map with labelled highs and lows"). I'm not going to copy and paste the code from this site, but would like to know how to do the same in cartopy. The main thing I can't get my head around is how to do m.xmax and x > m.xmin and y < m.ymax and y > m.ymin in cartopy (some kind of vector transform I'd imagine.
I've had a good look and can't see this particular example translated into something compatible with cartopy. Any help would be welcome!
In order to write an equivalent program using cartopy you need to be able to translate two concepts. The first is finding the extent of a projection, this can be done with the get_extent() method of a GeoAxes:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
my_proj = ccrs.Miller(central_longitude=180)
ax = plt.axes(projection=my_proj)
xmin, xmax, ymin, ymax = ax.get_extent()
You also need to transform coordinate points from geographic to projection coordinates, which is the function of the transform_points() method of a coordinate reference system instance:
import numpy as np
lons2d, lats2d = np.meshgrid(lons, lats) # lons lats are in degrees
transformed = my_proj.transform_points(ccrs.Geodetic(), lons2d, lats2d)
x = transformed[..., 0] # lons in projection coordinates
y = transformed[..., 1] # lats in projection coordinates
Now you can use the same technique as in the basemap example to filter and plot points, where instead of m.xmin you use xmin etc.
There are of course alternate ways of doing this which have pros and cons relative to the basemap example. If you come up with something nice you can contribute it to the Cartopy gallery.

Pyplot polar surface plot

I am new in pyplot.
I have a Cartesian surface plot:
# offset and omega are arrays
Z = my_function(omega,offset) # my_function give and arrays of omega.size*offset.size
fig, ax = plt.subplots(1)
p = ax.pcolor(offset,omega,Z.T,cmap=cm.jet,vmin=abs(Z).min(),vmax=abs(Z).max())
cb = fig.colorbar(p,ax=ax)
Maybe there is a more simple way to plot a surface but that the way I've found on the internet.
Well, now I want to plot my_function as a surface using polar coordinate, I've tried this:
ax2 = plt.subplot(111, polar=True)
p2 = ax2.pcolor(offset,omega,Z.T,cmap=cm.jet,vmin=abs(Z).min(),vmax=abs(Z).max())
It kind of work, I have a surface plot but it does not take into account the limits of Y.
For example if Y is defined between -15 and 15° I only want my function to be plotted and shown between those angles and not 0 to 360° as my example is doing.
How can I do that ?
I thank you in advance for any answer.