Skip to content

Commit e93ff94

Browse files
committed
v1.9.0
2 parents 1312343 + 0d111ac commit e93ff94

15 files changed

+227
-211
lines changed

Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ daemon:
1414
docker run --rm -itd --volume "$(shell pwd)/data:/app/data:ro" -p 5000:5000 opentopodata:$(VERSION)
1515

1616
test: build black-check
17-
docker run --rm -e DISABLE_MEMCACHE=1 --volume "$(shell pwd)/htmlcov:/app/htmlcov" opentopodata:$(VERSION) pytest --ignore=data --ignore=scripts --cov=opentopodata --cov-report html
17+
docker run --rm -e DISABLE_MEMCACHE=1 --volume "$(shell pwd)/htmlcov:/app/htmlcov" opentopodata:$(VERSION) python -m pytest --ignore=data --ignore=scripts --cov=opentopodata --cov-report html --timeout=10
1818

1919
test-m1: build-m1 black-check
20-
docker run --rm -e DISABLE_MEMCACHE=1 --volume "$(shell pwd)/htmlcov:/app/htmlcov" opentopodata:$(VERSION) pytest --ignore=data --ignore=scripts --cov=opentopodata --cov-report html
20+
docker run --rm -e DISABLE_MEMCACHE=1 --volume "$(shell pwd)/htmlcov:/app/htmlcov" opentopodata:$(VERSION) python -m pytest --ignore=data --ignore=scripts --cov=opentopodata --cov-report html --timeout=10
2121

2222
run-local:
2323
FLASK_APP=opentopodata/api.py FLASK_DEBUG=1 flask run --port 5000
@@ -26,11 +26,11 @@ black:
2626
black --target-version py39 tests opentopodata
2727

2828
black-check:
29-
docker run --rm opentopodata:$(VERSION) black --check --target-version py39 tests opentopodata
29+
docker run --rm opentopodata:$(VERSION) python -m black --check --target-version py39 tests opentopodata
3030

3131
update-requirements: build
3232
# pip-compile gets confused if there's already a requirements.txt file, and
3333
# it can't be deleted without breaking the docker mount. So instead do the
3434
# compiling in /tmp. Should run test suite afterwards.
35-
docker run --rm -v $(shell pwd)/requirements.txt:/app/requirements.txt -w /tmp opentopodata:$(VERSION) /bin/bash -c "cp /app/requirements.in .; pip-compile requirements.in; cp requirements.txt /app/requirements.txt"
35+
docker run --rm -v $(shell pwd)/requirements.txt:/app/requirements.txt -w /tmp opentopodata:$(VERSION) /bin/bash -c "cp /app/requirements.in .; pip-compile requirements.in --resolver backtracking; cp requirements.txt /app/requirements.txt"
3636

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.8.3
1+
1.9.0

docker/Dockerfile

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Container for packages that need to be built from source but have massive dev dependencies.
2-
FROM python:3.9.16-slim-bullseye as builder
2+
FROM python:3.11.8-slim-bookworm as builder
33
RUN set -e && \
44
apt-get update && \
55
apt-get install -y --no-install-recommends \
66
gcc \
7-
python3.9-dev
7+
python3.11-dev
88

99
RUN pip config set global.disable-pip-version-check true && \
10-
pip wheel --wheel-dir=/root/wheels uwsgi==2.0.21 && \
11-
pip wheel --wheel-dir=/root/wheels regex==2022.10.31
10+
pip wheel --wheel-dir=/root/wheels uwsgi==2.0.24 && \
11+
pip wheel --wheel-dir=/root/wheels regex==2023.12.25
1212

1313
# The actual container.
14-
FROM python:3.9.16-slim-bullseye
14+
FROM python:3.11.8-slim-bookworm
1515
RUN set -e && \
1616
apt-get update && \
1717
apt-get install -y --no-install-recommends \

docker/apple-silicon.Dockerfile

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# It works just the same as the main image, but is much larger and slower to
66
# build.
77

8-
FROM osgeo/gdal:ubuntu-full-3.5.2
8+
FROM ghcr.io/osgeo/gdal:ubuntu-full-3.6.4
9+
RUN python --version
910
RUN set -e && \
1011
apt-get update && \
1112
apt-get install -y --no-install-recommends \
@@ -16,7 +17,7 @@ RUN set -e && \
1617
g++ \
1718
supervisor \
1819
libmemcached-dev \
19-
python3.8-dev && \
20+
python3.10-dev && \
2021
rm -rf /var/lib/apt/lists/*
2122

2223
COPY requirements.txt /app/requirements.txt

docs/api.md

+53-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Latitudes and longitudes should be in `EPSG:4326` (also known as WGS-84 format),
2424
* The default option `null` makes NODATA indistinguishable from a location outside the dataset bounds.
2525
* `NaN` (not a number) values aren't valid in json and will break some clients. The `nan` option was default before version 1.4 and is provided only for backwards compatibility.
2626
* When querying multiple datasets, this NODATA replacement only applies to the last dataset in the stack.
27+
* `format`: Either `json` or `geojson`. Default: `json`.
2728

2829

2930

@@ -47,14 +48,11 @@ Some notes about the elevation value:
4748
* Unless the `nodata_value` parameter is set, a `null` elevation could either mean the location is outside the dataset bounds, or a NODATA within the raster bounds.
4849

4950

50-
5151
### Example
5252

5353
`GET` <a href="https://api.opentopodata.org/v1/srtm90m?locations=-43.5,172.5|27.6,1.98&interpolation=cubic">api.opentopodata.org/v1/srtm90m?locations=-43.5,172.5|27.6,1.98&interpolation=cubic</a>
5454

5555

56-
57-
5856
```json
5957
{
6058
"results": [
@@ -79,6 +77,58 @@ Some notes about the elevation value:
7977
}
8078
```
8179

80+
81+
### GeoJSON response
82+
83+
If `format=geojson` is passed, you get a `FeatureCollection` of `Point` geometries instead. Each feature has its elevation as the `z` coordinate, and a `dataset` property specifying the source (corresponding to `results[].dataset` in the regular json response):
84+
85+
86+
### GeoJSON example
87+
88+
89+
`GET` <a href="https://api.opentopodata.org/v1/srtm90m?locations=-43.5,172.5|27.6,1.98&interpolation=cubic&format=geojson">api.opentopodata.org/v1/srtm90m?locations=-43.5,172.5|27.6,1.98&interpolation=cubic&format=geojson</a>
90+
91+
92+
93+
94+
```json
95+
{
96+
"features": [
97+
{
98+
"geometry": {
99+
"coordinates": [
100+
172.5,
101+
-43.5,
102+
45
103+
],
104+
"type": "Point"
105+
},
106+
"properties": {
107+
"dataset": "srtm90m"
108+
},
109+
"type": "Feature"
110+
},
111+
{
112+
"geometry": {
113+
"coordinates": [
114+
1.98,
115+
27.6,
116+
402
117+
],
118+
"type": "Point"
119+
},
120+
"properties": {
121+
"dataset": "srtm90m"
122+
},
123+
"type": "Feature"
124+
}
125+
],
126+
"type": "FeatureCollection"
127+
}
128+
```
129+
130+
131+
82132
---
83133

84134

docs/changelog.md

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
This is a list of changes to Open Topo Data between each release.
44

55

6+
## Version 1.9.0 (19 Feb 2024)
7+
* Dependency upgrades, including python to 3.11 and rasterio to 1.3.9
8+
* Add support for geojson responses ([#86](https://github.com/ajnisbet/opentopodata/pull/86), thanks [@arnesetzer](https://github.com/arnesetzer)!)
9+
* Fix handling of preflight requests ([#93](https://github.com/ajnisbet/opentopodata/issues/93), thanks [@MaRaSu](https://github.com/MaRaSu)!)
10+
* Fix error message bug ([#70](https://github.com/ajnisbet/opentopodata/pull/70), thanks [@khendrickx](https://github.com/khendrickx)!)
11+
12+
13+
614
## Version 1.8.3 (7 Feb 2023)
715

816
* Fix memory leak ([#68](https://github.com/ajnisbet/opentopodata/issues/68))

docs/datasets/eudem.md

+8-114
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,25 @@ The advantage of the `NODATA` oceans is that you cane use EU-DEM without clippin
3030

3131
## Adding EU-DEM to Open Topo Data
3232

33+
As of Jan 2024, EU-DEM is no longer available to download via copernicus.eu.
3334

34-
Make a new folder for the dataset:
35+
I have uploaded my version of the dataset at [https://files.gpxz.io/eudem_buffered.zip](https://files.gpxz.io/eudem_buffered.zip), see [EUDEM download](https://www.gpxz.io/blog/eudem) for more details.
3536

36-
```bash
37-
mkdir ./data/eudem
38-
```
39-
40-
Download the dataset from [Copernicus](https://land.copernicus.eu/imagery-in-situ/eu-dem/eu-dem-v1.1?tab=download). There are 27 files. Unzip them and move all the `.TIF` files into the data folder (you don't need the `.aux.xml`, `.ovr`, or `.TFw` files).
41-
42-
Your data folder should now contain only 27 TIF files:
37+
Download and unzip the folder into:
4338

4439
```bash
45-
ls ./data/eudem
46-
47-
# eu_dem_v11_E00N20.TIF
48-
# eu_dem_v11_E10N00.TIF
49-
# eu_dem_v11_E10N10.TIF
50-
# ...
51-
```
52-
53-
54-
If you have [gdal](https://gdal.org) installed, the easiest thing to do here is build a [VRT](https://gdal.org/drivers/raster/vrt.html) - a single raster file that links to the 27 tiles and which Open Topo Data can treat as a single-file dataset.
55-
56-
```bash
57-
mkdir ./data/eudem-vrt
58-
cd ./data/eudem-vrt
59-
gdalbuildvrt -tr 25 25 -tap -te 0 0 8000000 6000000 eudem.vrt ../eudem/*.TIF
60-
cd ../../
40+
mkdir ./data/eudem
6141
```
62-
63-
The `tr`, `tap`, and `te` options in the above command ensure that slices from the VRT will use the exact values and grid of the source rasters.
64-
42+
There are 27 files.
6543

6644
Then create a `config.yaml` file:
6745

6846
```yaml
6947
datasets:
7048
- name: eudem25m
71-
path: data/eudem-vrt/
49+
path: data/eudem
50+
filename_epsg: 3035
51+
filename_tile_size: 1000000
7252
```
7353
7454
Finally, rebuild to enable the new dataset at [localhost:5000/v1/eudem25m?locations=51.575,-3.220](http://localhost:5000/v1/eudem25m?locations=51.575,-3.220).
@@ -82,92 +62,6 @@ make build && make run
8262
If you don't have gdal installed, you can use the tiles directly. There are instructions for this [here](https://github.com/ajnisbet/opentopodata/blob/f012ec136bebcd97e1dc05645e91a6d2487127dc/docs/datasets/eudem.md#adding-eu-dem-to-open-topo-data), but because the EU-DEM tiles don't come with an overlap you will get a `null` elevation at locations within 0.5 pixels of tile edges.
8363

8464

85-
### Buffering tiles (optional)
86-
87-
The tiles provided by EU-DEM don't overlap and cover slightly less than a 1000km square. This means you'll get a `null` result for coordinates along the tile edges.
88-
89-
The `.vrt` approach above solves the overlap issue, but for improved performance you can leave the tiles separate and add a buffer to each one. This is the code I used on the public API to do this:
90-
91-
92-
```python
93-
import os
94-
from glob import glob
95-
import subprocess
96-
97-
import rasterio
98-
99-
100-
# Prepare paths.
101-
input_pattern = 'data/eudem/*.TIF'
102-
input_paths = sorted(glob(input_pattern))
103-
assert input_paths
104-
vrt_path = 'data/eudem-vrt/eudem.vrt'
105-
output_dir = 'data/eudem-buffered/'
106-
os.makedirs(output_dir, exist_ok=True)
107-
108-
109-
110-
# EU-DEM specific options.
111-
tile_size = 1_000_000
112-
buffer_size = 50
113-
114-
for input_path in input_paths:
115-
116-
# Get tile bounds.
117-
with rasterio.open(input_path) as f:
118-
bottom = int(f.bounds.bottom)
119-
left = int(f.bounds.left)
120-
121-
# For EU-DEM only: round this partial tile down to the nearest tile_size.
122-
if left == 943750:
123-
left = 0
124-
125-
# New tile name in SRTM format.
126-
output_name = 'N' + str(bottom).zfill(7) + 'E' + str(left).zfill(7) + '.TIF'
127-
output_path = os.path.join(output_dir, output_name)
128-
129-
# New bounds.
130-
xmin = left - buffer_size
131-
xmax = left + tile_size + buffer_size
132-
ymin = bottom - buffer_size
133-
ymax = bottom + tile_size + buffer_size
134-
135-
# EU-DEM tiles don't cover negative locations.
136-
xmin = max(0, xmin)
137-
ymin = max(0, ymin)
138-
139-
# Do the transformation.
140-
cmd = [
141-
'gdal_translate',
142-
'-a_srs', 'EPSG:3035', # EU-DEM crs.
143-
'-co', 'NUM_THREADS=ALL_CPUS',
144-
'-co', 'COMPRESS=DEFLATE',
145-
'-co', 'BIGTIFF=YES',
146-
'--config', 'GDAL_CACHEMAX','512',
147-
'-projwin', str(xmin), str(ymax), str(xmax), str(ymin),
148-
vrt_path, output_path,
149-
]
150-
r = subprocess.run(cmd)
151-
r.check_returncode()
152-
```
153-
154-
These new files can be used in Open Topo Data with the following `config.yaml` file
155-
156-
157-
```yaml
158-
datasets:
159-
- name: eudem25m
160-
path: data/eudem-buffered/
161-
filename_epsg: 3035
162-
filename_tile_size: 1000000
163-
```
164-
165-
and rebuilding:
166-
167-
```bash
168-
make build && make run
169-
```
170-
17165

17266

17367
## Public API

docs/notes/kubernetes.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,9 @@ spec:
8282
- containerPort: 5000
8383

8484
restartPolicy: Always
85-
```
85+
```
86+
87+
88+
---
89+
90+
Thanks to [@khintz](https://github.com/khintz) for contributing this documentation in [#57](https://github.com/ajnisbet/opentopodata/pull/57)!

docs/notes/performance-optimisation.md

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Batch request are faster (per point queried) than single-point requests, and lar
1919

2020
Batch queries are fastest if the points are located next to each other. Sorting the locations you are querying before batching will improve performance. Ideally sort by some block-level attribute like postal code or state/county/region, or by something like `round(lat, 1), round(lon, 1)` depending on your tile size.
2121

22+
If the requests are very large and the server has several CPU cores, try splitting the request and sending it simultaneously. The optimum for the number of requests is slightly higher than the amount of CPU cores used by Open Topo Data. The number of CPU cores used is displayed when OpenTopodata is started. If you missed the log message, you can find iw with the following command:
23+
```bash
24+
docker logs {NAME_OF_CONTAINER} 2>&1 | grep "CPU cores"
25+
```
2226

2327

2428
## Dataset format

docs/notes/running-without-docker.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ git clone https://github.com/ajnisbet/opentopodata.git
1717
cd opentopodata
1818
```
1919

20-
Install system dependencies
20+
Install system dependencies (if you're not using Debian 10, install whatever python3.X-dev matches your installed python)L
2121

2222
```bash
2323
apt install gcc python3.7-dev python3-pip
2424
```
2525

26-
Debian 10 comes with an old version of pip, it needs to be updated:
26+
Debian 10 comes with an old version of pip, it needs to be updated so we can install wheels:
2727

2828
```bash
2929
pip3 install --upgrade pip
@@ -38,7 +38,7 @@ cat requirements.txt | grep pyproj
3838
and install that pinned version
3939

4040
```bash
41-
pip3 install pyproj==3.0.0.post1
41+
pip3 install pyproj==3.4.1
4242
```
4343

4444
then the remaining python packages can be installed:
@@ -133,4 +133,9 @@ Then manage Open Topo Data with
133133
systemctl daemon-reload
134134
systemctl enable opentopodata.service
135135
systemctl start opentopodata.service
136-
```
136+
```
137+
138+
!!! warning "Warning"
139+
Opentopodata caches `config.yaml` in two places: memcache and uwsgi.
140+
141+
If you update the config file (to eg add a new dataset) you'll need to restart memcached **first**, then opentopodata.

example-config.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
# 400 error will be thrown above this limit.
66
max_locations_per_request: 100
77

8+
89
# CORS header. Should be null for no CORS, '*' for all domains, or a url with
910
# protocol, domain, and port ('https://api.example.com/'). Default is null.
1011
access_control_allow_origin: "*"
1112

13+
1214
datasets:
1315

1416
# A small testing dataset is included in the repo.

0 commit comments

Comments
 (0)