Skip to content

Instantly share code, notes, and snippets.

@lauraskelton
Created April 29, 2014 01:20
Show Gist options
  • Save lauraskelton/11388576 to your computer and use it in GitHub Desktop.
Save lauraskelton/11388576 to your computer and use it in GitHub Desktop.
Generates map of beers clustered together by user preferences based on similar ratings
from PIL import Image,ImageDraw,ImageFilter
from scipy import stats
import math
from math import sqrt
import copy
import operator
import pickle
import random
import ftplib
# Call this function to add every single beer to the beer cluster map with no pauses
# (note: with lots of beers and user ratings (I have over 200,000) this takes a very long time to run)
def clusterAllBeers():
loc,seedPrefs,allItemPrefs,sorted_controversy,realsim,realdist=createInitialBeerClusters()
totalBeersToAdd=len(allItemPrefs)-len(seedPrefs)
loc,seedPrefs=addMoreBeersToClusterMap(sorted_controversy,seedPrefs,allItemPrefs,realdist,realsim,loc,limit=totalBeersToAdd)
return loc,seedPrefs,allItemPrefs,sorted_controversy,realsim,realdist
# Call this function to create the initial beer map we will add other beers to
def createInitialBeerClusters(path='data'):
# Load beer names from file
beers={}
# example line from beernames.txt would be "967\tLagunitas IPA" (beerid,name)
for line in open(path+'/beernames.txt'):
(beerid,name)=line.split('\t')
beers[beerid]=name.rstrip()
# Load all beer ratings data from file
prefs={}
for line in open(path+'/beerratings.txt'):
(user,beerid,rating)=line.split(',')
prefs.setdefault(user,{})
prefs[user][beers[beerid]]=float(rating)
allItemPrefs={}
for user in prefs:
for beer in prefs[user]:
allItemPrefs.setdefault(beer,{})
# Flip beer and user
allItemPrefs[beer][user]=prefs[user][beer]
# Create a dictionary of each beer's similarity to every other beer
realsim={}
c=0
for beer in allItemPrefs:
# Status updates for large datasets
c+=1
if c%100==0:
print "%d / %d" % (c,len(allItemPrefs))
# Find the similarity of every beer to this one
realsim[beer]={}
for otherBeer in allItemPrefs:
realsim[beer][otherBeer]=float(sim_pearson_correlation(allItemPrefs,beer,otherBeer))
# Create a dictionary of each beer's distance from every other beer
realdist={}
c=0
for beer in allItemPrefs:
# Status updates for large datasets
c+=1
if c%100==0:
print "%d / %d" % (c,len(allItemPrefs))
# Find the distance from every beer to this one
realdist[beer]={}
for otherBeer in allItemPrefs:
realdist[beer][otherBeer]=float(sim_pearson_distance(allItemPrefs,beer,otherBeer))
# Find the most controversial beers (they are the most significant beers for creating a beer similarities diagram)
controversy={}
c=0
for beer in allItemPrefs:
controSum=0
num=0
for otherBeer in allItemPrefs:
# The most controversial beers (highly predictive beers) are those that have the strongest overall correlation values
# with other beers, either positively or negatively. So, if you love this beer, that tells me a lot about which other
# beers you'll love and/or which beers you'll hate.
controSum+=abs(realsim[beer][otherBeer])
num+=1
if num>0:
controversy[beer]=controSum/num
else:
controversy[beer]=0
# Gets a sorted array in descending order of all beers in order of how controversial they are
# (which means, how much information their ratings give you about what a user's other beer preferences are)
sorted_controversy=sorted(controversy.iteritems(), key=operator.itemgetter(1))
sorted_controversy.reverse()
# Get a dictionary of the 30 most controversial beers and their user ratings to seed the clustering algorithm
# (The clustering error is lower if we start with a few beers and find their relative positions,
# then add more beers to that initial diagram one by one)
seedBeers={}
seedPrefs={}
# Get names of the 30 most controversial beers
for x in range(30):
beer=sorted_controversy[x][0]
seedBeers[beer]=beer
# Get ratings data for each of the 30 most controversial beers from the dictionary of all beer ratings data we loaded earlier
for seedBeer in seedBeers:
seedPrefs[seedBeer]={}
seedPrefs[seedBeer]=allItemPrefs[seedBeer]
# Randomly initialize the starting points of the beer diagram locations for the seed beers in 2D
loc={}
for beer in seedPrefs:
loc[beer]=[random.random(),random.random()]
# Move each beer incrementally to approximate the distances the beers should be from each other
# based on their pearson distance calculation (how similar their ratings are)
loc=decreaseClusterError(loc,realdist,seedPrefs,rate=0.01,tries=200000)
# Move each beer one at a time to the weighted centerpoint of all of the most similar beers
# Then run the clustering algorithm again so that the resulting distances on the graph
# are close to the calculated pearson distances between each beer
# Repeat this over all of the beers a few times in case a beer jumps to another part of the graph
for m in range(3):
for beer in seedPrefs:
tmpPrefs=copy.deepcopy(seedPrefs)
del tmpPrefs[beer]
del loc[beer]
loc=addBeerAndRecluster(tmpPrefs,allItemPrefs,realdist,realsim,loc,beer)
# Create an image of the beer map and check to make sure that the clustering is working, and it makes sense
draw2d(loc,seedPrefs,png="initial_beer_clusters.png",scale=2000)
# Good idea to save since this takes awhile to calculate
pickle.dump(loc, open("pickle/initial_loc.p","wb"))
pickle.dump(seedPrefs, open("pickle/initial_seedprefs.p","wb"))
pickle.dump(allItemPrefs, open("pickle/initial_allitemprefs.p","wb"))
pickle.dump(sorted_controversy, open("pickle/initial_sorted_controversy.p","wb"))
pickle.dump(realsim, open("pickle/initial_realsim.p","wb"))
pickle.dump(realdist, open("pickle/initial_realdist.p","wb"))
return loc,seedPrefs,allItemPrefs,sorted_controversy,realsim,realdist
# Keep calling this function to add new beers a few at a time
def addMoreBeersToClusterMap(sorted_controversy,seedPrefs,allItemPrefs,realdist,realsim,loc,limit=10):
for x in range(limit):
loc,seedPrefs=addBeerToClusterMap(sorted_controversy,seedPrefs,allItemPrefs,realdist,realsim,loc)
print "added beer %d / %d" % (x+1,limit)
return loc,seedPrefs
# private methods--------------------------------------------------------------------------------->
def addBeerToClusterMap(sorted_controversy,seedPrefs,allItemPrefs,realdist,realsim,loc):
# Get the next index of the beer to add to the cluster
# (This is the next most controversial beer on the list)
newIndex=len(seedPrefs)
if newIndex < len(allItemPrefs):
beer=sorted_controversy[newIndex][0]
addBeerAndRecluster(seedPrefs,allItemPrefs,realdist,realsim,loc,beer)
# Draw an image of the current beer graph to see where this beer landed
if newIndex<100:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=2000)
elif newIndex<200:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=3000)
elif newIndex<400:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=4000)
elif newIndex<550:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=5000)
elif newIndex<700:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=6000)
elif newIndex<850:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=7000)
else:
draw2d(loc,seedPrefs,png="%d_beer_clusters.png" % (newIndex),scale=8000)
# Save the data structures just in case
pickle.dump(loc, open("pickle/%d_loc.p" % (newIndex),"wb"))
pickle.dump(seedPrefs, open("pickle/%d_seedprefs.p" % (newIndex),"wb"))
else:
print 'all beers have been added'
return loc,seedPrefs
def addBeerAndRecluster(seedPrefs,itemPrefs,realdist,realsim,loc,beer):
# adjust only this beer's position to match closest other seed beers
locSecondary={}
locSecondary[beer]={}
secondaryPrefs={}
secondaryPrefs[beer]={}
secondaryPrefs[beer]=itemPrefs[beer]
locSecondary[beer]=[0.0,0.0]
totalSim=0
# Sorted array of most similar beers to this one
simArray=sorted(realsim[beer].iteritems(), key=operator.itemgetter(1))
simArray.reverse()
for x in range(len(simArray)):
# See if this is a seed beer
simBeer=simArray[x][0]
if simBeer==beer: continue
if simBeer in seedPrefs:
if realsim[beer][simBeer]>0:
# weighted average of all similar beer locations for better starting point
# instead of the random starting point, will decrease the overall error of the beer diagram
locSecondary[beer][0]+=(loc[simBeer][0])*realsim[beer][simBeer]
locSecondary[beer][1]+=(loc[simBeer][1])*realsim[beer][simBeer]
totalSim+=realsim[beer][simBeer]
else: break
if totalSim>0:
locSecondary[beer][0]=(locSecondary[beer][0])/totalSim
locSecondary[beer][1]=(locSecondary[beer][1])/totalSim
locSecondary=decreaseClusterErrorForThisBeer(locSecondary,realdist,secondaryPrefs,seedPrefs,loc,rate=0.01,tries=10000)
seedPrefs[beer]={}
seedPrefs[beer]=itemPrefs[beer]
loc[beer]={}
loc[beer]=[locSecondary[beer][0],locSecondary[beer][1]]
loc=decreaseClusterError(loc,realdist,seedPrefs,rate=0.01,tries=500)
return loc
def decreaseClusterError(loc,realdist,itemPrefs,rate=0.01,tries=10000):
fakedist={}
grad={}
for beer in itemPrefs:
fakedist[beer]={}
for otherBeer in itemPrefs:
fakedist[beer][otherBeer]=[0.0]
for m in range(0,tries):
# Calculate the distance between each beer when they are at these coordinates ("fakedist")
for beer in itemPrefs:
for otherBeer in itemPrefs:
# calculate current distance by square root of sum of the squares of the changes in x and y coordinates
fakedist[beer][otherBeer]=sqrt(sum([pow(loc[beer][x]-loc[otherBeer][x],2) for x in range(len(loc[beer]))]))
# Move points
for beer in itemPrefs:
grad[beer]=[0.0,0.0]
totalerror=0
num=0
for beerK in itemPrefs:
for beerJ in itemPrefs:
if beerK==beerJ: continue
if realdist[beerK][beerJ]==-1: continue
# The errorterm is the difference between this current distance and what the distance should be, in ratio to the current distance
if fakedist[beerK][beerJ]!=0:
errorterm=(fakedist[beerK][beerJ]-realdist[beerK][beerJ])/fakedist[beerK][beerJ]
else:
errorterm=1
# Each point needs to be moved away from or towards the other
# point in proportion to how much error it has
if fakedist[beerK][beerJ]!=0:
grad[beerK][0]+=(loc[beerJ][0]-loc[beerK][0])*errorterm
grad[beerK][1]+=(loc[beerJ][1]-loc[beerK][1])*errorterm
# Keep track of the total error
totalerror+=pow(errorterm,2)
num+=1
if num>0:
totalerror = sqrt(totalerror)/num
# Status updates for large datasets
if (m+1)%500==0:
print "%d / %d with error: %f" % (m+1,tries,totalerror)
# Move each of the points by the learning rate times the gradient
for beerK in itemPrefs:
if num>0:
loc[beerK][0]+=rate*(grad[beerK][0]/num)
loc[beerK][1]+=rate*(grad[beerK][1]/num)
return loc
def decreaseClusterErrorForThisBeer(loc,realdist,secondaryPrefs,seedPrefs,locSeed,rate=0.01,tries=50):
fakedist={}
grad={}
for beer in secondaryPrefs:
fakedist[beer]={}
for otherBeer in seedPrefs:
fakedist[beer][otherBeer]=[0.0]
lasterror=None
for m in range(0,tries):
# Calculate the distance between each beer when they are at these coordinates ("fakedist")
for beer in secondaryPrefs:
for otherBeer in seedPrefs:
# calculate current distance by square root of sum of the squares of the changes in x and y coordinates
fakedist[beer][otherBeer]=sqrt(sum([pow(loc[beer][x]-locSeed[otherBeer][x],2) for x in range(len(loc[beer]))]))
# Move points
for beer in secondaryPrefs:
grad[beer]=[0.0,0.0]
totalerror=0
num=0
for beerK in secondaryPrefs:
for beerJ in seedPrefs:
if beerK==beerJ: continue
if realdist[beerK][beerJ]==-1: continue
# The errorterm is the difference between this current distance and what the distance should be, in ratio to the current distance
if fakedist[beerK][beerJ]!=0:
errorterm=(fakedist[beerK][beerJ]-realdist[beerK][beerJ])/fakedist[beerK][beerJ]
else:
errorterm=1
# Each point needs to be moved away from or towards the other
# point in proportion to how much error it has
if fakedist[beerK][beerJ]!=0:
grad[beerK][0]+=(locSeed[beerJ][0]-loc[beerK][0])*errorterm
grad[beerK][1]+=(locSeed[beerJ][1]-loc[beerK][1])*errorterm
# Keep track of the total error
totalerror+=pow(errorterm,2)
num+=1
if num>0:
totalerror = sqrt(totalerror)/num
# Status updates for large datasets
#if (m+1)%10000==0:
#print "%d / %d with error: %f" % (m,tries,totalerror)
#print "error: %f" % (totalerror)
# Move each of the points by the learning rate times the gradient
for beerK in secondaryPrefs:
if num>0:
loc[beerK][0]+=rate*(grad[beerK][0]/num)
loc[beerK][1]+=rate*(grad[beerK][1]/num)
return loc
# Draw the beer clusters
def draw2d(loc,itemPrefs,png='l_beerclusters2d.png', scale=2500):
img=Image.new('RGB',(scale,scale),(255,255,255))
draw=ImageDraw.Draw(img)
for beer in itemPrefs:
x=((loc[beer][0]+0.5)*0.8)*scale/2
y=((loc[beer][1]+0.5)*0.8)*scale/2
draw.text((x,y),beer,(0,0,0))
img.save('images/'+png,'PNG')
def sim_pearson_distance(itemPrefs,beer1name,beer2name):
beer1Data = itemPrefs[beer1name]
beer2Data = itemPrefs[beer2name]
x = []
y = []
for user in beer1Data:
if beer2Data.has_key(user):
x.append(beer1Data[user])
y.append(beer2Data[user])
# Find the number of elements
n=len(x)
# If they have no ratings in common, return -1 (which we will ignore in our distance calculations later)
if n<2: return -1
pearson_correlation=stats.pearsonr(x, y)[0]
if math.isnan(pearson_correlation):
# return -1 (which we will ignore in our distance calculations later)
return -1
# Greater correlation means smaller distance apart, and distances should be positive (pearson_correlation ranges from -1 to 1)
return 1-pearson_correlation
def sim_pearson_correlation(itemPrefs,beer1name,beer2name):
beer1Data = itemPrefs[beer1name]
beer2Data = itemPrefs[beer2name]
x = []
y = []
for user in beer1Data:
if beer2Data.has_key(user):
x.append(beer1Data[user])
y.append(beer2Data[user])
# Find the number of elements
n=len(x)
# If they have no ratings in common, return 0 (they are not correlated)
if n<2: return 0
pearson_correlation=stats.pearsonr(x, y)[0]
if math.isnan(pearson_correlation):
# return 0 (they are not correlated)
return 0
return pearson_correlation
# Beer Mapping -------------------------------------------------------------------------------------------------------------------->
# Calculate beer similarity and beer distance between all beers
def loadDistAndSim(allItemPrefs):
# Create a dictionary of each beer's similarity to every other beer
realsim={}
c=0
for beer in allItemPrefs:
# Status updates for large datasets
c+=1
if c%100==0:
print "%d / %d" % (c,len(allItemPrefs))
# Find the similarity of every beer to this one
realsim[beer]={}
for otherBeer in allItemPrefs:
realsim[beer][otherBeer]=float(sim_pearson_correlation(allItemPrefs,beer,otherBeer))
# Create a dictionary of each beer's distance from every other beer
realdist={}
c=0
for beer in allItemPrefs:
# Status updates for large datasets
c+=1
if c%100==0:
print "%d / %d" % (c,len(allItemPrefs))
# Find the distance from every beer to this one
realdist[beer]={}
for otherBeer in allItemPrefs:
realdist[beer][otherBeer]=float(sim_pearson_distance(allItemPrefs,beer,otherBeer))
pickle.dump(realsim, open("pickle/realsim.p","wb"))
pickle.dump(realdist, open("pickle/realdist.p","wb"))
return realsim,realdist
# Load ABV data for each beer
def loadABV(path='data'):
# example line from beerabv.txt would be "Lagunitas IPA\t5.7" (beer,abv)
abvData={}
for line in open(path+'/beerabv.txt'):
(name,abv)=line.split('\t')
beer=name.rstrip()
abvData[beer]=float(abv)
return abvData
# Load IBU data for each beer
def loadIBU(path='data'):
# example line from beeribu.txt would be "Lagunitas IPA\t46" (beer,ibu)
ibuData={}
for line in open(path+'/beeribu.txt'):
(name,ibu)=line.split('\t')
beer=name.rstrip()
if ibu.rstrip() == 'NULL':
ibuData[beer]=float(0)
else:
ibuData[beer]=float(ibu)
return ibuData
# Load Specific Gravity data for each beer (relates to how sweet/thick the beer is)
def loadGravity(path='data'):
# example line from beergravity.txt would be "Lagunitas IPA\t1.014" (beer,gravity)
gravityData={}
for line in open(path+'/beergravity.txt'):
(name,gravity)=line.split('\t')
beer=name.rstrip()
if gravity.rstrip() == 'NULL':
gravityData[beer]=float(0)
else:
gravityData[beer]=float(gravity)
return gravityData
# Load beer style information for each beer
def loadStyle(path='data'):
# example line from beerstyle.txt would be "Lagunitas IPA\tAmerican IPA" (beer,style)
styleData={}
for line in open(path+'/beerstyle.txt'):
(name,style)=line.split('\t')
beer=name.rstrip()
if style.rstrip() == 'NULL':
styleData[beer]=str('')
else:
styleData[beer]=str(style.rstrip())
return styleData
def loadBeerData():
# Reload data from save point
loc=pickle.load(open("pickle/loc.p","rb"))
itemPrefs=pickle.load(open("pickle/itemprefs.p","rb"))
realsim=pickle.load(open("pickle/realsim.p","rb"))
realdist=pickle.load(open("pickle/realdist.p","rb"))
abv=loadABV()
ibu=loadIBU()
gravity=loadGravity()
style=loadStyle()
return loc,itemPrefs,realsim,realdist,abv,ibu,gravity,style
# Create and upload new beer map to server with optional ABV and IBU coloring
def makeGoogleBeerMap(loc,itemPrefs,style,abv=None,ibu=None):
out=open('data/beergmap.html','w')
out.write('<!DOCTYPE html>\n')
out.write('<html>\n')
out.write('\t<head>\n')
out.write('\t\t<title>Beer Map</title>\n')
out.write('\t\t<style>\n')
out.write('\t\t\thtml, body, #map-canvas {\n')
out.write('\t\t\t\theight: 100%;\n')
out.write('\t\t\t\tmargin: 0px;\n')
out.write('\t\t\t\tpadding: 0px\n')
out.write('\t\t\t}\n')
out.write('\t\t</style>\n')
out.write('\t\t<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>\n')
out.write('\t\t<script type="text/javascript" src="../beermap/infobox.js"></script>\n')
out.write('\t\t<script>\n')
out.write('\n')
out.write('function CoordMapType() {\n')
out.write('}\n')
out.write('\n')
out.write('CoordMapType.prototype.tileSize = new google.maps.Size(256,256);\n')
out.write('CoordMapType.prototype.maxZoom = 11;\n')
out.write('CoordMapType.prototype.minZoom = 5;\n')
out.write('\n')
out.write('CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {\n')
out.write('\tvar div = ownerDocument.createElement(\'div\');\n')
out.write('\tdiv.innerHTML = \'\';\n')
out.write('\tdiv.style.width = this.tileSize.width + \'px\';\n')
out.write('\tdiv.style.height = this.tileSize.height + \'px\';\n')
out.write('\tdiv.style.fontSize = \'10\';\n')
out.write('\tdiv.style.borderStyle = \'none\';\n')
out.write('\tdiv.style.backgroundColor = \'#E5E3DF\';\n')
out.write('\treturn div;\n')
out.write('};\n')
out.write('\n')
out.write('CoordMapType.prototype.name = \'Beer\';\n')
out.write('CoordMapType.prototype.alt = \'Beer Map Type\';\n')
out.write('\n')
out.write('var map;\n')
out.write('var coordinateMapType = new CoordMapType();\n')
out.write('\n')
out.write('var beerMapData = [\n')
for beer in itemPrefs:
out.write('\t{latitude: '+str(float((loc[beer][0])*15))+', ')
out.write('longitude: '+str(float((loc[beer][1])*15))+', ')
out.write('title: "'+str(beer)+'", ')
out.write('description: "'+str(style[beer].replace("&","and"))+'",')
rA=255
gA=255
bA=255
if abv!=None:
rA=126
gA=200
bA=252
if abv[beer] < 10 and abv[beer] > 4:
rA=int(((6-(abv[beer]-4))/6)*(255-rA)+rA)
gA=int(((6-(abv[beer]-4))/6)*(255-gA)+gA)
bA=int(((6-(abv[beer]-4))/6)*(255-bA)+bA)
elif abv[beer] <= 4:
rA=255
gA=255
bA=255
rI=255
gI=255
bI=255
if ibu!=None:
rI=231
gI=252
bI=126
if ibu[beer] < 80 and ibu[beer] > 10:
rI=int(((70-(ibu[beer]-10))/70)*(255-rI)+rI)
gI=int(((70-(ibu[beer]-10))/70)*(255-gI)+gI)
bI=int(((70-(ibu[beer]-10))/70)*(255-bI)+bI)
elif ibu[beer] <= 10:
rI=255
gI=255
bI=255
r=(rA+rI)-255
g=(gA+gI)-255
b=(bA+bI)-255
out.write('color: "rgb('+str(r)+','+str(g)+','+str(b)+')"},')
out.write('\n')
out.write('];\n')
out.write('\n')
out.write('var mapCenter = new google.maps.LatLng(11.9807276122, 4.99151301465);\n')
out.write('\n')
out.write('function initialize() {\n')
out.write('\tvar mapOptions = {\n')
out.write('\t\tzoom: 5,\n')
out.write('\t\tcenter: mapCenter,\n')
out.write('\t\tstreetViewControl: false,\n')
out.write('\t\tmapTypeId: \'coordinate\',\n')
out.write('\t\tmapTypeControlOptions: {\n')
out.write('\t\t\tmapTypeIds: [\'coordinate\'],\n')
out.write('\t\t\tstyle: google.maps.MapTypeControlStyle.DROPDOWN_MENU\n')
out.write('\t\t}\n')
out.write('\t};\n')
out.write('\tmap = new google.maps.Map(document.getElementById(\'map-canvas\'),mapOptions);\n')
out.write('\n')
out.write('\tfor (var i=0;i<beerMapData.length;i++)\n')
out.write('\t{\n')
out.write('\t\tvar myOptions = {\n')
out.write('\t\t\tcontent: beerMapData[i][\'title\']+"<br/>("+beerMapData[i][\'description\']+")"\n')
out.write('\t\t\t,boxStyle: {\n')
out.write('\t\t\t\tborder: "1px solid black"\n')
out.write('\t\t\t\t,textAlign: "center"\n')
out.write('\t\t\t\t,fontSize: "6pt"\n')
out.write('\t\t\t\t,width: "60px"\n')
out.write('\t\t\t\t,backgroundColor: beerMapData[i][\'color\']\n')
out.write('\t\t\t}\n')
out.write('\t\t\t,disableAutoPan: true\n')
out.write('\t\t\t,pixelOffset: new google.maps.Size(-25, 0)\n')
out.write('\t\t\t,position: new google.maps.LatLng(beerMapData[i][\'latitude\'], beerMapData[i][\'longitude\'])\n')
out.write('\t\t\t,closeBoxURL: ""\n')
out.write('\t\t\t,isHidden: false\n')
out.write('\t\t\t,pane: "mapPane"\n')
out.write('\t\t\t,enableEventPropagation: true\n')
out.write('\t\t};\n')
out.write('\t\tvar ibLabel = new InfoBox(myOptions);\n')
out.write('\t\tibLabel.open(map);\n')
out.write('\t}\n')
out.write('\n')
out.write('map.mapTypes.set(\'coordinate\', coordinateMapType);\n')
out.write('}\n')
out.write('\n')
out.write('google.maps.event.addDomListener(window, \'load\', initialize);\n')
out.write('\n')
out.write('\t\t</script>\n')
out.write('\t</head>\n')
out.write('\t<body>\n')
out.write('\t\t<div id="map-canvas"></div>\n')
out.write('\t</body>\n')
out.write('</html>\n')
out.close()
username=raw_input("Enter FTP username: ")
password=raw_input("Enter FTP password: ")
session = ftplib.FTP('www.beerchooser.com',username,password)
file = open('data/beergmap.html','rb') # file to send
session.storbinary('STOR beermap/beergmap.html', file) # send the file
file.close() # close file and FTP
session.quit()
print 'gmap uploaded'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment