Skip to content

Commit 78fb6d9

Browse files
Added document on getting started with TiTiler (#1124)
* created document on getting started with titiler * updated based on comment --------- Co-authored-by: dimplejaiin <dimple@pixxel.co.in>
1 parent cf37c6b commit 78fb6d9

5 files changed

Lines changed: 283 additions & 0 deletions

File tree

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ nav:
9292
- NumpyTile: "examples/notebooks/Working_with_NumpyTile.ipynb"
9393
- Algorithm: "examples/notebooks/Working_with_Algorithm.ipynb"
9494
- Statistics: "examples/notebooks/Working_with_Statistics.ipynb"
95+
- Getting Started with TiTiler: "examples/getting_started_with_titiler.md"
9596

9697
- API:
9798
- titiler.core:
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
[TiTiler](https://developmentseed.org/titiler) is a modern map tile server that helps developers quickly serve geospatial data on the web. Think of it as a specialized tool that takes large geographic files (like satellite imagery) and slices them into small, web-friendly map tiles that load efficiently in browser-based maps.
2+
3+
Built on FastAPI, TiTiler makes working with Cloud-Optimized GeoTIFFs, Spatio Temporal Asset Catalog and other spatial data formats straightforward, even if you're not a GIS expert. It handles all the complex work of processing geographic data and serving it through simple API endpoints that any web developer can use.
4+
5+
In the past, putting maps on websites was a real pain. Developers had to use bulky tools like GeoServer that were hard to set up, or spend hours making thousands of **static** tiny map images with tools like gdal2tiles that couldn't be changed later. TiTiler makes this so much easier. It creates **dynamic** map pieces right when you need them, instead of making them all beforehand. It works great with modern cloud data and doesn't need complicated setup. This means less headache and more time to focus on building cool map features that users will love.
6+
7+
## Dynamic vs. Static Tiles: What's the Difference?
8+
9+
Static tiles are like pre-printed map pieces stored in folders. Once created, they're locked—changing anything means starting over. They use lots of storage but load quickly.
10+
11+
TiTiler's dynamic tiles work like a chef cooking to order. When someone views your map, TiTiler grabs just the data needed and creates tiles on the spot. This lets you instantly change colors, adjust contrast, or highlight different features. Your map becomes flexible and responsive, adapting to what users need right now rather than being stuck with choices made earlier.
12+
13+
## Let's Get TiTiler Up and Running!
14+
15+
Now that we understand the advantage of TiTiler's dynamic approach, let's get it running on your local machine. Follow these steps:
16+
17+
### **1. Create Your Project Workspace**
18+
19+
First, let's create a dedicated space for our TiTiler project. Open your terminal (Command Prompt or PowerShell on Windows, Terminal on macOS/Linux) and run:
20+
21+
```bash
22+
# Works on all operating systems
23+
mkdir Titiler
24+
cd Titiler
25+
```
26+
27+
> 💡 **Pro Tip**: Keeping your TiTiler project in its own folder makes it easier to manage and prevents conflicts with other Python projects.
28+
29+
### **2. Set Up a Python Virtual Environment**
30+
a. Create the virtual environment:
31+
```bash
32+
python -m venv titiler
33+
```
34+
b. Activate the virtual environment:
35+
- **For Linux/macOS:**
36+
```bash
37+
source titiler/bin/activate
38+
```
39+
- **For Windows:**
40+
```bash
41+
titiler\Scripts\activate
42+
```
43+
44+
### **3. Install TiTiler and Its Dependencies**
45+
46+
With your environment activated, install TiTiler and the web server it needs:
47+
48+
```bash
49+
pip install titiler.core uvicorn
50+
```
51+
52+
This command installs the core TiTiler package and Uvicorn, a lightning-fast ASGI server.
53+
54+
> 💡 **What's happening**: TiTiler.core contains the essential functionality for serving map tiles. Uvicorn is the engine that will run our FastAPI application.
55+
56+
### **4. Create Your TiTiler Application**
57+
58+
Now for the fun part! Create a file named `main.py` with the following code:
59+
60+
```python
61+
from fastapi import FastAPI
62+
from titiler.core.factory import TilerFactory
63+
64+
from starlette.middleware.cors import CORSMiddleware
65+
66+
app = FastAPI()
67+
68+
# Add CORS middleware
69+
app.add_middleware(
70+
CORSMiddleware,
71+
allow_origins=["*"], # Allows all origins (for development - be more specific in production)
72+
allow_credentials=True,
73+
allow_methods=["*"],
74+
allow_headers=["*"],
75+
)
76+
77+
# Create a TilerFactory for Cloud-Optimized GeoTIFFs
78+
cog = TilerFactory()
79+
80+
# Register all the COG endpoints automatically
81+
app.include_router(cog.router, tags=["Cloud Optimized GeoTIFF"])
82+
83+
84+
# Optional: Add a welcome message for the root endpoint
85+
@app.get("/")
86+
def read_index():
87+
return {"message": "Welcome to TiTiler"}
88+
```
89+
90+
> 💡 **Code Breakdown**:
91+
>
92+
> - We create a FastAPI app and add CORS middleware to allow web maps to access our images
93+
> - The `TilerFactory()` creates all the endpoints needed for serving COG tiles
94+
> - We include those endpoints in our app with `app.include_router()`
95+
> - A simple home endpoint provides a welcome message
96+
97+
### **5. Launch Your TiTiler Server**
98+
99+
Run the following command to start the server:
100+
```bash
101+
uvicorn main:app --reload
102+
```
103+
You should see output similar to this:
104+
105+
![server logs](../img/server_logs.png)
106+
107+
> 💡 **The `--reload` flag** automatically restarts the server whenever you change your code - perfect for development!
108+
109+
### **6. Explore Your TiTiler API**
110+
111+
Open your browser and go to:
112+
113+
``` http://127.0.0.1:8000/ ``` - See your welcome message
114+
115+
![browser](../img/browser.png)
116+
117+
``` http://127.0.0.1:8000/docs ``` - Explore the interactive API documentation. The `/docs` page is your mission control center. It shows all the endpoints TiTiler created for you and lets you test them directly in your browser:
118+
119+
![api docs](../img/api_docs.png)
120+
121+
## Visualizing Your Geospatial Data
122+
123+
Now that your server is running, let's see what it can do with real data!
124+
125+
### **Quick Preview of Your Raster**
126+
127+
To get a quick preview of any Cloud-Optimized GeoTIFF, use:
128+
129+
```bash
130+
http://127.0.0.1:8000/preview?url=file:///path_to_your_raster.tif
131+
```
132+
> ⚠️ **Note**: Replace the path with the actual path to your COG file. Remember to use the full path for local files.
133+
134+
## Visualizing a Specific Tile (Z, X, Y)
135+
136+
When working with web maps, understanding tile coordinates is essential. Let's break down what Z, X, Y values mean:
137+
138+
- **Z (zoom level)**: How far in/out you're zoomed. Lower numbers (0-5) show the whole world with less detail; higher numbers (15-22) show smaller areas with more detail.
139+
- **X (column)**: Horizontal position, increasing eastward.
140+
- **Y (row)**: Vertical position, increasing southward.
141+
142+
At zoom level 0, there's just 1 tile for the whole world. Each zoom level increase splits each tile into 4 more detailed tiles.
143+
144+
### **Why Visualize Specific Tiles?**
145+
146+
- **Performance**: Load only what users can see
147+
- **Debugging**: Inspect problematic tiles
148+
- **Specific Analysis**: Extract data from exact locations
149+
150+
### **Finding Z, X, Y for Your Image**
151+
152+
The `rio_tiler` and `morecantile` library makes this straightforward:
153+
154+
```python
155+
from rio_tiler.io import Reader
156+
import morecantile
157+
158+
# Web Mercator is the default tiling scheme for most web map clients
159+
WEB_MERCATOR_TMS = morecantile.tms.get("WebMercatorQuad")
160+
161+
with Reader('/path/to/your/raster.tif', tms=WEB_MERCATOR_TMS) as src:
162+
bbox = src.get_geographic_bounds("epsg:4326")
163+
zoom = 15
164+
# Find all tiles covering the bounding box
165+
tiles = list(src.tms.tiles(bbox[0], bbox[1], bbox[2], bbox[3], zoom))
166+
for t in tiles:
167+
print("Tile coordinate (x, y, z):", t.x, t.y, t.z)
168+
```
169+
170+
### **Viewing a Specific Tile in TiTiler**
171+
172+
For example, if your tile has coordinates `x=5412, y=12463, z=15`, you would access the specific tile with:
173+
174+
```bash
175+
http://127.0.0.1:8000/tiles/WebMercatorQuad/15/5412/12463.png?url=raster.tif
176+
```
177+
178+
URL components explained:
179+
180+
- **`WebMercatorQuad/`**: The tiling scheme (this should match your raster's CRS - TiTiler will reproject on-the-fly if needed, but using the correct scheme improves performance and accuracy)
181+
- **`{z}/{x}/{y}`**: Your tile coordinates
182+
- **`.png`**: Output format (alternatives: `.jpg`, `.webp`, `.tif`)
183+
- **`?url=raster.tif`**: Source raster file
184+
185+
### **Creating a Web Map with Leaflet**
186+
187+
[Leaflet](https://leafletjs.com/) is a lightweight, open-source JavaScript library for interactive maps. It lets you combine base maps (like OpenStreetMap) with overlays from custom tile servers such as TiTiler.
188+
189+
The following code (in **map.html**) loads a base map, adds your TiTiler raster overlay, and automatically sets the map's view to the raster's bounds:
190+
191+
---
192+
193+
<details>
194+
<summary><strong>map.html Code</strong></summary>
195+
196+
```html
197+
<!DOCTYPE html>
198+
<html>
199+
<head>
200+
<title>Leaflet Basemap + TiTiler Raster Overlay</title>
201+
<meta charset="utf-8">
202+
<meta name="viewport" content="initial-scale=1.0">
203+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
204+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
205+
</head>
206+
<body>
207+
<div id="map" style="width: 100%; height: 600px;"></div>
208+
<script>
209+
// Initialize the map with OpenStreetMap as the basemap
210+
var map = L.map('map').setView([0, 0], 2);
211+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
212+
maxZoom: 19,
213+
attribution: '&copy; OpenStreetMap contributors'
214+
}).addTo(map);
215+
216+
/// Define the local raster path and TiTiler endpoint
217+
// Replace with your own full GeoTIFF path - use the appropriate format for your OS.
218+
var rasterPath = 'file:///path_to_your_raster.tif';
219+
var titilerUrl = 'http://127.0.0.1:8000/tiles/WebMercatorQuad/{z}/{x}/{y}.png?url=' + encodeURIComponent(rasterPath);
220+
221+
// Add the TiTiler raster overlay with some transparency
222+
L.tileLayer(titilerUrl, {
223+
tileSize: 256,
224+
opacity: 0.7,
225+
maxZoom: 22
226+
}).addTo(map);
227+
228+
// Fetch the raster's bounding box from TiTiler and adjust the map view accordingly
229+
var boundsUrl = 'http://127.0.0.1:8000/bounds?url=' + encodeURIComponent(rasterPath);
230+
console.log(boundsUrl)
231+
fetch(boundsUrl)
232+
.then(response => response.json())
233+
.then(data => {
234+
console.log("Bounds data:", data);
235+
if (data && data.bounds) {
236+
// data.bounds is [minX, minY, maxX, maxY]
237+
var b = data.bounds;
238+
// Convert to Leaflet bounds: [[southWest_lat, southWest_lng], [northEast_lat, northEast_lng]]
239+
var leafletBounds = [[b[1], b[0]], [b[3], b[2]]];
240+
map.fitBounds(leafletBounds);
241+
} else {
242+
console.error("No bounds returned from TiTiler.");
243+
}
244+
})
245+
.catch(error => console.error("Error fetching bounds:", error));
246+
247+
</script>
248+
</body>
249+
</html>
250+
```
251+
</details>
252+
253+
---
254+
255+
## Troubleshooting Common Issues
256+
257+
### **CORS Issues**
258+
259+
If you encounter "Access to fetch at X has been blocked by CORS policy" errors in your browser console, make sure you:
260+
261+
- Have included the CORS middleware in `main.py` as shown above
262+
- Restart your TiTiler server after making changes
263+
264+
### **File Not Found Errors**
265+
266+
When using `file:///` URLs:
267+
- Make sure to use the absolute path to your file with the correct format for your operating system:
268+
269+
- Windows: `file:///C:/Users/username/data/image.tif`
270+
- macOS: `file:///Users/username/data/image.tif`
271+
- Linux: `file:///home/username/data/image.tif`
272+
273+
### **No Tiles Showing**
274+
275+
If your map loads but your tiles don't appear:
276+
277+
- Check the browser console for errors
278+
- Verify that your GeoTIFF is Cloud-Optimized (use `rio cogeo validate` from the rio-cogeo package)
279+
- Try different zoom levels - your data might not be visible at all scales
280+
281+
---
282+
*Created by [Dimple Jain](https://jaiindimple.github.io)*

docs/src/img/api_docs.png

179 KB
Loading

docs/src/img/browser.png

62.4 KB
Loading

docs/src/img/server_logs.png

450 KB
Loading

0 commit comments

Comments
 (0)