Metadata-Version: 2.4
Name: localtileserver
Version: 1.0.0
Summary: Locally serve geospatial raster tiles in the Slippy Map standard.
Author-email: Bane Sullivan <hello@banesullivan.com>
License-Expression: MIT
Project-URL: Documentation, https://localtileserver.banesullivan.com
Project-URL: Bug Tracker, https://github.com/banesullivan/localtileserver/issues
Project-URL: Source Code, https://github.com/banesullivan/localtileserver
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click
Requires-Dist: fastapi>=0.100.0
Requires-Dist: uvicorn[standard]
Requires-Dist: jinja2
Requires-Dist: jupyter-loopback[comm]>=0.3.3
Requires-Dist: rio-tiler
Requires-Dist: rio-cogeo
Requires-Dist: requests
Requires-Dist: server-thread
Requires-Dist: scooby
Provides-Extra: colormaps
Requires-Dist: matplotlib; extra == "colormaps"
Requires-Dist: cmocean; extra == "colormaps"
Requires-Dist: colorcet; extra == "colormaps"
Provides-Extra: jupyter
Requires-Dist: ipyleaflet; extra == "jupyter"
Provides-Extra: xarray
Requires-Dist: xarray; extra == "xarray"
Requires-Dist: rioxarray; extra == "xarray"
Provides-Extra: helpers
Requires-Dist: shapely; extra == "helpers"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: matplotlib; extra == "test"
Requires-Dist: folium; extra == "test"
Requires-Dist: ipyleaflet; extra == "test"
Requires-Dist: shapely; extra == "test"
Provides-Extra: doc
Requires-Dist: bokeh; extra == "doc"
Requires-Dist: folium; extra == "doc"
Requires-Dist: ipyleaflet; extra == "doc"
Requires-Dist: jupyter-sphinx; extra == "doc"
Requires-Dist: matplotlib; extra == "doc"
Requires-Dist: pydata-sphinx-theme; extra == "doc"
Requires-Dist: shapely; extra == "doc"
Requires-Dist: sphinx; extra == "doc"
Requires-Dist: sphinx-copybutton; extra == "doc"
Requires-Dist: sphinx-notfound-page; extra == "doc"
Provides-Extra: dev
Requires-Dist: localtileserver[colormaps,doc,helpers,jupyter,test,xarray]; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Provides-Extra: all
Requires-Dist: localtileserver[colormaps,helpers,jupyter,xarray]; extra == "all"
Dynamic: license-file

### 🚀 Support This Project

If localtileserver saves you time, powers your work, or you need direct help, please consider supporting the project and my efforts:

[![Sponsor](https://img.shields.io/badge/Sponsor%20Bane%20Sullivan-🚀-green?style=for-the-badge)](https://github.com/sponsors/banesullivan)

![tile-diagram](https://raw.githubusercontent.com/banesullivan/localtileserver/main/imgs/oam-tiles.jpg)

# 🌐 Local Tile Server for Geospatial Rasters

[![codecov](https://codecov.io/gh/banesullivan/localtileserver/branch/main/graph/badge.svg?token=S0HQ64FW8G)](https://codecov.io/gh/banesullivan/localtileserver)
[![PyPI](https://img.shields.io/pypi/v/localtileserver.svg?logo=python&logoColor=white)](https://pypi.org/project/localtileserver/)
[![conda](https://img.shields.io/conda/vn/conda-forge/localtileserver.svg?logo=conda-forge&logoColor=white)](https://anaconda.org/conda-forge/localtileserver)

_Need to visualize a rather large (gigabytes+) raster?_ **This is for you.**

A Python package for serving tiles from large raster files in
the [Slippy Maps standard](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames)
(i.e., `/zoom/x/y.png`) for visualization in Jupyter with `ipyleaflet` or `folium`.

Try it live on MyBinder: [![MyBinder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/banesullivan/localtileserver/HEAD?labpath=examples/example.ipynb) (more demos in [`examples/`](examples/))

Documentation: https://localtileserver.banesullivan.com/

Built on [rio-tiler](https://github.com/cogeotiff/rio-tiler) and [FastAPI](https://fastapi.tiangolo.com/)

## 🌟 Highlights

- Launch a tile server for large geospatial images
- View local or remote raster files with `ipyleaflet` or `folium` in Jupyter
- Band math expressions for on-the-fly computed imagery (e.g., NDVI)
- Per-band statistics and multiple image stretch modes
- Multiple output formats: PNG, JPEG, WebP, GeoTIFF, NPY
- Spatial subsetting via bounding box crops and GeoJSON masks
- [STAC](https://stacspec.org/) item support for multi-asset catalogs
- [Xarray](https://xarray.dev/) DataArray tile serving (NetCDF, Zarr, etc.)
- Virtual mosaics from multiple raster files
- View rasters with CesiumJS with the built-in web application
- Full REST API powered by FastAPI with auto-generated OpenAPI docs

## 🚀 Usage

Usage details and examples can be found in the documentation: https://localtileserver.banesullivan.com/

The following is a minimal example to visualize a local raster file with
`ipyleaflet`:

```py
import localtileserver as lts
from ipyleaflet import Map

# First, create a tile server from local raster file
client = lts.open('path/to/geo.tif')

# Create ipyleaflet tile layer from that server
t = lts.get_leaflet_tile_layer(client)

m = Map(center=client.center(), zoom=client.default_zoom)
m.add(t)
m
```

![ipyleaflet](https://raw.githubusercontent.com/banesullivan/localtileserver/main/imgs/ipyleaflet.png)

### Band Math Expressions

Compute derived imagery on the fly using band math expressions:

```py
client = lts.open('path/to/multispectral.tif')

# NDVI: (NIR - Red) / (NIR + Red) where NIR=b4, Red=b1
t = lts.get_leaflet_tile_layer(client, expression='(b4-b1)/(b4+b1)',
                               vmin=-1, vmax=1, colormap='RdYlGn')
```

### STAC Support

Visualize assets from STAC catalogs:

```py
import requests

# Fetch tiles from a STAC item's assets
resp = requests.get('http://localhost:PORT/api/stac/tiles/10/512/512.png',
                    params={'url': 'https://example.com/stac/item.json',
                            'assets': 'visual'})
```

### Xarray DataArrays

Serve tiles directly from xarray DataArrays (NetCDF, Zarr, etc.):

```py
import xarray as xr

ds = xr.open_dataset('temperature.nc')
da = ds['temperature']
da = da.rio.write_crs('EPSG:4326')

# Register and serve tiles through the REST API
```

### VS Code, Colab, and other webview notebooks

`localtileserver` works out of the box in JupyterLab, Notebook 7, JupyterHub,
and Binder because those frontends let the browser reach the jupyter-server
origin directly. VS Code Jupyter (including Remote-SSH), Google Colab, Shiny
for Python, Solara, and marimo render notebook outputs in a sandboxed webview
whose origin is **not** the jupyter-server — so root-relative tile URLs never
reach the proxy, and `http://127.0.0.1:<port>/…` fails to resolve.

To cover those frontends, `localtileserver` integrates with
[`jupyter-loopback`](https://github.com/banesullivan/jupyter-loopback). When
you call `get_leaflet_tile_layer(...)` or `get_folium_tile_layer(...)`, the
helper automatically routes that client's tile URLs through the comm bridge.
No install step or notebook changes required — `jupyter-loopback[comm]` is
pulled in by the core `pip install localtileserver`.

If you use a `TileClient` outside those helpers (e.g. embedding raw tile
URLs in a custom HTML output), call the method explicitly:

```py
client = lts.open('path/to/geo.tif')
client.enable_jupyter_loopback()
```

Or, for a specific port you're managing yourself:

```py
import localtileserver
localtileserver.enable_jupyter_loopback(port)
```

Opt out globally by setting `LOCALTILESERVER_DISABLE_JUPYTER_LOOPBACK=1` in
your environment before importing `localtileserver`.

## ℹ️ Overview

The `TileClient` class can be used to launch a tile server in a background
thread which will serve raster imagery to a viewer (usually `ipyleaflet` or
`folium` in Jupyter notebooks).

This tile server can efficiently deliver varying resolutions of your
raster imagery to your viewer; it helps to have pre-tiled,
[Cloud Optimized GeoTIFFs (COGs)](https://www.cogeo.org/).

There is an included, standalone web viewer leveraging
[CesiumJS](https://cesium.com/platform/cesiumjs/).

### REST API

The server exposes a comprehensive REST API built on FastAPI:

| Endpoint                                  | Description             |
| ----------------------------------------- | ----------------------- |
| `GET /api/tiles/{z}/{x}/{y}.{fmt}`        | Raster tiles            |
| `GET /api/thumbnail.{fmt}`                | Thumbnail preview       |
| `GET /api/metadata`                       | Raster metadata         |
| `GET /api/bounds`                         | Geographic bounds       |
| `GET /api/statistics`                     | Per-band statistics     |
| `GET /api/part.{fmt}`                     | Bounding box crop       |
| `POST /api/feature.{fmt}`                 | GeoJSON mask extraction |
| `GET /api/stac/tiles/{z}/{x}/{y}.{fmt}`   | STAC item tiles         |
| `GET /api/xarray/tiles/{z}/{x}/{y}.{fmt}` | Xarray DataArray tiles  |
| `GET /api/mosaic/tiles/{z}/{x}/{y}.{fmt}` | Mosaic tiles            |
| `GET /swagger/`                           | Interactive API docs    |

All tile/thumbnail endpoints support `expression`, `stretch`, `indexes`, `colormap`, `vmin`, `vmax`, and `nodata` query parameters.

## ⬇️ Installation

Get started with `localtileserver` to view rasters in Jupyter or deploy as your
own FastAPI application.

### 🐍 Installing with `conda`

Conda makes managing `localtileserver`'s dependencies across platforms quite
easy and this is the recommended method to install:

```bash
conda install -c conda-forge localtileserver
```

### 🎡 Installing with `pip`

If you prefer pip, then you can install from PyPI: https://pypi.org/project/localtileserver/

```
pip install localtileserver
```

### Optional Dependencies

For xarray/DataArray support:

```
pip install localtileserver[xarray]
```

For Jupyter widget integration:

```
pip install localtileserver[jupyter]
```

For additional colormaps:

```
pip install localtileserver[colormaps]
```

## 💭 Feedback

Please share your thoughts and questions on the [Discussions](https://github.com/banesullivan/localtileserver/discussions) board.
If you would like to report any bugs or make feature requests, please open an issue.

If filing a bug report, please share a scooby `Report`:

```py
import localtileserver as lts
print(lts.Report())
```
