Pandas: Passing format options into functions - python

I want to extract coordinates from postcodes as a new df column.
The functionality from the geopy module is:
from geopy.geocoders import Nominatim
geolocator = Nominatim()
location = geolocator.geocode('%s tn6 3rn')
print((location.latitude, location.longitude))
(51.0459837, 0.2192646)
My function to apply to this to a single value works:
def pcodeToCoor(x):
geolocator = Nominatim()
location = geolocator.geocode(x)
return ((location.latitude, location.longitude))
pcodeToCoor('%s tn6 3rn')
(51.0459837, 0.2192646)
But when passing the function to a test df:
name postcode
0 jd tn6 3rn
1 hf en6 1dg
2 ss sw17 0ju
df['coordinate'] = df['postcode'].map(pcodeToCoor)
I get AttributeError: 'NoneType' object has no attribute 'latitude. Note I can recreate this error by removing %s from the basic api functionality.
The question is, how do I use %s in my function? I imagine the answer's very simple but nothing I've tried works!

You could do something like this if you are going to use this function consistently this way, or you code code a check to see if your string starts with "%s".
def pcodeToCoor(x):
geolocator = Nominatim()
location = geolocator.geocode('%s '+x)
return ((location.latitude, location.longitude))
Edit:
def pcodeToCoor(x):
if x[0:2] != '%s':
x = '%s ' + x
geolocator = Nominatim()
location = geolocator.geocode(x)
return ((location.latitude, location.longitude))
Test:
pcodeToCoor('%s tn6 3rn')
Output:
(51.0459837, 0.2192646)
Test 2:
df['postcode'].map(pcodeToCoor)
Output:
0 (51.0459837, 0.2192646)
1 (51.7206134, -0.2042041)
2 (51.3866947, -0.1800573)
Name: postcode, dtype: object

Related

Conditional-based geolocator in Python

I am working on the Nominatim geolocator in Python. Unfortunately, some addresses are missing, therefore I tried to make some condition-based workaround, which would allow executing something based at least on postcode, which works well in any case.
Unfortunately, I failed for now. With the following code:
import pandas as pd
import folium
import web-browser
from geopy.geocoders import Nominatim
geolocator = Nominatim(timeout=10, user_agent="Krukarius")
def find_location(row):
place = row['Address']
place_data = newstr = place[-8:]
location = geolocator.geocode(place)
location_overall = geolocator.geocode(place_data)
if location != None:
return location.latitude, location.longitude
else:
#return 0,0
return location_overall
points = pd.read_csv("Addresses4.csv")
points[['Lat','Lng']] = points.apply(find_location, axis="columns", result_type="expand")
print(points)
points.to_csv('NewAddresses4.csv')
ValueError: Location should consist of two numerical values, but '' of type <class 'str'> is not convertible to float.
def find_location(row):
place = row['Address']
place_data = newstr = place[-8:]
location = geolocator.geocode(place)
location_overall = geolocator.geocode(place_data)
if location is not None:
return location.latitude, location.longitude
elif location_overall is not None:
return location_overall.latitude, location_overall.longitude
else:
return None, None
the if block returns the latitude and longitude of the location object if it's not None. The elif block returns the latitude and longitude of the location_overall object if it's not None. Finally, the else block returns None, None if neither location nor location_overall are available.
I think I sorted it out on my own.
The code should exactly look like this:
def find_location(row):
place = row['Address']
place_data = newstr = place[-8:]
location = geolocator.geocode(place)
location_overall = geolocator.geocode(place_data)
if location != None:
return location.latitude, location.longitude
else:
return location_overall.latitude, location_overall.longitude
where instead of the first condition, we should call another one.

Why is my program returning result AttributeError: 'NoneType' object has no attribute 'longitude'

I am trying to make a weather app. I am using this code
def getWeather():
city = textfield.get
geolocator = Nominatim(user_agent="geoapiExercises")
location = geolocator.geocode(city)
obj = TimezoneFinder()
result = obj.timezone_at(lng = location.longitude,lat = location.latitude)
print(result)
I was attempting to input a city and get where the city. Instead i get the afformentioned error. Ty for any help

list iterating exception so the loop keeps going, geocode

I have a list of place names and I want to iterate over it to get the coordinates:
import time
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="xxx")
for a in pl:
location = geolocator.geocode(a)
print(location.latitude)
time.sleep(2)
Now it works for the first few entries, then I get the following error:
AttributeError: 'NoneType' object has no attribute 'latitude'
I assume that that particular entry is not in a format that can be interpreted. How can I make my loop go on in those cases and just leave the entry black for these one, or just delete the entry outright.
You can check if location is not None, and then only get the latitude attribute from it
import time
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="xxx")
for a in pl:
location = geolocator.geocode(a)
#If location is not None, print latitude
if location:
print(location.latitude)
time.sleep(2)
Wrap the access to location.latitude inside a try/except block:
for a in pl:
location = geolocator.geocode(a)
try:
print(location.latitude)
except AttributeError:
print('Skipping bad location...')
time.sleep(2)

getting distance between two location using geocoding

I want to find the distance between two location using google API. I want output to be look like - "The distance between location 1 and location 2 is 500 miles ( distance here is example purposes )", but how can i get the desired output as the current program is showing various output ( which i cant use to get he desired output ) . can you guys please show me the way or show me what is the exact procedure to do it?
import urllib
import json
serviceurl = 'http://maps.googleapis.com/maps/api/geocode/json?'
while True:
address = raw_input('Enter location: ')
if len(address) < 1 : break
url = serviceurl + urllib.urlencode({'sensor':'false', 'address': address})
print 'Retrieving', url
uh = urllib.urlopen(url)
data = uh.read()
print 'Retrieved',len(data),'characters'
try: js = json.loads(str(data))
except: js = None
if 'status' not in js or js['status'] != 'OK':
print '==== Failure To Retrieve ===='
print data
continue
print json.dumps(js, indent=4)
lat = js["results"][0]["geometry"]["location"]["lat"]
lng = js["results"][0]["geometry"]["location"]["lng"]
print 'lat',lat,'lng',lng
location = js['results'][0]['formatted_address']
print location
Google has a specific api for that, it's called Google Maps Distance Matrix API.
Distance & duration for multiple destinations and transport modes.
Retrieve duration and distance values based on the recommended route
between start and end points.
If you just need the distance between two points on the globe you may want to use the Haversine formula
If you know lat and lon, use the geopy package:
In [1]: from geopy.distance import great_circle
In [2]: newport_ri = (41.49008, -71.312796)
In [3]: cleveland_oh = (41.499498, -81.695391)
In [4]: great_circle(newport_ri, cleveland_oh).kilometers
Out[4]: 864.4567616296598

How to get Address from Latitude & Longitude in Django GeoIP?

I cannot see anything in their API to do this:
https://docs.djangoproject.com/en/dev/ref/contrib/gis/geoip/#geoip-api
Or should I just use Google API for Reverse Geocoding?
Solution - call this URL and parse it's JSON.
http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=false
Use geopy, it can handle multiple geocoders including googlev3.
from geopy.geocoders import GoogleV3
geolocator = GoogleV3()
location = geolocator.reverse("52.509669, 13.376294")
print(location.address)
>>> Potsdamer Platz, Mitte, Berlin, 10117, Deutschland, European Union
install with pip:
pip install geopy
infos found on: https://github.com/geopy/geopy
You can use maps API. I've included a snippet which I use to calculate marathon start points converted into a PointField using Postgis with Django. This should set you on your way.
import requests
def geocode(data):
url_list = []
for item in data:
address = ('%s+%s' % (item.city, item.country)).replace(' ', '+')
url = 'http://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false' % address
url_list.append([item.pk, url])
json_results = []
for url in url_list:
r = requests.get(url[1])
json_results.append([url[0], r.json])
result_list = []
for result in json_results:
if result[1]['status'] == 'OK':
lat = float(result[1]['results'][0]['geometry']['location']['lat'])
lng = float(result[1]['results'][0]['geometry']['location']['lng'])
marathon = Marathon.objects.get(pk=result[0])
marathon.point = GEOSGeometry('POINT(%s %s)' % (lng, lat))
marathon.save()
return result_list
#rawsix answer seems smart for a django user.
Note however that the location returned by geolocator.reverse(query) is a list and not a Location object; so attempting to retrieve attribute address from it would result in an error.
Usually, the first item in that list has the closest address information. so u can simply do:
location = location[0]
address = location.address
Additionally, instead of passing a string latitude and longitude to the reverse method, you can use a tuple and it must be the latitude before the longitude. You can do:
from geopy.geocoders import GoogleV3()
geocoder = GoogleV3()
location_list = geocoder.reverse((latitude, longitude))
location = location_list[0]
address = location.address

Categories