Graph line from GPS points
I have about 100 lists of gps coordinates and I want to draw a line that each of these lists make.
One of the scatter-plotted lists looks something like this:
Clearly there is a line in there;
I tried several methods for sorting gps positions and plotting them:
lats = []
lngs = []
with open(filename) as f:
for line in f:
lat, lng = line.split("\t")
lats.append(float(lat))
lngs.append(float(lng))
def sort_positions(position):
return position[0]+position[1]
positions= zip(lngs, lats)
positions = sorted(poss, key=sort_positions)
for i, positionin enumerate(positions):
lng, lat = position
#plt.scatter(lng, lat)
try:
n_lng, n_lat = positions[i+1]
plt.plot((lng, n_lng),(lat, n_lat), "b")
except IndexError:
pass
plt.show()
Sorted by longitude
def sort_positions(position):
return position[0]
Sorted by latitude
def sort_positions(position):
return position[1]
Sort by summing both
def sort_positions(position):
return position[0]+position[1]
If the line is mostly straight on one of the axes (latitude / longitude) it looks good (some small bumps are still displayed)
Here's one of the lists that do fine sorting by sorting by latitude.
I only plan if the distance between the two points was less than 200 ~ 500 meters, but I get holes in the rows as some data is missing there.
Perhaps I am doing it wrong. Does anyone know how to construct these lines correctly?
EDIT:
In response to the rth
answer:
The blue line uses its own approach in these questions, the red one uses this method in its other answer .
Ignoring the fact that red closes the loop.
There are some limitations in both cases: firstly, red cannot handle too many points, I had to use 1/90 points for both, blue generates some strange sharp turns when the points are too (dark spots in the image), and red is some strange curves in these places.
source to share
The easiest thing to do here is to figure out why the GPS coordinates were involved in the first place and fix it.
If this is not possible, the only thing I can think of is an iterative algorithm that takes an xy point and decides, based on some criteria (like distance, directions of consecutive points, etc.) which should go further.
Something along these lines
import numpy as np
from scipy.spatial.distance import pdist, squareform
def find_gps_sorted(xy_coord, k0=0):
"""Find iteratively a continuous path from the given points xy_coord,
starting by the point indexes by k0 """
N = len(xy_coord)
distance_matrix = squareform(pdist(xy_coord, metric='euclidean'))
mask = np.ones(N, dtype='bool')
sorted_order = np.zeros(N, dtype=np.int)
indices = np.arange(N)
i = 0
k = k0
while True:
sorted_order[i] = k
mask[k] = False
dist_k = distance_matrix[k][mask]
indices_k = indices[mask]
if not len(indices_k):
break
# find next unused closest point
k = indices_k[np.argmin(dist_k)]
# you could also add some criterion here on the direction between consecutive points etc.
i += 1
return sorted_order, xy_coord[sorted_order]
which you could use like
xy_coord = np.random.randn(10, 2)
sorted_order, xy_coord_sorted = find_gps_sorted(xy_coord, k0=0)
although this may need to be expanded.
For example, you could say that in addition to the closest distance criteria, you don't want the trajectory to rotate more than 90 ° (if that's what makes sense for buses) and ignores those points on each iteration. Basically, you can add enough constraints to this algorithm to get the result you are looking for.
Change: . Since GPS coordinates have some uncertainty, the last step could be to smooth the resulting trace using B-spline interpolation using scipy.interpolate.splprep
and play with the argument s
(see related questions (1) , (2) )
source to share
I suspect that all the (nice but) weird plots (except the first one) are due to the fact that you are trying to sort something that doesn't allow alphabetical ordering.
There is no reason to plot each line segment separately. Try to do only:
plt.plot(lngs, lats, 'b')
Here's a sample track I plotted: I didn't scale the horizontal and vertical axes correctly, so the graph is stretched vertically (too tall).
source to share