Bringing a friends idea to life:

Finding the middle ground for our next vacation with Django and Python

Thomas Bacas
Analytics Vidhya
Published in
7 min readApr 17, 2020

--

This morning started like any other in the world of COVID-19 quarantine. I had just walked my dog Toby, started on my cup of coffee and I was running my morning queries to refresh a report I do daily for work. After my standard morning meetings I drifted off looking out the window thinking back to a time when simply going outside wasn’t seemingly dangerous. It was then I got a call from my friend Boyd for a standard check in. You see, after college all of my friends moved all over the country. I had one in Spartanburg SC, another in Cincinnati OH, two in Charleston SC and others spread out in New York, San Francisco, Boston. I asked Boyd “What’s your plans when Corona has run its course?”, “We should all get together” he said. But where? Traveling to Charleston seems simple because its where Boyd and another college roommate live, but that’s a far trip for all of us besides them. “Why don’t we just get a cabin or something in the dead middle of everyone so its fair” Boyd told me. What a great idea. Let’s find the middle ground between all of us and just find an Airbnb there…

We talked briefly about how mathematically we could determine a centroid between varying different points. I told Boyd, after work — I’m going to try this in Python to make things simple. Thus spawned my homebrew Hackathon… a few hours after work and I had stood up a functional webapp that looked like this:

Here is a demo of my website called (tentatively) FindMid!

I leveraged many open source libraries and the very helpful googlemaps api to achieve the above result. It was a fun challenge to get all of the pieces working together, but in the end I was very happy with the result. And yes, before you criticize my terrible UX let me say, I am not a UX designer. I’m a data scientist and avid python programmer with a bit of Django experience. If I had it my way I’d pass this along to someone with much better HTML,CSS and JS skills.

Lets start with the libraries:

from uszipcode import SearchEngine
import wikipedia
import gmplot
import numpy as np
import matplotlib.pyplot as plt
import datetime
import os

uszipcode: https://github.com/seanpianka/zipcodes

“Zipcodes is a package for Python 3 and Python 2.7 which supports lookup and filtering of zipcode data for the U.S.”

I used uszipcode to pull down long/latitudes of my various scatter points. By passing city and state name, I’m able to take the zip-codes generated from the search engine and pull down respective longitude and latitude data.

wikipedia: https://github.com/goldsmith/Wikipedia

“Wikipedia is a Python library that makes it easy to access and parse data from Wikipedia.

Search Wikipedia, get article summaries, get data like links and images from a page, and more. Wikipedia wraps the MediaWiki API so you can focus on using Wikipedia data, not getting it.”

My utilization of the wikipedia api may not be immediately recognizable, but I used it to grab a quick summary of each midpoint town. When a town is generated I pass the city/state data to the wikipedia search to generate a one sentence summary for the website.

gmplot: https://github.com/vgm64/gmplot

“Plotting data on Google Maps, the easy way. A matplotlib-like interface to generate the HTML and javascript to render all the data you’d like on top of Google Maps. Several plotting methods make creating exploratory map views effortless. Here’s a crash course:”

Gmplot did the majority of the heavy lifting, with my experience in matplotlib it made things simple to create and plot the various lines and points.

I started out my development process by establishing the logic for my center point. I went with a simple centroid formula.

I went with something simple for the sake of time and this seemed to get the job done. I started by populating some random numbers for my lat, long then trying the average distance to the centroid to get a sense of the results. Afterward I plugged it into the backend of my django webapp (I wont be covering the basics of starting a django webapp but I’m happy to point to some good resources)

points =[]
search = SearchEngine()
cities = request.POST.getlist('feedurl[]')
states = request.POST.getlist('feedurl[1]')

for i in range(len(cities)):
result = search.by_city_and_state(cities[i],states[i])
points.append([result[0].lat,result[0].lng])
final_x = sum([x[0] for x in points])/ len(points)
final_y = sum([y[1] for y in points])/ len(points)

By utilizing the request.POST.getlist() I would retrieve two populated lists of cities and states that I could use to search via uszipcode SearchEngine() function. The result of this search would contain lat/long and a variety of other data points which can be helpful but I didn’t end up using for this project. The lists would look like this:

[[lat1,long1],[lat2,long2],[lat3,long3],...]

With this list I can determine our centroid. GREAT! but now what…

result = search.by_coordinates(final_x,final_y)

Lets plug those new data points into the SearchEngine() function again and find out where we ended up. In the demo above — that was Jonesville, NC. I’ve never been to Jonesville, but I’ve been through North Carolina and the state is beautiful. Maybe we’ll end up going there after all? Who knows. Now we have a City and a State with which I can get some information from wikipedia..

wikipedia.summary(result[0].city+', '+result[0].state, sentences=1)

Our result from this API call gives us the short blurb under the midpoint announcement on the webpage. With the same above variables it was a simple adjustment to the Airbnb url, changing the date and City/State name to our above variables then passing that back to the django template. Voila, Airbnb data for the mid point in question.

With those done lets plot our points on GoogleMaps. Important note, Google requires an API key for utilizing gmaps properly. You do need to register a credit card but your API calls are free for your first 100,000 static map calls. For a small fun project for my friends it was no problem, but scaling up to commercialization this would be a consideration.

gmap = gmplot.GoogleMapPlotter(final_x,
final_y, zoom =5, apikey=**yourkey**)
gmap.scatter([x[0] for x in points], [y[1] for y in points], size = 10000, color = 'red', marker=False)
gmap.scatter([final_x],[final_y], size = 10000, color = 'blue', marker=False)

We instantiate our map centered around our centroid with the two lat/long points, I found that zoom 5 was appropriate for the US map but that is up to your use case. This is also where you would supply your API key.

With the gmap instantiated I began mapping our Origin/Destination points. Like before, I used list comprehension to pass the lat/longs from our list to generate our Origin points, then I passed our centroid lat/long as single item lists (the scatter function requires an iterable).

gmap.plot([x[0] for x in points], [y[1] for y in points])
gmap.draw('findmid/media/map.html')

Now we plot the lines between each origin and our destination. Gmplot does a great job making these lines, its super simple and you can customize a decent amount. The last step… we create our html file.

All of the pieces are here, let’s get these on a front-end framework. Below is the HTML template that Django calls to populate the page. Since all of the variables are empty until we post data to the frontend I could tag them directly into the HTML with little effect. The exception was the airbnb link, which I put behind a simple if statement.

<style>
.feed {padding: 5px 0}
</style>
<!-- onsubmit="return validate(this)" -->
<form method="post">
{% csrf_token %}
<table>
<tr>
<td valign=top>
<div id="newlink">
<div class="feed">
<input type="text" name="feedurl[]" size="50">
<input type="text" name="feedurl[1]" size="2">
</div>
<div class="feed">
<input type="text" name="feedurl[]" size="50">
<input type="text" name="feedurl[1]" size="2">
</div>
</div>
</td>
</tr>
</table>
<p>
<br>
<input type="submit" name="submit1">
</p>
<p id="addnew">
<a href="javascript:add_feed()">Add New </a>
</p>
</form>
<h1>
{{ midpoint }}
</h1>
{{ wiki }}
<br>
{% if airbnb != '' %}
<a href = "{{ airbnb }}"> See options for stays in the are</a>
{% endif %}
<br>
<hr>
{{ map | safe}}
<!-- Template. This whole data will be added directly to working form above -->
<div id="newlinktpl" style="display:none">
<div class="feed">
<input type="text" name="feedurl[]" value="" size="50">
<input type="text" name="feedurl[1]" size="2">
</div>
</div>
<script type="text/javascript">
function validate(frm)
{
var ele = frm.elements['feedurl[]'];
if (! ele.length)
{
alert(ele.value);
}
for(var i=0; i<ele.length; i++)
{
alert(ele[i].value);
}
return true;
}
function add_feed()
{
var div1 = document.createElement('div');
// Get template data
div1.innerHTML = document.getElementById('newlinktpl').innerHTML;
// append to our form, so that template data
//become part of form
document.getElementById('newlink').appendChild(div1);
}
</script>

With that, I launched the Django server and it was functional!

Woof, what a ride. I’m trying to get this all done on the same day so its still fresh and the context of a hackathon doesn't seem fair coming back two days afterward. I’m putting pen to paper ASAP so I can channel the frantic prototyping this project became. I had a lot of fun with this project and others like this, its a great opportunity to hone some skills and pick up new ones as you go along. A lot of the tools I used today I had never seen before; GMAP, Wiki, USZIP were all new libraries to me. It speaks to what you can do with a bit a perseverance and creativity. Thanks for reading (sorry for any bad grammar), I’ll be uploading the code to my public github in the next few days: https://github.com/tbacas

-TRB

--

--