Skip to content

Commit e9f8e3f

Browse files
authored
Merge pull request #3 from Healy-Hyperspatial/streamlit-map
Streamlit map application
2 parents 28447b6 + 43bb7e1 commit e9f8e3f

File tree

7 files changed

+896
-3
lines changed

7 files changed

+896
-3
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The format is (loosely) based on [Keep a Changelog](http://keepachangelog.com/)
66

77
## [Unreleased]
88

9+
## [v0.3.0] - 2025-10-24
10+
11+
### Added
12+
13+
- Added `viewer` command to launch interactive Streamlit-based web viewer for exploring STAC collections and items. [#3](https://github.com/healy-hyperspatial/sfeos-tools/pull/3)
14+
915
## [v0.2.0] - 2025-10-21
1016

1117
### Added
@@ -32,7 +38,8 @@ The format is (loosely) based on [Keep a Changelog](http://keepachangelog.com/)
3238

3339
- Initial release
3440

35-
[Unreleased]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.2.0..main
41+
[Unreleased]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.3.0..main
42+
[v0.3.0]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.2.0...v0.3.0
3643
[v0.2.0]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.1.1...v0.2.0
3744
[v0.1.1]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.1.0...v0.1.1
3845
[v0.1.0]: https://github.com/healy-hyperspatial/sfeos-tools/compare/v0.1.0

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ CLI tools for managing [stac-fastapi-elasticsearch-opensearch](https://github.co
2323
- [Installation](#installation)
2424
- [For Elasticsearch](#for-elasticsearch)
2525
- [For OpenSearch](#for-opensearch)
26+
- [For Viewer](#for-viewer)
2627
- [For Development](#for-development-both-backends)
2728
- [Usage](#usage)
2829
- [Commands](#commands)
2930
- [add-bbox-shape](#add-bbox-shape)
3031
- [reindex](#reindex)
3132
- [load-data](#load-data)
33+
- [viewer](#viewer)
3234
- [Development](#development)
3335
- [License](#license)
3436

@@ -56,6 +58,19 @@ Or for local development:
5658
pip install -e sfeos_tools[opensearch]
5759
```
5860

61+
### For Viewer
62+
63+
To use the interactive Streamlit viewer:
64+
65+
```bash
66+
pip install sfeos-tools[viewer]
67+
```
68+
69+
Or for local development:
70+
```bash
71+
pip install -e sfeos_tools[viewer]
72+
```
73+
5974
### For Development (both backends)
6075

6176
```bash
@@ -168,6 +183,48 @@ sfeos-tools load-data \
168183
--collection-id production-data
169184
```
170185

186+
### viewer
187+
188+
Launch an interactive Streamlit-based web viewer for exploring STAC collections and items. The viewer provides:
189+
- Interactive map visualization of STAC items
190+
- Collection browser and selector
191+
- Item search and filtering
192+
- Metadata inspection
193+
- **Asset preview and imagery display**
194+
- Support for thumbnails, images (JPEG, PNG, TIFF), and other asset types
195+
196+
```bash
197+
sfeos-tools viewer [options]
198+
```
199+
200+
Options:
201+
- `--stac-url`: STAC API base URL (default: http://localhost:8080)
202+
- `--port`: Port for the Streamlit viewer (default: 8501)
203+
204+
**Requirements:**
205+
206+
The viewer requires additional dependencies. Install with:
207+
```bash
208+
pip install sfeos-tools[viewer]
209+
```
210+
211+
Examples:
212+
```bash
213+
# Launch viewer with default settings (connects to http://localhost:8080)
214+
sfeos-tools viewer
215+
216+
# Connect to a custom STAC API
217+
sfeos-tools viewer --stac-url https://my-stac-api.com
218+
219+
# Use a different port
220+
sfeos-tools viewer --port 8502
221+
222+
# Custom STAC API and port
223+
sfeos-tools viewer --stac-url http://localhost:8080 --port 8502
224+
```
225+
226+
The viewer will automatically open in your default web browser. Press `Ctrl+C` in the terminal to stop the viewer.
227+
171228
## Development
172229

173230
To develop sfeos-tools locally:

VIEWER_QUICKSTART.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# SFEOS Viewer Quick Start
2+
3+
The SFEOS Viewer is a Streamlit-based interactive web application for exploring STAC collections and items with map visualization.
4+
5+
## Installation
6+
7+
Install the viewer dependencies:
8+
9+
```bash
10+
pip install -e .[viewer]
11+
```
12+
13+
Or if you want all dev dependencies including the viewer:
14+
15+
```bash
16+
pip install -e .[dev]
17+
```
18+
19+
## Usage
20+
21+
### Basic Usage
22+
23+
Launch the viewer with default settings (connects to http://localhost:8080):
24+
25+
```bash
26+
sfeos-tools viewer
27+
```
28+
29+
### Custom STAC API
30+
31+
Connect to a different STAC API:
32+
33+
```bash
34+
sfeos-tools viewer --stac-url https://my-stac-api.com
35+
```
36+
37+
### Custom Port
38+
39+
Run on a different port:
40+
41+
```bash
42+
sfeos-tools viewer --port 8502
43+
```
44+
45+
## Features
46+
47+
- **Interactive Map**: Visualize STAC items on an OpenStreetMap-based map using Folium
48+
- **Collection Browser**: Select and explore different STAC collections
49+
- **Item Search**: Search for items with configurable limits
50+
- **Metadata Display**: View collection and item metadata in a clean interface
51+
- **Asset Preview**: Display imagery and other assets from STAC items
52+
- Automatic thumbnail detection
53+
- Full image viewer for JPEG, PNG, TIFF formats
54+
- Asset selector to browse all available assets
55+
- Support for COG (Cloud Optimized GeoTIFF) and other formats
56+
- **Responsive Layout**: Three-column layout with map, metadata, and asset preview
57+
58+
## Architecture
59+
60+
### Components
61+
62+
1. **STACClient** (`viewer.py`): Simple HTTP client for STAC API interactions
63+
- `get_collections()`: Fetch all collections
64+
- `get_collection(id)`: Fetch a specific collection
65+
- `search_items()`: Search for items with optional filters
66+
- `get_item()`: Fetch a specific item with full details
67+
68+
2. **Asset Management**: Extract and display STAC assets
69+
- `get_asset_urls()`: Extract all asset URLs from items
70+
- `get_thumbnail_url()`: Smart thumbnail detection
71+
- `load_image_from_url()`: Load and display images using Pillow
72+
73+
3. **Map Visualization**: Folium-based map rendering
74+
- Supports Point and Polygon geometries
75+
- Interactive popups with item metadata
76+
- Auto-centering based on item locations
77+
78+
4. **Streamlit UI**: Clean, responsive interface
79+
- Sidebar controls for collection selection and search
80+
- Main map view
81+
- Collection info and item selector
82+
- Asset preview panel with image display
83+
84+
### File Structure
85+
86+
```
87+
sfeos_tools/
88+
├── viewer.py # Main viewer module
89+
├── cli.py # CLI command integration
90+
tests/
91+
├── test_viewer.py # Unit tests for viewer
92+
```
93+
94+
## Development
95+
96+
### Running Tests
97+
98+
```bash
99+
pytest tests/test_viewer.py -v
100+
```
101+
102+
### Modifying the Viewer
103+
104+
The viewer is designed to be easily extensible:
105+
106+
- **Add new filters**: Modify the sidebar section in `run_viewer()`
107+
- **Change map style**: Update the `folium.Map()` initialization in `create_map()`
108+
- **Add new visualizations**: Extend the Streamlit layout in `run_viewer()`
109+
110+
### Testing Locally
111+
112+
1. Start your STAC API (e.g., SFEOS instance)
113+
2. Load some test data using `sfeos-tools load-data`
114+
3. Launch the viewer: `sfeos-tools viewer`
115+
4. Open http://localhost:8501 in your browser
116+
117+
## Troubleshooting
118+
119+
### "Streamlit is not installed"
120+
121+
Install the viewer dependencies:
122+
```bash
123+
pip install -e .[viewer]
124+
```
125+
126+
### "No collections found"
127+
128+
- Verify your STAC API is running
129+
- Check the STAC URL is correct
130+
- Ensure the API is accessible from your machine
131+
132+
### Port already in use
133+
134+
Use a different port:
135+
```bash
136+
sfeos-tools viewer --port 8502
137+
```
138+
139+
## Future Enhancements
140+
141+
Potential improvements for the viewer:
142+
143+
- [ ] Advanced search filters (date range, bbox drawing)
144+
- [x] Asset preview (thumbnails, imagery) ✅
145+
- [ ] Export functionality (GeoJSON, CSV)
146+
- [ ] Bookmark/save searches
147+
- [ ] Multi-collection comparison
148+
- [ ] Custom basemap options
149+
- [ ] Item detail modal with full metadata
150+
- [ ] COG band visualization and manipulation
151+
- [ ] Image histogram and statistics
152+
- [ ] Side-by-side asset comparison

pyproject.toml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "sfeos-tools"
7-
version = "0.2.0"
7+
version = "0.3.0"
88
description = "CLI tools for managing stac-fastapi-elasticsearch-opensearch deployments"
99
readme = "README.md"
1010
authors = [
1111
{name = "Jonathan Healy", email = "[email protected]"},
12-
{name = "CloudFerro S.A."}
12+
{name = "CloudFerro S.A."},
13+
{name = "Healy Hyperspatial"}
1314
]
1415
license = {file = "LICENSE"}
1516
maintainers = [
@@ -50,9 +51,20 @@ elasticsearch = [
5051
opensearch = [
5152
"stac-fastapi-opensearch>=6.6.0",
5253
]
54+
viewer = [
55+
"streamlit>=1.28.0",
56+
"folium>=0.14.0",
57+
"streamlit-folium>=0.15.0",
58+
"pillow>=9.0.0",
59+
]
5360
dev = [
5461
"stac-fastapi-elasticsearch>=6.6.0",
5562
"stac-fastapi-opensearch>=6.6.0",
63+
# Viewer dependencies
64+
"streamlit>=1.28.0",
65+
"folium>=0.14.0",
66+
"streamlit-folium>=0.15.0",
67+
"pillow>=9.0.0",
5668
# Development tools
5769
"pytest>=6.0",
5870
"pytest-asyncio>=0.21.0",

sfeos_tools/cli.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,5 +275,83 @@ def load_data(base_url: str, collection_id: str, use_bulk: bool, data_dir: str)
275275
sys.exit(1)
276276

277277

278+
@cli.command("viewer")
279+
@click.option(
280+
"--stac-url",
281+
default="http://localhost:8080",
282+
help="STAC API base URL (default: http://localhost:8080)",
283+
)
284+
@click.option(
285+
"--port",
286+
type=int,
287+
default=8501,
288+
help="Port for the Streamlit viewer (default: 8501)",
289+
)
290+
def viewer(stac_url: str, port: int) -> None:
291+
"""Launch interactive Streamlit viewer for exploring STAC collections and items.
292+
293+
This command starts a local web-based viewer that allows you to:
294+
- Browse STAC collections
295+
- View items on an interactive map
296+
- Search and filter items
297+
- Inspect item metadata
298+
299+
Examples:
300+
sfeos-tools viewer
301+
sfeos-tools viewer --stac-url http://localhost:8080
302+
sfeos-tools viewer --stac-url https://my-stac-api.com --port 8502
303+
"""
304+
try:
305+
import sys
306+
from pathlib import Path
307+
308+
import streamlit.web.cli as stcli
309+
310+
# Get the path to viewer.py
311+
viewer_path = Path(__file__).parent / "viewer.py"
312+
313+
# Set environment variable for the STAC URL
314+
import os
315+
316+
os.environ["SFEOS_STAC_URL"] = stac_url
317+
318+
click.echo(click.style("🚀 Starting SFEOS Viewer...", fg="green"))
319+
click.echo(click.style(f"📡 STAC API: {stac_url}", fg="cyan"))
320+
click.echo(
321+
click.style(f"🌐 Viewer will open at: http://localhost:{port}", fg="cyan")
322+
)
323+
click.echo(click.style("\n💡 Press Ctrl+C to stop the viewer\n", fg="yellow"))
324+
325+
# Run streamlit
326+
sys.argv = [
327+
"streamlit",
328+
"run",
329+
str(viewer_path),
330+
"--server.port",
331+
str(port),
332+
"--server.headless",
333+
"true",
334+
"--browser.gatherUsageStats",
335+
"false",
336+
]
337+
sys.exit(stcli.main())
338+
339+
except ImportError:
340+
click.echo(
341+
click.style(
342+
"✗ Streamlit is not installed. Install with: pip install sfeos-tools[viewer]",
343+
fg="red",
344+
)
345+
)
346+
sys.exit(1)
347+
except KeyboardInterrupt:
348+
click.echo(click.style("\n✓ Viewer stopped", fg="yellow"))
349+
sys.exit(0)
350+
except Exception as e:
351+
error_msg = str(e)
352+
click.echo(click.style(f"✗ Failed to start viewer: {error_msg}", fg="red"))
353+
sys.exit(1)
354+
355+
278356
if __name__ == "__main__":
279357
cli()

0 commit comments

Comments
 (0)