How to use OpenStreetMap background on Matplotlib Basemap
Asked Answered
E

6

12

This should be simple, but when I look for it I just find web packages. I need something better than as oriented on This Blog. Maybe using .oms file or shapefiles. Some way to give bbox and get the OpenStreetMap background on Basemap map.

I found some questions like this on Stack, but the answers directs to, or download the .png file on OpenStreetMap website, or to use some web package.

Ecumenical answered 5/5, 2015 at 12:29 Comment(0)
F
11

There are many libraries today that can do this for you - smopy, folium and tilemapbase are three examples from my recent use.

Each of these tools fetch map tiles from the one of several servers that host OSM or other (Stamen, Carto, etc) map tiles and then allows you to display and plot on them using matplotlib. Tilemapbase also caches the tiles locally so that they are not fetched again the next time.

But there does not seem to be a readily available tool yet, based on my recent experience, to use offline tilesets (such as a compressed .mbtiles file) as background for matplotlib plotting.

This link contains a survey of the above tools and more - https://github.com/ispmarin/maps

EDIT

I had mentioned in my previous answer that Tilemapbase did not work for some geographical locations in the world, and hence explicitly recommended not to use it. But it turns out I was wrong, and I apologize for that. It actually works great! The problem in my case was embarrassingly simple - I had reversed the order or lat and lon while fetching tiles, and hence it always fetched blank tiles for certain geographical locations, leading me to assume that it did not work for those locations.

I had raised the issue in github and it was immediately resolved by the developers. See it here - https://github.com/MatthewDaws/TileMapBase/issues/7

Note the responses:

Coordinates are to be provided in order (1) longitude, (2) latitude. If you copied them from Google Maps, they will be in lat/lon order and you have to flip them. So your map image is not empty, it's just a location in the ocean north of Norway.

And from the developer himself:

Yes, when I wrote the code, it seemed that there wasn't a universal standard for ordering. So I chose the one which is different to Google Maps. The method name from_lonlat should give a hint as to the correct ordering...

Fibrilliform answered 8/8, 2018 at 12:5 Comment(0)
I
10

I would suggest not to try to make something work, which is not made (yet) to work together. There is a simple way to achieve what you want with Mplleaflet. https://github.com/jwass/mplleaflet The library allows you to visualize geographic data on a beautiful interactive openstreetmap. Map projection of data in long lat format is automatically performed.

Installation in windows and ubuntu is easy:

pip install mplleaflet

You can start with the provided examples and go from there.

Indecisive answered 8/6, 2016 at 7:24 Comment(3)
Great! But is not exactly what I want. I want to plot it on matplotlib.Ecumenical
I highly advise to not use basemap it is inflexible and very slow, but maybe you could explain more what your objectives actually are, then you can get better advise. Btw, I just found another very similiar module to mplleaflet, try out also if smopy fits your needs, github.com/rossant/smopyIndecisive
@PhilippSchwarz: a second post with a smopy solution might well help some peopleLifework
C
9

For those who are using Cartopy, this is relatively simple:

import matplotlib.pyplot as pl
import numpy as np

import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt

request = cimgt.OSM()

# Bounds: (lon_min, lon_max, lat_min, lat_max):
extent = [1, 13, 45, 53]

ax = pl.axes(projection=request.crs)
ax.set_extent(extent)
ax.add_image(request, 5)    # 5 = zoom level

# Just some random points/lines:
pl.scatter(4.92, 51.97, transform=ccrs.PlateCarree())
pl.plot([4.92, 9], [51.97, 47], transform=ccrs.PlateCarree())

This produces:

enter image description here

Conni answered 29/11, 2021 at 8:8 Comment(0)
M
2

You can download the necessary tiles yourself from one of the tile servers. The OSM wiki explains the technical details behind slippy map tilenames and also includes examples for various programming and scripting languages.

Please also read about the tile usage policy and keep in mind that different tile serves may have different policies.

Monochord answered 5/5, 2015 at 16:11 Comment(2)
So, there's no simple way to do it?Ecumenical
If you want to stick to matplotlib basemap, it is not easy but fortunately there are alternatives such as mplleflet.Indecisive
P
2

@Bart's Cartopy answer is good, but I wanted to make it more flexible and deomonstrate the scale of zooming:

import matplotlib.pyplot as pl
import numpy as np

import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt

request = cimgt.OSM()

# helper function
def zoomlevel_from_deg(deg):
    "Calculate OSM zoom level from a span in degrees.  Adjust +/-1 as desired"
    from numpy import log2, clip, floor
    zoomlevel = int(clip(floor(log2(360) - log2(delta)),0,20 ))
    return zoomlevel 

# Parameters for Schoonhaven Watertoren, Schoonhaven, Nederlands

lon_i = 4.84795
lat_i = 51.9441
delta = 0.0016 # 0.0012 # 38 to 0.0002 degrees to avoid north pole
zoom = zoomlevel_from_deg(delta)-1 # 10 #  0-19 
print(f"Zoom Level: {zoom}")

# Bounds: (lon_min, lon_max, lat_min, lat_max):
extent = [lon_i-delta/np.cos(lat_i*np.pi/180), lon_i+delta/np.cos(lat_i*np.pi/180), lat_i-delta, lat_i+delta]

ax = pl.axes(projection=request.crs)
ax.set_extent(extent)
ax.add_image(request, zoom)    # 6 = zoom level

# Just some random points/lines:
pl.scatter(lon_i, lat_i, transform=ccrs.PlateCarree())
pl.plot([lon_i, lon_i+delta/2], [lat_i, lat_i-delta/2], transform=ccrs.PlateCarree())

Schoorhaven Watertoren map at zoom level 19 Schoorhaven Watertoren map at zoom level 7 Schoorhaven Watertoren map at zoom level 2

Pean answered 13/9, 2023 at 3:20 Comment(0)
R
0

This is very easy with geopandas and contextily. Have a look at https://geopandas.org/gallery/plotting_basemap_background.html.

Regimen answered 31/5, 2021 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.