I was on reddit one day looking at Data is beautiful subreddit, and i came across a post by Geoff Boeing about mapping every place that he’s ever been in his life. And i thought this was cool and something i’d like to try to code my self. In his example he shows how he got the data from Google and Foursquare. I didn’t want to start in the same place so i’ve decided to start with my Photos. For the last 6-7 years every camera i’ve own has had built in GPS and my Phone all have GPS as well. So i have plenty of data to start with.
Before we look in to the code here is what the end product looks like. And here a web version that can be played with
First Getting the Exif data out of a JPG
There is a great Package for this called ExifRead which you can install here. I created the function read_image, which get the data we needs.
First we check to see if the image is a JPG or not, if it not we skip it. Next we try to see if it has the 4 variables that we need. The Latitude, Longitude and Direction for each (N,S or W,E). We then return a string in the following format longitude,Latitude. I use this as a key for my dictionary so that we only plot each location once
def read_image(image, full_path): """ Read an Image, and get the EXIF data that include the GPS data """ with open(os.path.join(full_path, image), 'rb') as f: if image.find('JPG') == -1: return tags = exifread.process_file(f) try: lat = tags['GPS GPSLatitude'] long = tags['GPS GPSLongitude'] lat_directions = tags['GPS GPSLatitudeRef'] long_direction = tags['GPS GPSLongitudeRef'] lat_degree = convert_to_degree(lat) if str(lat_directions) == "S": lat_degree = -lat_degree long_degree = convert_to_degree(long) if str(long_direction) == "W": long_degree = -long_degree return str(long_degree) + ',' + str(lat_degree) except: return
For my Sony Cybershot, and my current iPhone both store the Latitude and Longitude in the following format. Degree Minute Second\
Degree + Minute\60 + (second\
In my code i also round to 4 decimal places. Which greatly cut the number of point drop, The closest point can be at this point is roughly 1 meter, which for this map is still way way more than we need.
def convert_to_degree(number): """ Takes a Degree in the Degree min second format and covert it to a decimal """ #convert from IfdTag to a string so we can parse it number = str(number) #Remove  from the ends number = number[1:-1] degree, min, sec = number.split(',') s_t, s_b = sec.split('/') sec = (float(s_t) / float(s_b)) / 3600 dd = Decimal(degree) + Decimal(min)/60 + Decimal(sec) #Limit us to 4 places after the point dd = round(dd, 4) return dd
The last 2 function in the code just put everything together.
Create_GeoJson create the json file needed by Leaflet (the mapping software i’m using)
Get_photos which goes in to an iphoto library and find all the photos