#!/usr/bin/env python
# coding: utf-8
TO DO NEXT:
Try last effort(described below) at making quartile legend. If that fails put the ugly-code matplotlib legend solution back in (it's hiding in the "copy".
To do:
Map Tiles
Scale
?side by side maps
point people towards the folium examples on github
Clean up code and what not
Write an intro (that includes the fact i'm looking for a job outside of teaching ASAP (but in portland):p)
Write prose to explain any complicated bit
Write conclusion about limitations
?Figure out how to deal with massive file sizes
Figure out how to get it to the web for sharing
# In[96]:
#Collin Reinking
#collin.reinking@berkeley.edu
import folium
get_ipython().run_line_magic('matplotlib', 'inline')
import pandas as pd
import re
import os
import branca.colormap as cm
import re
import numpy as np
#import matplotlib as mpl
#import matplotlib.pyplot as plt
#from matplotlib import colors
#from scipy import stats
# # Simple Dot Plot On Map
# In[2]:
data = pd.read_pickle('data/listings_cleaned.pkl')
data = pd.DataFrame(data, columns = ['latitude','longitude']) #[:50] <-this kind of slice is useful for developing a map
data.head()
# In[3]:
#create a map
this_map = folium.Map(prefer_canvas=True)
def plotDot(point):
'''input: series that contains a numeric named latitude and a numeric named longitude
this function creates a CircleMarker and adds it to your this_map'''
folium.CircleMarker(location=[point.latitude, point.longitude],
radius=2,
weight=0).add_to(this_map)
#use df.apply(,axis=1) to iterate through every row in your dataframe
data.apply(plotDot, axis = 1)
#Set the zoom to the maximum possible
this_map.fit_bounds(this_map.get_bounds())
#Save the map to an HTML file
#this_map.save(os.path.join('html_map_output/simple_dot_plot.html'))
this_map
# # Dots with Popup Info
# In[5]:
data = pd.read_pickle('data/listings_cleaned.pkl')
data = pd.DataFrame(data, columns = ['latitude','longitude','listing_name']) #[:50] <-this kind of slice is useful for developing a map
data.head()
# In[10]:
#create a map
this_map = folium.Map(prefer_canvas=True)
def plotDot(point):
'''input: series that contains a numeric named latitude and a numeric named longitude
this function creates a CircleMarker and adds it to your this_map'''
folium.CircleMarker(location=[point.latitude, point.longitude],
radius=2,
weight=0,#remove outline
popup = point.listing_name,
fill_color='#000000').add_to(this_map)
#use df.apply(,axis=1) to iterate through every row in your dataframe
data.apply(plotDot, axis = 1)
#Set the zoom to the maximum possible
this_map.fit_bounds(this_map.get_bounds())
#Save the map to an HTML file
#this_map.save(os.path.join('html_map_output/basic_pop_up.html'))
this_map
# # Popups with Links
# In[10]:
data = pd.read_pickle('data/listings_cleaned.pkl')
data = pd.DataFrame(data, columns = ['latitude','longitude','listing_name','listing_url','host_name','host_url'])[:50]# <-this kind of slice is useful for developing a map
data.head()
# In[12]:
#create a map
this_map = folium.Map(prefer_canvas=True)
def makeHref(url,link_text = None):
if link_text == None:
link_text = str(url)
return '' + re.sub(r"[']+", "\\\\'", link_text[:45]) +''
def popopHTMLString(point):
'''input: a series that contains a url somewhere in it and generate html'''
html = 'Listing: ' + makeHref(point.listing_url, point.listing_name) + '
'
html += 'Host: ' + makeHref(point.host_url, point.host_name)
return html
def plotDot(point):
'''input: series that contains a numeric named latitude and a numeric named longitude
this function creates a CircleMarker and adds it to your this_map'''
htmlString = folium.Html(popopHTMLString(point), script=True)
folium.CircleMarker(location=[point.latitude, point.longitude],
radius=2,
weight=0,#remove outline
popup = folium.Popup(htmlString),
fill_color='#000000').add_to(this_map)
#use df.apply(,axis=1) to iterate through every row in your dataframe
data.apply(plotDot, axis = 1)
#Set the zoom to the maximum possible
this_map.fit_bounds(this_map.get_bounds())
#Save the map to an HTML file
#this_map.save(os.path.join('html_map_output/html_pop_up.html'))
this_map
# # Color by value using a Colormap
# In[20]:
data = pd.read_pickle('data/listings_cleaned.pkl')
data = pd.DataFrame(data, columns = ['latitude','longitude','listed_price','accommodates'])[:50]# <-this kind of slice is useful for developing a map
data['price_per_person'] = data.listed_price / data.accommodates
data.drop(['listed_price','accommodates'], axis='columns', inplace=True)
data.head()
# In[16]:
blRd = cm.LinearColormap(['blue', 'red'],
vmin=3, vmax=10)
blRd
# In[97]:
#create a map
this_map = folium.Map(prefer_canvas=True)
#create a color map
color_var = 'price_per_person' #what variable will determine the color
cmap = cm.LinearColormap(['blue', 'red'],
vmin=data[color_var].quantile(0.05), vmax=data[color_var].quantile(0.95),
caption = color_var)
#Add the color map legend to your map
this_map.add_child(cmap)
def plotDot(point):
'''input: series that contains a numeric named latitude and a numeric named longitude
this function creates a CircleMarker and adds it to your this_map'''
folium.CircleMarker(location=[point.latitude, point.longitude],
fill_color=cmap(point[color_var]),
radius=2,
weight=0).add_to(this_map)
#use df.apply(,axis=1) to iterate through every row in your dataframe
data.apply(plotDot, axis = 1)
#Set the zoom to the maximum possible
this_map.fit_bounds(this_map.get_bounds())
#Save the map to an HTML file
#this_map.save(os.path.join('html_map_output/color_by_value.html'))
this_map
# # Color Points by quartile groupings
# In[98]:
data = pd.read_pickle('data/listings_cleaned.pkl')
data = pd.DataFrame(data, columns = ['latitude','longitude','listed_price','listing_name','listing_url','host_name','host_url'])
data.head()
# In[107]:
color_var = 'listed_price'
cmap = cm.LinearColormap(['cornflowerblue', 'limegreen', 'orange', 'red']
)
cmap = cmap.to_step(
n=4,
data=data[color_var],
method='quantiles')
cmap.caption = color_var + " grouped by quartile"
this_map = folium.Map(prefer_canvas=True)
this_map.add_child(cmap)
this_map
#As you can see there is a major limitation with this map:
#The data data in the color_var is so skewed that the 4th quartile
#completely dominates the legend.
# In[135]:
cmap_linear = cm.LinearColormap(['cornflowerblue', 'limegreen', 'orange', 'red'])
cmap = cmap_linear.to_step(
n=4,
data=data[color_var],
method='quantiles')
cmap_legend = cmap_linear.to_step(4)
cmap_legend.caption = color_var + " grouped by quartile"
this_map = folium.Map(prefer_canvas=True)
this_map.add_child(cmap_legend)
this_map
#this Makes the a well proportioned colorbar for the legend
#and you can still use cmap for the color map BUT...
#there is no way to change the labels on top
so the next solution to try to attempt is to create a proxy variable to reprsent the quartile that the color_var quartile and use that for color create the color bar AND color the point
# In[102]:
import pdir
pdir(cmap)
# In[25]:
#create a map
#this_map = folium.Map(prefer_canvas=True)
from matplotlib import colors
#create a color map
my_colors = [(.4, .4, 1), (0, .9, 0) ,(1, .6, 0) , (1, 0, 0)]
cm = colors.LinearSegmentedColormap.from_list("MyMap", my_colors, N=4) #cm is the color map
#norm = colors.Normalize(0, 1)
#color_dict = {data.ix[p][color_var]:colors.to_hex(cm(data.ix[p].color_group-.0001)) for p in data.T}
cm
# In[32]:
fig = plt.figure(figsize=(4, .1))
ax = fig.add_axes([1, 1, 1, 1])
leg = mpl.colorbar.ColorbarBase(ax, cmap=cm,
norm=norm,
orientation='horizontal')
leg.set_ticks([q/4 for q in range(5)])
leg.set_ticklabels([data[color_var].quantile(q/4) for q in range(5)])
fig.text(1.5, 2, color_var,
horizontalalignment='center',
verticalalignment='bottom')
fig.savefig(str('legends/legend_'+color_var+'_quartiles.png'), bbox_inches='tight',transparent=True)
#plt.close(fig)
#To DO: there has to be a smarter way to do this (dealing with the "URL" issue)
FloatImage(str(server_url + 'files/legends/legend_'+color_var+'_quartiles.png'),bottom=90, left=65).add_to(this_map)
# In[33]:
def popopHTMLString(point):
'''input: a series that contains a url somewhere in it and generate html'''
html = 'Listing: '
html += ''
html += re.sub(r"[']+", "\\\\'", point.listing_name) #to put a \ in front of any ' in the name
html += ' '
html += '
'
html += 'Host: '
html += ''
html += re.sub(r"[']+", "\\\\'", point.host_name)
html += ' '
html += '
'
html += 'listed_price = '
html += str('${:,.2f}'.format(point.listed_price))
return html
# In[34]:
def plotDot(point):
'''input: series that contains a numeric named latitude and a numeric named longitude
this function creates a CircleMarker and adds it to your this_map'''
htmlString = folium.Html(popopHTMLString(point), script=True)
folium.CircleMarker(location=[point.latitude, point.longitude],
fill_color=color_dict[point[color_var]], ####NOTE THE CHANGE IN THE COLOR
radius=2,
popup = folium.Popup(htmlString),
weight=0).add_to(this_map)
#use df.apply(,axis=1) to iterate through every row in your dataframe
data.apply(plotDot, axis = 1)
#Set the zoom to the maximum possible
this_map.fit_bounds(this_map.get_bounds())
#Save the map to an HTML file
#this_map.save(os.path.join('html_map_output/color_by_value_quartile.html'))
this_map