Python for-loop to go through all rows of one column - python

I want to extract all coordinates out of a table which are inside a given radius.
How do I need to set the for loop?
I use the haversine formula for this and I just enter the lat and lon values of the center point and the lat and lon values of the point to be tested if it is in the given radius.
So I thought I need a for-loop where I run the haversine formula for each row of the lat and lon column and if the cooridnates are inside the radius i save them in an list.
#Get coordinates
#Center coordinates = nearest road location
lat1 = float(lowParkingUtilization.iloc[roadIndex].toLat)
lon1 = float(lowParkingUtilization.iloc[roadIndex].toLon)
#Test coordinates = scooter coordinates
insideRadius = []
radius = 2.50 # in kilometer
for i in eScooterVOI['lat']:
lat2 = float(eScooterVOI['lat'][i])
lon2 = float(eScooterVOI['lon'][i])
a = haversine(lon1, lat1, lon2, lat2)
if a <= radius:
insideRadius += str(lon2)+","+str(lat2)
else:
With the given code I get following error message:
File "<ipython-input-574-02dadebee55c>", line 18
^
SyntaxError: unexpected EOF while parsing

The correct answer for the question "How do I need to set the for loop?" is: YOU DON'T. pandas dataframes are not for looping over their rows. What you DO need to do is the create two new columns in the dataframe, one to calculate the distance, and one to store the names in the format you want:
eScooterVOI['dist'] = eScooterVOI.apply(lambda x: haversine(lon1, lat1, x['lon'], x['lat']), axis=1)
eScooterVOI['name'] = eScooterVOI['lon'].astype(str) + ',' + eScooterVOI['lat'].astype(str)
And then, to get a list with only the names of the coordinates whose distance is less than the radius use:
insideRadius = list(eScooterVOI[eScooterVOI['dist'] <= radius]['name'])
btw: the haversine function can be built in a way that it recieves a pandas series instead of a value, and by that it could be implemented much faster than using df.apply, but that would require changing some code which is not here in the question.

The SyntaxError: unexpected EOF while parsing error message means that some of the code blocks were not completed and the end of the code has reached.
Your else block requires at least one line of code that should be in it.
For example:
else:
lots_of_code_to_write_here

You had this error because of your else block.
When Python reads it, it expects some code to be written. Python does not find any so an error occures.
Your code might be working laready, just delete the else block, you can use an if block without being bound to use an else one.
Anyway, if you absolutely want to use an else block try something like that :
if a <= radius:
insideRadius += str(lon2)+","+str(lat2)
else :
pass
But I do not think it is recommended.

Related

How Can I Create Variables From Text and Convert Coordinates

I am aware there are similar questions to mine, but after trying numerous "answers" over several hours I thought my best next step is submit my conundrum here. I respect your time.
After several hours with no success in understanding why my Python script won't work I decided to see if someone could help me. Essentially, the goal is to use the astronomical program, "Stellarium" as a "day and night sky" to practice Celestial Navigation (CelNav) navigating the simulated world of Microsoft Flight Simulator X (FSX). The script actually writes a "startup.ssc" script which initializes Stellarium's date, time, and position.
The process is thus...
Use FSX and save a "flight." This creates a *.FLT file which is a text file which saves the complete situation, including time and location.
Run the FSXtoStellarium.py
Locate the lines of date, time, latitude, longitude, and altitude in the *.FLT text.
Read the data into variables.
Convert the Degrees(°), Minutes('), Seconds(") (DMS) to Decimal Degrees (DD).
Lastly, the script constructs a "startup.ssc" and opens Stellarium at the recorded time and place.
The Problem:
I have not been able to read the DMS into variable(s) correctly nor can I format the DMS into Decimal Degrees (DD). According to the "watches" I set in my IDE (PyScripter), the script is reading in an "int" value I can't decipher instead of the text string of the DMS (Example: W157° 27' 23.20").
Here are some excerpts of the file and script.
HMS Bounty.FLT
Various lines of data above...
[SimVars.0]
Latitude=N21° 20' 47.36"
Longitude=W157° 27' 23.20"
Altitude=+000004.93
Various lines of data below...
EOF
FSXtoStellarium.py
Various lines of script above...
# find lat & Lon in the file
start = content.find("SimVars.0")
latstart = content.find("Latitude=")
latend = content.find("Latitude=",latstart+1)
longstart = content.find("Longitude=",start)
longend = content.find(",",longstart)
# convert to dec deg
latitude = float(content[longend+1:latend])/120000
longitude = float(content[longstart+10:longend])/120000
Various lines of script below...
So, what am I missing?
FYI - I am an old man who gets confused. My professional career was in COBOL/DB2/CICS, but you can consider me a Python newbie (it shows, right?). :)
Your help s greatly appreciated and I will gladly provide any additional information.
Calvin
Here is a way to get from the text file (with multiple input lines) all the way to Decimal Degrees in python 2.7:
from __future__ import print_function
content='''
[SimVars.0]
Latitude=N21° 20' 47.36"
Longitude=W157° 27' 23.20"
'''
latKey = "Latitude="
longKey = "Longitude="
latstart = content.index(latKey) + len(latKey)
latend = content.find('"', latstart) + 1
longstart = content.find(longKey, latend) + len(longKey)
longend = content.find('"', longstart) + 1
lat = content[latstart:latend]
long = content[longstart:longend]
print()
print('lat ', lat)
print('long ', long)
deg, mnt, sec = [float(x[:-1]) for x in lat[1:].split()]
latVal = deg + mnt / 60 + sec / 3600
deg, mnt, sec = [float(x[:-1]) for x in long[1:].split()]
longVal = deg + mnt / 60 + sec / 3600
print()
print('latVal ', latVal)
print('longVal ', longVal)
Explanation:
we start with a multi-line string, content
the first index() call finds the start position of the substring "Latitude=" within content, to which we add the length of "Latitude=" since what we care about is the characters following the = character
the second index() call searches for the 'seconds' character " (which marks the end of the Latitude substring), to which we add one (for the length of the ")
the third index() call does for Longitude= something similar to what we did for latitude, except it starts at the position latend since we expect Longitude= to follow the latitude string following Latitude=
the fourth index() call seeks the end of the longitude substring and is completely analogous to the second index() call above for latitude
the assignment to lat uses square bracket slice notation for the list content to extract the substring from the end of Latitude= to the subsequent " character
the assignment to long is analogous to the previous step
the first assignment to deg, mnt, sec is assigning a tuple of 3 values to these variables using a list comprehension:
split lat[1:], which is to say lat with the leading cardinal direction character N removed, into space-delimited tokens 21°, 20' and 47.36"
for each token, x[:-1] uses slice notation to drop the final character which gives strings 21, 20 and 47.36
float() converts these strings to numbers of type float
the assignment to latVal does the necessary arithmetic to calculate a quantity in decimal degrees using the degrees, minutes and seconds stored in deg, mnt, sec.
the treatment of long to get to longVal is completely analogous to that for lat and latVal above.
Output:
lat N21° 20' 47.36"
long W157° 27' 23.20"
latVal 21.34648888888889
longVal 157.45644444444443

Program to draw line when y coordinates match or z coordinates

I am working on Ironpython in Revit application.
This is the code below I was trying in python. Help would be appreciated.
From the list of points, there is a first point and second point. I have created functions for them.
The script should check if the y coordinates are same and draw line if true.
Its not working and returning unexpected error - new line error.
`The inputs to this node will be stored as a list in the IN variables.`
points = IN[0]
`# Place your code below this line`
lines = []
def fp(x)
firstpoint = points[x]
return firstpoint
def sp(x)
secondpoint = points[x+1]
return secondpoint
x = 0
while x <= points.Count:
if (fp(x).Y == sp(x).Y) or (fp(x).Z == sp(x).Z):
setlines = Line.ByStartPointEndPoint(fp(x), sp(x))
lines.append(setlines)
x = x + 1
`# Assign your output to the OUT variable.`
OUT = lines
As #itprorh66 points out, there's really not enough info here to definitively answer your question, but one issue is you're incorrectly comparing what I assume are floats.
fp(x).Y == sp(x).Y
Instead of comparing for direct equality, you'll need to compare for equality within a tolerance. Here is some discussion on how to do that, What is the best way to compare floats for almost-equality in Python?

Comparing two sets of attributes from two datasets and updating third dataset with matches

I have a couple of questions about my code. One is why I'm having trouble with my uber-nested for loops, and the other is if anyone has any tips for improving my code in general.
I'm trying to write code that normalizes a small spatial dataset (inputDs) by comparing columns from it and a huge reference dataset called refDs, and then returns potential matches in a new table called "matches". The fields being compared are:
refDs latitude,
refDs longitude,
inputDs lat (which I copied to a list, inLat),
inDs long (in another list, inLong),
refDs field "nameAttested" (the formal name of a location),
refDs field "nameTransliterated" (for the sake of this code, this is one or more alternate names for the location),
inDs nameAtt (copied to a list, inAtt),
inDs nameTrans (copied to a list, inTrans).
So for those of you who are counting, that's four lists-- one for each inputDs attribute, and four columns in a table, refDs, which are going to be compared. First, if the coordinates line up (within 5 of each other), the refDs and inputDs records are added to the new table "matches." Then, each of the name attributes has to be compared twice-- refAtt to inAtt, refTrans to inAtt, refAtt to inTrans, and refTrans to inTrans, and for each name match, a count attribute in matches ("mCount") gets += 1. Also, some nameTrans fields in both refDs and inDs have 0 names or more than 1.
The code below shows how I'm working on a nested insert cursor for my matches table, which iterates through my inLat and inLong lists, passing them and the refLat and refLong into the great circle distance function (which I successfully added). Take a look:
# set variables
lat1 = "reprLat"
lon1 = "reprLong"
lat2 = inLat
lon2 = inLong
refAtt = refDs.nameAttested
refTrans = refDs.nameTransliterated
# insertCursor for matches Table
rows = arcpy.da.InsertCursor(matches, [lat1, lon1, lat2, lon2, refAtt, refTrans,"inAtt",
"inTrans", "mCount"])
#searchcursor for refDs
refCursor = arcpy.da.SearchCursor(refDs, ["reprLat", "reprLong"])
for i in lat2:
for x in lon2:
for y in lat1:
for z in lon1:
if great_circle(lon1[0], lat1[0], lon2[0], lat2[0]) <= 5:
rows.insertRow()
for x in inAtt:
for y in inTrans:
for z in refAtt:
for i in refTrans:
if textdistance.jaro(refAtt, inAtt) >= 0.45:
mCount += 1
elif textdistance.jaro(refAtt, inTrans) >= 0.45:
mCount += 1
elif textdistance.jaro(refTrans, inAtt) >= 0.45:
mCount += 1
elif textdistance.jaro(refTrans, inTrans) >= 0.45:
mCount += 1
I tested the first part (measuring distances), by running it in Juptyer with a simple, if ... <= 5, print"yes", else print "no". And no matter the number I measured the distances against (5, 20, 100, 1000), I either got all yeses or all nos. So I'm clearly doing something wrong. Can anyone tell me how to fix the semantics of that section?
Also, is there anyway to make all this nesting ... more elegant? I only started to learn to code this year, and I'm still learning a lot of basic things and making elementary errors.
Thank you in advance.

Huge Difference in result when calculating distance b/w two points using longitude-latitude

I am attempting to calculate the distance between two Positions using SRID(32148)
Here are my two points
Point-1:
Lat:46.489767 Long:-119.043221
Point-2:
Lat:47.610902 Long:-122.336422
This website states that the distance in miles b/w these two points is 173.388 however from the code below the result I am getting is 0.002161632093865483
This is the code that I am using
employeeloc = modelEmployee.objects.filter(user__first_name="adam")[0].location
employerloc = modelEmployer.objects.filter(user__first_name="adam")[0].location
meters = employerloc.distance(employeeloc)
#Caluclate in miles
dobj = Distance(m=meters)
mi = dobj.mi
This is a little more detail with debugging results attached
Any suggestions on why my result is so different ?
Update:
I tried transforming the position using the following code using SRID 4326. However the results are still incorrect
You appear to have used the lon / lat coordinates as SRID(32148) ones; you need to transform them.
This incorrect query gives your result 3.47m, because the coordinates don't match the SRID:
select
st_distance(
st_setsrid(st_point(-122.336422,47.610902),32148),
st_setsrid(st_point(-119.043221,46.489767),32148))
-- 3.47880964046985
This query gives you the 173.71 mi result you expect:
select
st_distance(
st_transform(st_setsrid(st_point(-122.336422,47.610902),4326),32148),
st_transform(st_setsrid(st_point(-119.043221,46.489767),4326),32148))
--279558.106935732m (=173.71mi)
And that is similar to the result of this query:
select
st_distance(
st_setsrid(st_point(-122.336422,47.610902),4326)::geography,
st_setsrid(st_point(-119.043221,46.489767),4326)::geography)
--279522.55326056 m (= 173.69 mi)

Geopandas : sort a sample of points like a cycle graph

I'm trying geopandas to manipulate some points data. My final GeoDataFrame is represented there :
In order to use an other Python module which calculates the shortest road between two points with OSM data, I must sort my points like a tour.
If not, the next Python module which calculates shortest road, but not necessarily between the nearest points. And the main problem is the constraint of a tour.
If my points were only in a line, a basic sorting function on latitudes and longitudes of each point should be enough, like :
df1 = pd.read_csv("file.csv", sep = ",")
df1 = df1.sort_values(['Latitude','Longitude'], ascending = [1,1])
# (I'm starting with pandas df before GeoDataFrame conversion)
If we start from the "upper" point of previous picture following this sorting, the second point of DataFrame will be the nearest of it, etc... Until the fifth point, wich is on the right of the picture (so not the nearest anymore)...
So my question is : does someone know how achieve this special kind of sorting, or must I change my index manually ?
If I understand your question correctly, you want to rearrange the order of points in a way that they would create the shortest possible path.
I have run into the same problem also.
Here is the function that accepts regular dataframe (= with separate fields for each coordinate. I am sure you will be able to modify either function in order to accept geodataframe or dataframe in order to split geometry field into x and y fields.
def autoroute_points_df(points_df, x_col="e",y_col="n"):
'''
Function, that converts a list of random points into ordered points, searching for the shortest possible distance between the points.
Author: Marjan Moderc, 2016
'''
points_list = points_df[[x_col,y_col]].values.tolist()
# arrange points in by ascending Y or X
points_we = sorted(points_list, key=lambda x: x[0])
points_sn = sorted(points_list, key=lambda x: x[1])
# Calculate the general direction of points (North-South or West-East) - In order to decide where to start the path!
westmost_point = points_we[0]
eastmost_point = points_we[-1]
deltay = eastmost_point[1] - westmost_point[1]
deltax = eastmost_point[0] - westmost_point[0]
alfa = math.degrees(math.atan2(deltay, deltax))
azimut = (90 - alfa) % 360
# If main directon is towards east (45°-135°), take westmost point as starting line.
if (azimut > 45 and azimut < 135):
points_list = points_we
elif azimut > 180:
raise Exception("Error while computing the azimuth! It cant be bigger then 180 since first point is west and second is east.")
else:
points_list = points_sn
# Create output (ordered df) and populate it with the first one already.
ordered_points_df = pd.DataFrame(columns=points_df.columns)
ordered_points_df = ordered_points_df.append(points_df.ix[(points_df[x_col]==points_list[0][0]) & (points_df[y_col]==points_list[0][1])])
for iteration in range(0, len(points_list) - 1):
already_ordered = ordered_points_df[[x_col,y_col]].values.tolist()
current_point = already_ordered[-1] # current point
possible_candidates = [i for i in points_list if i not in already_ordered] # list of candidates
distance = 10000000000000000000000
best_candidate = None
for candidate in possible_candidates:
current_distance = Point(current_point).distance(Point(candidate))
if current_distance < distance:
best_candidate = candidate
distance = current_distance
ordered_points_df = ordered_points_df.append(points_df.ix[(points_df[x_col]==best_candidate[0]) & (points_df[y_col]==best_candidate[1])])
return ordered_points_df
Hope it solves your problem!

Categories

Resources