Why do the inverse function from both cartopy and basemap have different results to calculate distance? - matplotlib-basemap

I want to calculate the distance between two points on surface of earth in meteres
I have tried with both basemap and cartopy but both result in different numbers.
Basemap:
import mpl_toolkits.basemap.pyproj as pyproj
k = pyproj.Geod(ellps="WGS84")
distance = k.inv(c0[1], c0[0], c1[1], c1[0])[-1]/1000.
Cartopy:
import cartopy.geodesic as gd
k = gd.Geodesic() // defaults to WGS84
distance = k.inverse(c0, c1).base[0,0]/1000
where both coord0 and coord1 are numpy arrays of size 2 having lat and lon of a coordinate.
c0 = numpy.array([77.343750, 22.593726])
c1 = numpy.array([86.945801, 23.684774])
Cartopy Output: 990.6094719605074
Basemap Output: 1072.3456344712142

With Basemap, you must use proper order of (long, lat):
distance = k.inv(c0[0], c0[1], c1[0], c1[1])[-1]/1000.
and the result will agree with Cartopy's, which is the correct result:
990.6094719605074

Related

annulus with scipy Delaunay

i try to draw a 3d solid that represents an annulus. I have used the scipy module and Delaunay to do the calculation.
Unfortunately the plot shows a 3d cylinder and not an annulus. Has somebody an idea how to modify the code? Is scipy the right module? Can i use Delaunay with retangular shapes?
thanks in advance!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import Delaunay
points = 50
theta = np.linspace(0,2*np.pi,points)
radius_middle = 7.5
radius_inner = 7
radius_outer = 8
x_m_cartesian = radius_middle * np.cos(theta)
y_m_cartesian = radius_middle * np.sin(theta)
z_m_cartesian = np.zeros(points)
M_m = np.c_[x_m_cartesian,y_m_cartesian,z_m_cartesian]
x_i_cartesian = radius_inner * np.cos(theta)
y_i_cartesian = radius_inner * np.sin(theta)
z_i_cartesian = np.zeros(points)
M_i = np.c_[x_i_cartesian,y_i_cartesian,z_i_cartesian]
x1_m_cartesian = radius_middle * np.cos(theta)
y1_m_cartesian = radius_middle * np.sin(theta)
z1_m_cartesian = np.ones(points)
M1_m = np.c_[x1_m_cartesian,y1_m_cartesian,z1_m_cartesian]
x2_i_cartesian = radius_inner * np.cos(theta)
y2_i_cartesian = radius_inner * np.sin(theta)
z2_i_cartesian = np.ones(points)
M2_i = np.c_[x2_i_cartesian,y2_i_cartesian,z2_i_cartesian]
M = np.vstack((M_m,M_i,M1_m,M2_i))
# Delaunay
CH = Delaunay(M).convex_hull
x,y,z = M[:,0],M[:,1],M[:,2]
fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111,projection='3d')
#ax.scatter(x[:,0],y[:,1],z[:,2])
ax.plot_trisurf(x,y,z,triangles=CH, shade=False, color='lightblue',lw=1, edgecolor='k')
plt.show()
As noted in the comments the convex hull is a convex shape and therefore cannot represent an annulus. However, the concept of the concave hull (also known as the alpha-shape) is probably appropriate for your needs. Basically, the alpha-shape removes from the Delaunay triangulation the triangles (tetrahedra in your 3D case) that have a circumradius greater than some value (defined by the alpha parameter).
This answer provides an implementation of the alpha-shape surface (i.e., the outer boundary) for 3D points. Using the alpha_shape_3D function from that answer, with an alpha value of 3, resulted in the figure below.
The following two lines in the code (replacing the assignment to CH and the plot function) do the job.
vertices, edges, facets = alpha_shape_3D(pos=M, alpha=3.)
ax.plot_trisurf(x,y,z,triangles=facets, shade=False, color='lightblue',lw=1, edgecolor='k')

Combine and sum values of overlapping Polygons in GeoPandas

I have a GeoPandas dataframe with a.o. polygons as 'geometry' column and a corresponding value in a different column. E.g. like such:
import numpy as np
import geopandas as gpd
xmin, xmax, ymin, ymax = 900000, 1080000, 120000, 280000
xc = (xmax - xmin) * np.random.random(2000) + xmin
yc = (ymax - ymin) * np.random.random(2000) + ymin
gdf = gpd.GeoDataFrame(geometry=gpd.points_from_xy(xc,yc),crs=3857)
gdf['geometry'] = gdf['geometry'].buffer(5000)
gdf['value'] = np.random.random(2000)
gdf.head()
geometry value
0 POLYGON ((1058397.021 237842.681, 1058372.944 ... 0.792110
1 POLYGON ((907562.671 276549.404, 907538.595 27... 0.124436
2 POLYGON ((953685.557 229083.936, 953661.481 22... 0.264356
3 POLYGON ((1052030.845 242915.680, 1052006.769 ... 0.161183
4 POLYGON ((1063942.060 263330.293, 1063917.983 ... 0.972290
What I would like to do is create new polygons describing the overlap of all polygons and sum the values of these overlapping polygons, as in the picture below:
I've looked at dissolve and at unary_union, but these do not seem to do the trick. Any suggestions are appreciated.
For anyone intersted in a solution for this, here is an example that solves a similar problem.
First create the geodataframe:
from shapely.geometry import Polygon
import geopandas
from shapely.ops import linemerge, unary_union, polygonize
dftest = geopandas.GeoDataFrame({'geometry': geopandas.GeoSeries([Polygon([(0,0), (3,0), (3,3), (0,3)]),
Polygon([(0,0), (2,0), (2,2), (0,2)]),
Polygon([(2,2), (4,2), (4,4), (2,4)]),
Polygon([(1,1), (3,1), (3,3), (1,3)]),
Polygon([(3,3), (5,3), (5,5), (3,5)])])}
).reset_index()
dftest['values'] = [4,3,2,1,0]
Plot this:
dftest.plot('values', legend=True)
initial geodataframe
convert all polygons to lines and perform union:
lines = unary_union(linemerge([geom.exterior for geom
in dftest.geometry]))
Convert again to (smaller) intersecting polygons and to geodataframe:
polygons = list(polygonize(lines))
intersects = geopandas.GeoDataFrame({'geometry': polygons})
Perform sjoin with original geoframe to get overlapping polygons. Afterwards group per intersecting polygon to perform (arbitrary) aggregation.
intersects['sum_overlaps'] = (intersects
.sjoin(dftest, predicate='within')
.reset_index()
.groupby(['level_0', 'index_right'])
.head(1)
.groupby('level_0')
.values.sum())
plot result
intersects.plot('sum_overlaps', legend=True)
overlap result

Get Distance Between Two Points in GeoPandas

I have two points as below. I need to get the distance between them in meters.
POINT (80.99456 7.86795)
POINT (80.97454 7.872174)
How can this be done via GeoPandas?
Your points are in a lon, lat coordinate system (EPSG:4326 or WGS 84). To calculate a distance in meters, you would need to either use the Great-circle distance or project them in a local coordinate system to approximate the distance with a good precision.
For Sri Lanka, you can use EPSG:5234 and in GeoPandas, you can use the distance function between two GeoDataFrames.
from shapely.geometry import Point
import geopandas as gpd
pnt1 = Point(80.99456, 7.86795)
pnt2 = Point(80.97454, 7.872174)
points_df = gpd.GeoDataFrame({'geometry': [pnt1, pnt2]}, crs='EPSG:4326')
points_df = points_df.to_crs('EPSG:5234')
points_df2 = points_df.shift() #We shift the dataframe by 1 to align pnt1 with pnt2
points_df.distance(points_df2)
The result should be 2261.92843 m

networkx ego_graph apply to geopandas series speed-up

Having GeoSeries of around 100000 locations, I have a working code for calculating Polygons of walking accessibility from each location as a center.
The code does calculations over networkx graph, obtained from OpenStreeMaps via osmnx by apply to GeoDataFrame.
I am trying to speed up calculation, as that is incredibly slow.
G - is a networkx graph
# create graph walking_time edge property
walking_speed = 4.5 #km/h
walking_speed_m_minute = walking_speed * 1000 / 60 #km/h to m/min
for u, v, k, data in G.edges(data=True, keys=True):
data['walking_time'] = data['length'] / walking_speed_m_minute
This is the func I apply to GeoDataFrame:
def calculate_time_accessibility_polygon(row, trip_time):
# location x,y
y = row['latitude']
x = row['longitude']
# find nearest node on the graph
center_node = ox.get_nearest_node(G, (y, x))
subgraph = nx.ego_graph(G, center_node, radius=trip_time,
distance='time')
node_points = [Point((data['x'], data['y'])) for node, data in
subgraph.nodes(data=True)]
bounding_poly = gpd.GeoSeries(node_points).unary_union.convex_hull
return(bounding_poly)
I apply with the following line of code:
gdf.apply(calculate_time_accessibility_polygon, args=(15,), axis=1))
Thank you!!!

how can i calculate distances with pyephem?

hi i need a little help if any of you know how to calculate the distance of a coordinates and a satellite projection, i mean, when i predict the path of the satellite i need to know what is the distance between the future path and the coordinates that i put. and with that make a message alert notifiyng me when that satellite will be close to the coordinates.
this is the code that i am using any of you could help me that would be great.
from mpl_toolkits.basemap import Basemap
from geopy.distance import great_circle
from matplotlib import colors
from pyorbital import tlefile
import matplotlib.pyplot as plt
import numpy as np
import math
import ephem
from datetime import datetime
tlefile.TLE_URLS = ( 'http://celestrak.com/NORAD/elements/resource.txt',)
sat_tle = tlefile.read('NUSAT 1 (FRESCO)')
sat = ephem.readtle("NUSAT 1 (FRESCO)", sat_tle.line1, sat_tle.line2)
obs = ephem.Observer()
# location for tge coordinates
print("Latitud ")
sat_lat = input()
print("Longitud suggested point")
sat_lon = input()
obs.lat = str(sat_lat)
obs.long = str(sat_lon)
# programar proyeccion del mapa
map = Basemap(projection='ortho', lat_0=sat_lat, lon_0=sat_lon, resolution='l')
# draw coastlines, country boundaries, fill continents.
map.drawcoastlines(linewidth=0.25)
map.drawcountries(linewidth=0.25)
map.fillcontinents(color='coral',lake_color='aqua')
# draw the edge of the map projection region (the projection limb)
map.drawmapboundary(fill_color='aqua')
# grid in latitud and longitud every 30 sec.
map.drawmeridians(np.arange(0,360,30))
map.drawparallels(np.arange(-90,90,30))
# plot
passes = 4
for p in range(passes):
coords = []
dists = []
tr, azr, tt, altt, ts, azs = obs.next_pass(sat)
print """Date/Time (UTC) Alt/Azim Lat/Long Elev"""
print """====================================================="""
while tr < ts:
obs.date = tr
sat.compute(obs)
print "%s | %4.1f %5.1f | %4.1f %+6.1f | %5.1f" % \
(tr, math.degrees(sat.alt), math.degrees(sat.az), math.degrees(sat.sublat), math.degrees(sat.sublong), sat.elevation/1000.)
sat_lat = math.degrees(sat.sublat)
sat_lon = math.degrees(sat.sublong)
dist = great_circle((sat_lat, sat_lon), (sat_lat, sat_lon)).miles
coords.append([sat_lon, sat_lat])
dists.append(dist)
tr = ephem.Date(tr + 30.0 * ephem.second)
md = min(dists)
imd = 1 - (float(md) / 1400)
hue = float(240) / float(360)
clr = colors.hsv_to_rgb([hue, imd, 1])
map.drawgreatcircle(coords[0][0], coords[0][1], coords[-1][0], coords[-1][1], linewidth=2, color=clr)
obs.date = tr + ephem.minute
# map with UTC
date = datetime.utcnow()
cs=map.nightshade(date)
plt.title('next '+ str(passes)+ ' passes of the satellite')
plt.show()
You might want to look at http://rhodesmill.org/pyephem/quick.html#other-functions where it describes the function ephem.separation(). You are allowed to call it with two longitude, latitude coordinate pairs, and it will tell you how far apart they are:
ephem.separation((lon1, lat1), (lon2, lat2))
So if you pass the satellites's longitude and latitude as one of the coordinate pairs, and the longitude and latitude of the position you are interested in as the other, then you can watch for when the separation grows very small.