pythonopenstreetmap

Easy OpenStreetMap tile displaying for Python


I want to include the open street map (OSM) in my python code.

I have read through lots of webpages regarding OSM. But unfortunately I'm a bit lost, regarding which package I should use.

I'm looking for an easy way to get an OSM image in my app. As a starting point I'm thinking of something like:

import matplotlib.pyplot as plt

# Pseudo - Code for required function 'GetOSMImage'
Map = GetOSMImage(lat, long, delta_lat, delta_long)

imgplot = plt.imshow(Map)

Later I want to plot additional data in plt (I'm aware that I'll need to deal with projections etc.).

What I don't need/want:

Do you have a good starting point for me? Or do I underestimate the complexity of this topic?


Solution

  • Based on your input, I was able to achive my target. Here is my code for others, which are searching a starting point to OSM. (Of course there is still much room for improvements).


    DISCLAIMER

    Please respect the usage policy of Open Street Map!

    OpenStreetMap data is free for everyone to use. Our tile servers are not.

    Requirements

    • Heavy use (e.g. distributing an app that uses tiles from openstreetmap.org) is forbidden without prior permission from the Operations Working Group. See below for alternatives.
    • Clearly display license attribution.
    • Do not actively or passively encourage copyright infringement.
    • Calls to /cgi-bin/export may only be triggered by direct end-user action. (For example: “click here to export”.) The export call is an expensive (CPU+RAM) function to run and will frequently reject when server is under high load.
    • Recommended: Do not hardcode any URL at tile.openstreetmap.org as doing so will limit your ability to react quickly if the service is disrupted or blocked.
    • Recommended: add a link to https://www.openstreetmap.org/fixthemap to allow your users to report and fix problems in our data.

    Technical Usage Requirements

    • Valid HTTP User-Agent identifying application. Faking another app’s User-Agent WILL get you blocked.
    • If known, a valid HTTP Referer.
    • DO NOT send no-cache headers. (“Cache-Control: no-cache”, “Pragma: no-cache” etc.)
    • Cache Tile downloads locally according to HTTP Expiry Header, alternatively a minimum of 7 days.
    • Maximum of 2 download threads. (Unmodified web browsers’ download thread limits are acceptable.)

    More details see: https://operations.osmfoundation.org/policies/tiles/


    Here is the code:

    import matplotlib.pyplot as plt
    import numpy as np
    
    import math
    import urllib2
    import StringIO
    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 get_image_cluster(lat_deg, lon_deg, delta_lat,  delta_long, zoom):
        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 = urllib2.urlopen(imgurl).read()
                    tile = Image.open(StringIO.StringIO(imgstr))
                    cluster.paste(tile, box=((xtile-xmin)*256 ,  (ytile-ymin)*255))
                except: 
                    print("Couldn't download image")
                    tile = None
    
        return cluster
        
       
    if __name__ == '__main__':
        a = get_image_cluster(38.5, -77.04, 0.02, 0.05, 13)
        fig = plt.figure()
        fig.patch.set_facecolor('white')
        plt.imshow(np.asarray(a))
        plt.show()