0
# Tile Operations
1
2
Core functionality for downloading, caching, and processing map tiles from web services. These functions provide direct access to tile data for custom applications and analysis workflows.
3
4
## Capabilities
5
6
### Image Tile Retrieval
7
8
Download map tiles for specified geographic bounds and return as numpy arrays with extent information for direct use in applications.
9
10
```python { .api }
11
def bounds2img(w, s, e, n, zoom='auto', source=None, ll=False,
12
wait=0, max_retries=2, n_connections=1, use_cache=True,
13
zoom_adjust=None):
14
"""
15
Download tiles for bounding box and return as image array with extent.
16
17
Parameters:
18
- w: float - West edge coordinate
19
- s: float - South edge coordinate
20
- e: float - East edge coordinate
21
- n: float - North edge coordinate
22
- zoom: int or 'auto' - Zoom level (calculated automatically if 'auto')
23
- source: TileProvider, str, or None - Tile source (defaults to OpenStreetMap HOT)
24
- ll: bool - If True, coordinates are lon/lat (EPSG:4326), otherwise Web Mercator (EPSG:3857)
25
- wait: int - Seconds to wait between failed requests and retries
26
- max_retries: int - Maximum number of retries for failed requests
27
- n_connections: int - Number of parallel connections (default 1, max recommended 16)
28
- use_cache: bool - Whether to cache downloaded tiles
29
- zoom_adjust: int - Adjustment to automatically calculated zoom level
30
31
Returns:
32
tuple: (img: ndarray, extent: tuple)
33
- img: 3D array (height, width, bands) of RGB values
34
- extent: (minX, maxX, minY, maxY) bounding box in Web Mercator
35
"""
36
```
37
38
**Usage Examples:**
39
40
```python
41
import contextily as ctx
42
import matplotlib.pyplot as plt
43
44
# Download tiles for NYC area (lon/lat coordinates)
45
west, south, east, north = -74.1, 40.7, -73.9, 40.8 # NYC bounds
46
img, extent = ctx.bounds2img(west, south, east, north, zoom=12, ll=True)
47
48
# Display the downloaded image
49
fig, ax = plt.subplots(figsize=(10, 8))
50
ax.imshow(img, extent=extent)
51
ax.set_title("NYC Basemap")
52
plt.show()
53
54
# Use different tile provider
55
img, extent = ctx.bounds2img(west, south, east, north,
56
source=ctx.providers.Stamen.Toner,
57
zoom=10, ll=True)
58
59
# High resolution with parallel downloads (be respectful of tile servers)
60
img, extent = ctx.bounds2img(west, south, east, north,
61
zoom=15, n_connections=2, ll=True)
62
63
# Web Mercator coordinates (ll=False, default)
64
w_merc, s_merc, e_merc, n_merc = -8238310, 4969450, -8235310, 4972450
65
img, extent = ctx.bounds2img(w_merc, s_merc, e_merc, n_merc, zoom=14)
66
```
67
68
### Raster File Output
69
70
Download map tiles and save directly to geospatial raster files with proper georeferencing for use in GIS applications.
71
72
```python { .api }
73
def bounds2raster(w, s, e, n, path, zoom='auto', source=None, ll=False,
74
wait=0, max_retries=2, n_connections=1, use_cache=True):
75
"""
76
Download tiles for bounding box and write to raster file in Web Mercator CRS.
77
78
Parameters:
79
- w: float - West edge coordinate
80
- s: float - South edge coordinate
81
- e: float - East edge coordinate
82
- n: float - North edge coordinate
83
- path: str - Output raster file path
84
- zoom: int or 'auto' - Zoom level (calculated automatically if 'auto')
85
- source: TileProvider, str, or None - Tile source (defaults to OpenStreetMap HOT)
86
- ll: bool - If True, coordinates are lon/lat, otherwise Web Mercator
87
- wait: int - Seconds to wait between failed requests and retries
88
- max_retries: int - Maximum number of retries for failed requests
89
- n_connections: int - Number of parallel connections for downloading
90
- use_cache: bool - Whether to cache downloaded tiles
91
92
Returns:
93
tuple: (img: ndarray, extent: tuple)
94
- img: 3D array (height, width, bands) of RGB values
95
- extent: (minX, maxX, minY, maxY) bounding box in Web Mercator
96
"""
97
```
98
99
**Usage Examples:**
100
101
```python
102
import contextily as ctx
103
104
# Download and save basemap for analysis area
105
west, south, east, north = -122.5, 37.7, -122.3, 37.9 # San Francisco
106
img, extent = ctx.bounds2raster(west, south, east, north,
107
'sf_basemap.tiff', zoom=13, ll=True)
108
109
# High-resolution satellite imagery
110
img, extent = ctx.bounds2raster(west, south, east, north,
111
'sf_satellite.tiff',
112
source=ctx.providers.ESRI.WorldImagery,
113
zoom=16, ll=True)
114
115
# Use the saved raster in other applications
116
import rasterio
117
with rasterio.open('sf_basemap.tiff') as src:
118
print(f"CRS: {src.crs}") # EPSG:3857
119
print(f"Bounds: {src.bounds}")
120
basemap_data = src.read()
121
```
122
123
### Tile Count Estimation
124
125
Calculate the number of tiles required for a given area and zoom level to estimate download time and data usage.
126
127
```python { .api }
128
def howmany(w, s, e, n, zoom, verbose=True, ll=False):
129
"""
130
Calculate number of tiles required for bounding box and zoom level.
131
132
Parameters:
133
- w: float - West edge coordinate
134
- s: float - South edge coordinate
135
- e: float - East edge coordinate
136
- n: float - North edge coordinate
137
- zoom: int - Zoom level (integer value required)
138
- verbose: bool - Whether to print informative message
139
- ll: bool - If True, coordinates are lon/lat, otherwise Web Mercator
140
141
Returns:
142
int - Number of tiles required
143
"""
144
```
145
146
**Usage Examples:**
147
148
```python
149
import contextily as ctx
150
151
# Check tile count before downloading
152
west, south, east, north = -74.1, 40.7, -73.9, 40.8 # NYC
153
tile_count = ctx.howmany(west, south, east, north, zoom=15, ll=True)
154
# Output: "Using zoom level 15, this will download 64 tiles"
155
156
# Estimate for different zoom levels
157
for zoom in range(10, 17):
158
count = ctx.howmany(west, south, east, north, zoom, verbose=False, ll=True)
159
print(f"Zoom {zoom}: {count} tiles")
160
161
# Auto-calculated zoom estimation
162
count = ctx.howmany(west, south, east, north, zoom='auto', ll=True)
163
```
164
165
### Cache Management
166
167
Control tile caching behavior for performance optimization and storage management.
168
169
```python { .api }
170
def set_cache_dir(path):
171
"""
172
Set custom cache directory for tile downloads.
173
174
Parameters:
175
- path: str - Path to cache directory
176
177
Returns:
178
None
179
"""
180
```
181
182
**Usage Examples:**
183
184
```python
185
import contextily as ctx
186
import os
187
188
# Set persistent cache directory
189
cache_dir = os.path.expanduser('~/contextily_cache')
190
ctx.set_cache_dir(cache_dir)
191
192
# Now all tile downloads use persistent cache
193
img, extent = ctx.bounds2img(-74.1, 40.7, -73.9, 40.8, zoom=12, ll=True)
194
195
# Disable caching for specific downloads
196
img, extent = ctx.bounds2img(-74.1, 40.7, -73.9, 40.8,
197
zoom=12, ll=True, use_cache=False)
198
```
199
200
## Tile Sources and Providers
201
202
### Default Provider
203
204
```python
205
# Default source is OpenStreetMap Humanitarian tiles
206
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True)
207
# Equivalent to:
208
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True,
209
source=ctx.providers.OpenStreetMap.HOT)
210
```
211
212
### Popular Providers
213
214
```python
215
# Satellite imagery
216
img, extent = ctx.bounds2img(w, s, e, n, zoom=14, ll=True,
217
source=ctx.providers.ESRI.WorldImagery)
218
219
# Terrain map
220
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True,
221
source=ctx.providers.Stamen.Terrain)
222
223
# High contrast
224
img, extent = ctx.bounds2img(w, s, e, n, zoom=11, ll=True,
225
source=ctx.providers.Stamen.Toner)
226
```
227
228
### Custom Tile URLs
229
230
```python
231
# Custom tile server
232
custom_url = "https://tiles.example.com/{z}/{x}/{y}.png"
233
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True, source=custom_url)
234
235
# TileProvider object
236
from xyzservices import TileProvider
237
provider = TileProvider(
238
url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
239
attribution="© Esri"
240
)
241
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True, source=provider)
242
```
243
244
## Performance and Rate Limiting
245
246
### Parallel Downloads
247
248
```python
249
# Single connection (default, most respectful)
250
img, extent = ctx.bounds2img(w, s, e, n, zoom=14, ll=True, n_connections=1)
251
252
# Multiple connections (check provider's terms of service)
253
# OpenStreetMap allows max 2 connections
254
img, extent = ctx.bounds2img(w, s, e, n, zoom=14, ll=True, n_connections=2)
255
256
# Higher concurrency for servers that allow it
257
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True, n_connections=8)
258
```
259
260
### Rate Limiting and Retries
261
262
```python
263
# Handle rate-limited APIs
264
img, extent = ctx.bounds2img(w, s, e, n, zoom=14, ll=True,
265
wait=1, # Wait 1 second between retries
266
max_retries=5) # Try up to 5 times
267
268
# Disable retries for fast failure
269
img, extent = ctx.bounds2img(w, s, e, n, zoom=12, ll=True, max_retries=0)
270
```
271
272
### Memory Management
273
274
```python
275
# Disable caching for memory-constrained environments
276
img, extent = ctx.bounds2img(w, s, e, n, zoom=15, ll=True,
277
use_cache=False, n_connections=4)
278
279
# Process large areas in chunks
280
def download_large_area(w, s, e, n, zoom, chunk_size=0.01):
281
"""Download large area in smaller chunks to manage memory."""
282
chunks = []
283
for lat in np.arange(s, n, chunk_size):
284
for lon in np.arange(w, e, chunk_size):
285
chunk_w, chunk_s = lon, lat
286
chunk_e, chunk_n = min(lon + chunk_size, e), min(lat + chunk_size, n)
287
img, extent = ctx.bounds2img(chunk_w, chunk_s, chunk_e, chunk_n,
288
zoom=zoom, ll=True, use_cache=False)
289
chunks.append((img, extent))
290
return chunks
291
```
292
293
## Error Handling
294
295
### Common Error Scenarios
296
297
```python
298
import contextily as ctx
299
import requests
300
301
try:
302
img, extent = ctx.bounds2img(w, s, e, n, zoom=18, ll=True)
303
except requests.HTTPError as e:
304
if "404" in str(e):
305
print("Tiles not available at this zoom level")
306
else:
307
print(f"HTTP error: {e}")
308
except ValueError as e:
309
print(f"Invalid parameters: {e}")
310
except Exception as e:
311
print(f"Download failed: {e}")
312
313
# Validate zoom level for provider
314
try:
315
# Some providers have max zoom limits
316
img, extent = ctx.bounds2img(w, s, e, n, zoom=20, ll=True,
317
source=ctx.providers.OpenStreetMap.HOT)
318
except ValueError as e:
319
print(f"Zoom level error: {e}")
320
# Retry with lower zoom
321
img, extent = ctx.bounds2img(w, s, e, n, zoom=18, ll=True)
322
```
323
324
### Graceful Fallbacks
325
326
```python
327
def robust_tile_download(w, s, e, n, zoom=12, ll=True):
328
"""Download tiles with fallback providers."""
329
providers_to_try = [
330
ctx.providers.OpenStreetMap.HOT,
331
ctx.providers.CartoDB.Positron,
332
ctx.providers.Stamen.Toner
333
]
334
335
for provider in providers_to_try:
336
try:
337
return ctx.bounds2img(w, s, e, n, zoom=zoom, ll=ll, source=provider)
338
except Exception as e:
339
print(f"Provider {provider} failed: {e}")
340
continue
341
342
raise Exception("All tile providers failed")
343
344
# Usage
345
img, extent = robust_tile_download(-74.1, 40.7, -73.9, 40.8, zoom=12)
346
```