I want to include the open street map (OSM) in my python code.
I have read through lots of webpages regarding to OSM. But unfortunately I\'m a bit lost, regarding wh
Edit: OpenStreetMap states that their tile servers are not free to use and are under a usage policy:
https://operations.osmfoundation.org/policies/tiles/
Please read this before using the example.
As I had problems implementing the code in Python 3.8, I merged a few of the answers together and modified the code. Now it works for me and I don't get any errors.
When I tried to run the original code from BerndGit in Python 3, I had to make the same changes as Joining Dots described in his answer. I replaced
import urllib2
import StringIO
with
import requests
from io import BytesIO
because the urllib2 library doesn't work with Python 3 anymore. You have to use urllib.request or requests.
Then I had to change these two lines from the getImageCluster function
imgstr = urllib2.urlopen(imgurl).read()
tile = Image.open(StringIO.StringIO(imgstr))
to
imgstr = requests.get(imgurl)
tile = Image.open(BytesIO(imgstr.content))
After that I could run the code without errors but it still couldn't download the images. I always got a black tile as a result. Through some research I learned, that it is important to fake a user agent while using requests, as the website could tell that the request is coming from Python and may block it. The following website describes this:
https://www.scrapehero.com/how-to-fake-and-rotate-user-agents-using-python-3/
So I followed the suggestions from the website which resulted in adding this line right at the beginning of the getImageCluster function:
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
Now we need to include these headers into the requests call:
imgstr = requests.get(imgurl, headers=headers)
The whole code looks like this now:
import matplotlib.pyplot as plt
import numpy as np
import math
import requests
from io import BytesIO
from PIL import Image
def deg2num(lat_deg, lon_deg, zoom):
lat_rad = math.radians(lat_deg)
n = 2.0 ** zoom
xtile = int((lon_deg + 180.0) / 360.0 * n)
ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
return (xtile, ytile)
def num2deg(xtile, ytile, zoom):
n = 2.0 ** zoom
lon_deg = xtile / n * 360.0 - 180.0
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
lat_deg = math.degrees(lat_rad)
return (lat_deg, lon_deg)
def getImageCluster(lat_deg, lon_deg, delta_lat, delta_long, zoom):
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
smurl = r"http://a.tile.openstreetmap.org/{0}/{1}/{2}.png"
xmin, ymax =deg2num(lat_deg, lon_deg, zoom)
xmax, ymin =deg2num(lat_deg + delta_lat, lon_deg + delta_long, zoom)
Cluster = Image.new('RGB',((xmax-xmin+1)*256-1,(ymax-ymin+1)*256-1) )
for xtile in range(xmin, xmax+1):
for ytile in range(ymin, ymax+1):
try:
imgurl = smurl.format(zoom, xtile, ytile)
print("Opening: " + imgurl)
imgstr = requests.get(imgurl, headers=headers)
tile = Image.open(BytesIO(imgstr.content))
Cluster.paste(tile, box = ((xtile-xmin)*256 , (ytile-ymin)*255))
except:
print("Couldn't download image")
tile = None
return Cluster
if __name__ == '__main__':
a = getImageCluster(38.5, -77.04, 0.02, 0.05, 13)
fig = plt.figure()
fig.patch.set_facecolor('white')
plt.imshow(np.asarray(a))
plt.show()
The result is the following: