Skip to main content

Create map images and use as plot background

Project description

maptiles

Create map images and use as plot background.

Installation

# from pypi
$ pip3 install maptiles

# from github
$ git clone https://github.com/kota7/maptiles.git --depth 1
$ pip3 install -U ./maptiles
import matplotlib.pyplot as plt
from PIL import Image
%matplotlib inline

Illustrative examples

Map image on matplotlib axes

  • draw_map((lon1, lat1, lon2, lat2)) draws map image on the rectangle area on the matplotlib figure axes.
  • After drawing the map, one can add visualizations using the matplotlib features.

Remarks:

  • Longitude and latitudes must be given in angles. Internally longitudes are converted to [-180 to 180) scale. Latitudes must be in [-L, L] with L=85.0511287798. This L is the north and south limit of Web Mercator projection.
  • Zoom level is automatically chosen by heuristic calculation. The z option allows for explicit specification.
  • Aspect ratio is automatically adjusted by heuristic calculation. The aspect option allows for explicit specification.
  • If ax is not given, then new axes is created internally.
from maptiles import draw_map

# 5th Avenue in Manhattan, New York
bounds = [286.02288365364075, 40.761816905893156, 286.0257428884506, 40.7593098808893]
fig, ax = plt.subplots(figsize=(10, 10))
draw_map(bounds, ax=ax)

uniqlo = [286.02380633354187, 40.76029726182907]
uniqlo[0] -= 360
arrow_from = uniqlo[0] + 0.0001, uniqlo[1] - 0.0002
ax.annotate("UNIQLO IS HERE!", uniqlo, xytext=arrow_from, fontsize=25,
            bbox={"facecolor": "white", "alpha":0.75, "boxstyle":"round"}, arrowprops={"width":1})
None
Zoom level 18 is chosen

png

# Goryokaku Castle in Hokkaido, Japan
goryokaku = [[140.7545506954193, 41.79877552882002], [140.7546043395996, 41.797391817910004], [140.7536494731903, 41.7962160400744],
             [140.7536494731903, 41.79608006437536], [140.75378894805905, 41.79592009259535], [140.75480818748474, 41.79568013417667],
             [140.75480818748474, 41.79524020807576], [140.75473308563232, 41.79524820675909], [140.7547116279602, 41.79520021464413],
             [140.7548189163208, 41.79519221595479], [140.75482964515686, 41.7948002789552], [140.755033493042, 41.79467229900768],
             [140.75620293617249, 41.79503224195874], [140.75687885284424, 41.794456332266776], [140.75702905654907, 41.79442433713216],
             [140.75724363327026, 41.79444033470147], [140.75735092163086, 41.79449632616259], [140.75838088989255, 41.795648139652975],
             [140.76006531715393, 41.79620004294831], [140.76016187667847, 41.796288027092395], [140.76021552085876, 41.79639200819787],
             [140.7601833343506, 41.79651198618687], [140.75906753540036, 41.7976557650716], [140.75889587402344, 41.79899148100668],
             [140.75873494148254, 41.79915144512023], [140.75859546661377, 41.79919143608624], [140.7584023475647, 41.79915144512023],
             [140.7567822933197, 41.798759532332795], [140.7567822933197, 41.79872753934637], [140.75671792030334, 41.79872753934637],
             [140.75493693351746, 41.79900747743603], [140.75478672981262, 41.79899947922184], [140.75464725494385, 41.798927495249465],
             [140.7545506954193, 41.79877552882002]]
lons, lats = zip(*goryokaku)
bounds = min(lons), max(lats), max(lons), min(lats)
fig, ax = plt.subplots(figsize=(8, 8))
draw_map(bounds, ax=ax)

ax.plot(lons, lats, c="black", linewidth=4, linestyle="dashed")
None
Zoom level 17 is chosen

png

# Royal observatory of Greenwich
bounds = (-0.0092, 51.481, 0.0099, 51.472)
fig, ax = plt.subplots(figsize=(9, 9))
draw_map(bounds, ax=ax)

observatory = (-0.0008717179298400879, 51.47732699342673)
ax.scatter(*observatory, marker="x", s=200)
ax.axvline(x=0, linestyle="dotted", linewidth=3, c="blue")
ax.text(observatory[0], observatory[1]-0.0008, "Royal Observatory of Greenwich", ha="center",
        fontsize=20, bbox={"facecolor":"lightgreen", "alpha":0.75, "boxstyle":"round"})
None
Zoom level 15 is chosen

png

Obtain the image data as array

  • get_maparray((lon1, lat1, lon2, lat2)) returns:
    • The RGB image data as numpy array of shape (height, height, 3).
    • Tuple of (xmin, xmax, ymin, ymax) defining the area covered by the image.
from maptiles import get_maparray
# Royal observatory of Greenwich, again
bounds = (-0.0092, 51.481, 0.0099, 51.472)
img, extent = get_maparray(bounds)

print(img.shape)
print(extent)

Image.fromarray(img)
(338, 446, 3)
(-0.009226799011230469, 0.009913444519042969, 51.47197425351905, 51.48100872578421)


Zoom level 15 is chosen

png

Tiles

Predefined tiles

  • This package defines a number of map tiles for the convenience.
  • The available tiles are given by the predefined_tiles function.
  • These names can be used as the tile option of the draw_map and get_maparray functions.
from maptiles import predefined_tiles

list(predefined_tiles().keys())
['osm',
 'osm_bw',
 'osm_tonner',
 'osm_tonner_hybrid',
 'osm_tonner_labels',
 'osm_tonner_lines',
 'osm_tonner_backgrounds',
 'osm_tonner_lite',
 'japangsi',
 'japangsi_pale',
 'japangsi_blank',
 'google',
 'google_roads',
 'google_streets',
 'google_terrain',
 'google_satellite',
 'google_satellite_hybrid',
 'google_h',
 'google_r',
 'google_t',
 'google_s',
 'google_y']
# Royal observatory of Greenwich, again
bounds = (-0.0092, 51.481, 0.0099, 51.472)
fig, ax = plt.subplots(1, 2, figsize=(15, 7))
draw_map(bounds, ax=ax[0], tile="google")
ax[0].set_title("Google Map")
draw_map(bounds, ax=ax[1], tile="osm_bw")
ax[1].set_title("OpenStreetMap Black&White")
fig.tight_layout()
None
Zoom level 15 is chosen
Zoom level 15 is chosen

png

Custom tiles

  • Other tiles can be specified by a URL string with {x}, {y}, {z} parameters.
# Mount Fuji, Japan
bounds = [138.53553771972656, 35.48024245154482, 138.9276123046875, 35.231598543453316]
fig, ax = plt.subplots(1, 2, figsize=(15, 10))

draw_map(bounds, ax=ax[0], tile="japangsi")

url = "https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg"
draw_map(bounds, ax=ax[1], tile=url)
Zoom level 11 is chosen
Zoom level 11 is chosen

png

Implementation details

Database

  • Downloaded image data are stored at the internal SQLite database at config.dbfile. The default location is ~/maptiles.db.
  • By reusing the stored images, we reduce the number of requests to the map tile servers.
  • If you want to delete existing data, either run initialize_database(replace=True) or simply delete the file.
  • One may change the database file location by the set_databasefile function.
import sqlite3
from maptiles import config, set_databasefile

# The database has only one table "tiles"
#   with columns "url" and "image".
with sqlite3.connect(config.dbfile) as conn:
    c = conn.cursor()
    data = c.execute("SELECT url FROM tiles LIMIT 10").fetchall()
print(data)
[('http://tiles.wmflabs.org/bw-mapnik/15/16383/10900.png',), ('http://tiles.wmflabs.org/bw-mapnik/15/16383/10901.png',), ('http://tiles.wmflabs.org/bw-mapnik/15/16384/10900.png',), ('http://tiles.wmflabs.org/bw-mapnik/15/16384/10901.png',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1812/807.jpg',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1812/808.jpg',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1812/809.jpg',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1813/807.jpg',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1813/808.jpg',), ('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/11/1813/809.jpg',)]
# Change the database location
set_databasefile("./temp.db")
print(config.dbfile)
./temp.db

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

maptiles-0.0.1.tar.gz (9.1 kB view hashes)

Uploaded Source

Built Distribution

maptiles-0.0.1-py3-none-any.whl (8.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page