Compare commits
31 Commits
5ffe050926
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
ba59f1f291 | ||
|
74ebf5fa8d | ||
|
a7bea3a401 | ||
|
49229bb8f3 | ||
|
e3c957319d | ||
|
d7d0bf7bcc | ||
|
2c167140db | ||
|
be63f17f13 | ||
|
f1b61c5f7c | ||
|
d4cb905813 | ||
|
a5cb4ba9f3 | ||
|
8860499ecf | ||
|
8e156e37b4 | ||
|
20858a6f58 | ||
|
d2bbf1083a | ||
|
d2d31dd803 | ||
|
0f02bc4a06 | ||
|
d17dc7d6e0 | ||
|
4208670245 | ||
|
5dd7297200 | ||
|
f81b319526 | ||
|
a78d82b05b | ||
|
971d7c55a0 | ||
|
6ad5994f67 | ||
|
e6824b23b7 | ||
|
ee685987c8 | ||
|
15415b6956 | ||
|
12db1d59c7 | ||
|
80e61c8c77 | ||
|
dc2090cab7 | ||
|
91e8fc7a36 |
23
.github/workflows/docs.yml
vendored
@@ -1,4 +1,8 @@
|
||||
name: Deploy Docs
|
||||
# Deploy Docs to GitHub Pages using MkDocs
|
||||
# This workflow builds documentation from the 'docs/' folder using mkdocs.yml in the repo root
|
||||
# and deploys the static site to GitHub Pages.
|
||||
|
||||
name: Build and Deploy Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -6,20 +10,31 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
build-and-deploy-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
python-version: '3.12'
|
||||
# Ensure mkdocs.yml exists in the repo root
|
||||
- name: Check for mkdocs.yml in root
|
||||
run: |
|
||||
if [ ! -f mkdocs.yml ]; then
|
||||
echo "Error: mkdocs.yml not found in repository root. Please add it." && exit 1
|
||||
fi
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install -r docs/requirements.txt
|
||||
- name: Build docs
|
||||
- name: Build docs with MkDocs
|
||||
run: |
|
||||
mkdocs build
|
||||
- name: List files after build
|
||||
run: |
|
||||
pwd
|
||||
ls -l
|
||||
ls -l site || true
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
|
4
.github/workflows/generate-readme.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install nbconvert
|
||||
run: |
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
- name: Execute the notebook (run all cells)
|
||||
run: |
|
||||
jupyter nbconvert --to notebook --execute notebooks/examples.ipynb --output notebooks/examples.ipynb
|
||||
jupyter nbconvert --to notebook --execute notebooks/examples.ipynb --output examples.ipynb --output-dir notebooks
|
||||
|
||||
- name: Run notebooks_to_readme.sh
|
||||
run: |
|
||||
|
4
.github/workflows/publish-package.yml
vendored
@@ -25,10 +25,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python 3.11
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.11
|
||||
python-version: 3.12
|
||||
|
||||
- name: Install build and twine
|
||||
run: |
|
||||
|
2
.github/workflows/test.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.11"]
|
||||
python-version: ["3.12"]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
1
.gitignore
vendored
Executable file → Normal file
@@ -47,3 +47,4 @@ SRTM1/
|
||||
# Ignore test and temp files
|
||||
*.tmp
|
||||
*.tmp.png
|
||||
prettymaps/presets/my-preset.json
|
0
MANIFEST.in
Executable file → Normal file
293
README.md
@@ -2,7 +2,9 @@
|
||||
|
||||
A minimal Python library to draw customized maps from [OpenStreetMap](https://www.openstreetmap.org/#map=12/11.0733/106.3078) created using the [osmnx](https://github.com/gboeing/osmnx), [matplotlib](https://matplotlib.org/), [shapely](https://shapely.readthedocs.io/en/stable/index.html) and [vsketch](https://github.com/abey79/vsketch) packages.
|
||||
|
||||

|
||||

|
||||
|
||||
# [](https://marceloprates.github.io/prettymaps/) [](https://pypi.org/project/prettymaps/) [](https://www.python.org/) [](LICENSE)
|
||||
|
||||
|
||||
This work is [licensed](LICENSE) under a GNU Affero General Public License v3.0 (you can make commercial use, distribute and modify this project, but must **disclose** the source code with the license and copyright notice)
|
||||
@@ -17,8 +19,7 @@ This work is [licensed](LICENSE) under a GNU Affero General Public License v3.0
|
||||
<a href='https://ko-fi.com/marceloprates_' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
||||
|
||||
## As seen on [Hacker News](https://web.archive.org/web/20210825160918/https://news.ycombinator.com/news):
|
||||

|
||||
|
||||

|
||||
## [prettymaps subreddit](https://www.reddit.com/r/prettymaps_/)
|
||||
## [Google Colaboratory Demo](https://colab.research.google.com/github/marceloprates/prettymaps/blob/master/notebooks/examples.ipynb)
|
||||
|
||||
@@ -70,7 +71,7 @@ import prettymaps
|
||||
plot = prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands')
|
||||
```
|
||||
|
||||
Fetching geodataframes took 2.04 seconds
|
||||
Fetching geodataframes took 14.43 seconds
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +94,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 0.81 seconds
|
||||
Fetching geodataframes took 5.48 seconds
|
||||
|
||||
|
||||
|
||||
@@ -185,21 +186,11 @@ prettymaps.presets()
|
||||
</tr>
|
||||
<tr>
|
||||
<th>8</th>
|
||||
<td>my-preset</td>
|
||||
<td>{'layers': {'building': {'tags': {'building': ...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>9</th>
|
||||
<td>plotter</td>
|
||||
<td>{'layers': {'perimeter': {}, 'streets': {'widt...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>10</th>
|
||||
<td>pytest-temp-preset</td>
|
||||
<td>{'layers': {'building': {'tags': {'building': ...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>11</th>
|
||||
<th>9</th>
|
||||
<td>tijuca</td>
|
||||
<td>{'layers': {'perimeter': {}, 'streets': {'widt...</td>
|
||||
</tr>
|
||||
@@ -221,7 +212,7 @@ prettymaps.preset('default')
|
||||
|
||||
|
||||
|
||||
Preset(params={'layers': {'perimeter': {}, 'streets': {'width': {'motorway': 5, 'trunk': 5, 'primary': 4.5, 'secondary': 4, 'tertiary': 3.5, 'cycleway': 3.5, 'residential': 3, 'service': 2, 'unclassified': 2, 'pedestrian': 2, 'footway': 1}}, 'waterway': {'tags': {'waterway': ['river', 'stream']}, 'width': {'river': 20, 'stream': 10}}, 'building': {'tags': {'building': True, 'landuse': 'construction'}}, 'water': {'tags': {'natural': ['water', 'bay']}}, 'sea': {}, 'forest': {'tags': {'landuse': 'forest'}}, 'green': {'tags': {'landuse': ['grass', 'orchard'], 'natural': ['island', 'wood', 'wetland'], 'leisure': 'park'}}, 'rock': {'tags': {'natural': 'bare_rock'}}, 'beach': {'tags': {'natural': 'beach'}}, 'parking': {'tags': {'amenity': 'parking', 'highway': 'pedestrian', 'man_made': 'pier'}}}, 'style': {'perimeter': {'fill': False, 'lw': 0, 'zorder': 0}, 'background': {'fc': '#F2F4CB', 'zorder': -1}, 'green': {'fc': '#8BB174', 'ec': '#2F3737', 'hatch_c': '#A7C497', 'hatch': 'ooo...', 'lw': 1, 'zorder': 1}, 'forest': {'fc': '#64B96A', 'ec': '#2F3737', 'lw': 1, 'zorder': 2}, 'water': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 99}, 'sea': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 99}, 'waterway': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 200}, 'beach': {'fc': '#FCE19C', 'ec': '#2F3737', 'hatch_c': '#d4d196', 'hatch': 'ooo...', 'lw': 1, 'zorder': 3}, 'parking': {'fc': '#F2F4CB', 'ec': '#2F3737', 'lw': 1, 'zorder': 3}, 'streets': {'fc': '#2F3737', 'ec': '#475657', 'alpha': 1, 'lw': 0, 'zorder': 4}, 'building': {'palette': ['#433633', '#FF5E5B'], 'ec': '#2F3737', 'lw': 0.5, 'zorder': 5}, 'rock': {'fc': '#BDC0BA', 'ec': '#2F3737', 'lw': 1, 'zorder': 6}}, 'circle': None, 'radius': 500})
|
||||
Preset(params={'layers': {'perimeter': {}, 'streets': {'width': {'motorway': 5, 'trunk': 5, 'primary': 4.5, 'secondary': 4, 'tertiary': 3.5, 'cycleway': 3.5, 'residential': 3, 'service': 2, 'unclassified': 2, 'pedestrian': 2, 'footway': 1}}, 'waterway': {'tags': {'waterway': ['river', 'stream']}, 'width': {'river': 20, 'stream': 10}}, 'building': {'tags': {'building': True, 'landuse': 'construction'}}, 'water': {'tags': {'natural': ['water', 'bay']}}, 'sea': {}, 'forest': {'tags': {'landuse': 'forest'}}, 'green': {'tags': {'landuse': ['grass', 'orchard'], 'natural': ['island', 'wood', 'wetland'], 'leisure': ['dog_park', 'disc_golf_course', 'garden', 'golf_course', 'park', 'pitch', 'sports_centre', 'track']}}, 'rock': {'tags': {'natural': 'bare_rock'}}, 'beach': {'tags': {'natural': 'beach'}}, 'parking': {'tags': {'amenity': 'parking', 'highway': 'pedestrian', 'man_made': 'pier'}}}, 'style': {'perimeter': {'fill': False, 'lw': 0, 'zorder': 0}, 'background': {'fc': '#F2F4CB', 'zorder': -1}, 'green': {'fc': '#8BB174', 'ec': '#2F3737', 'hatch_c': '#A7C497', 'hatch': 'ooo...', 'lw': 1, 'zorder': 1}, 'forest': {'fc': '#64B96A', 'ec': '#2F3737', 'lw': 1, 'zorder': 2}, 'water': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 99}, 'sea': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 99}, 'waterway': {'fc': '#a8e1e6', 'ec': '#2F3737', 'hatch_c': '#9bc3d4', 'hatch': 'ooo...', 'lw': 1, 'zorder': 200}, 'beach': {'fc': '#FCE19C', 'ec': '#2F3737', 'hatch_c': '#d4d196', 'hatch': 'ooo...', 'lw': 1, 'zorder': 3}, 'parking': {'fc': '#F2F4CB', 'ec': '#2F3737', 'lw': 1, 'zorder': 3}, 'streets': {'fc': '#2F3737', 'ec': '#475657', 'alpha': 1, 'lw': 0, 'zorder': 4}, 'building': {'palette': ['#433633', '#FF5E5B'], 'ec': '#2F3737', 'lw': 0.5, 'zorder': 5}, 'rock': {'fc': '#BDC0BA', 'ec': '#2F3737', 'lw': 1, 'zorder': 6}}, 'circle': None, 'radius': 500})
|
||||
|
||||
|
||||
|
||||
@@ -378,7 +369,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 15.97 seconds
|
||||
Fetching geodataframes took 20.74 seconds
|
||||
|
||||
|
||||
|
||||
@@ -402,7 +393,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 1.28 seconds
|
||||
Fetching geodataframes took 14.80 seconds
|
||||
|
||||
|
||||
|
||||
@@ -422,7 +413,7 @@ plot = prettymaps.plot('Centro Histórico, Porto Alegre', show = False)
|
||||
plot.geodataframes['building']
|
||||
```
|
||||
|
||||
Fetching geodataframes took 1.59 seconds
|
||||
Fetching geodataframes took 14.56 seconds
|
||||
|
||||
|
||||
|
||||
@@ -455,16 +446,16 @@ plot.geodataframes['building']
|
||||
<th>amenity</th>
|
||||
<th>operator</th>
|
||||
<th>website</th>
|
||||
<th>historic</th>
|
||||
<th>check_date</th>
|
||||
<th>...</th>
|
||||
<th>contact:website</th>
|
||||
<th>payment:lightning_contactless</th>
|
||||
<th>payment:onchain</th>
|
||||
<th>bus</th>
|
||||
<th>smoothness</th>
|
||||
<th>inscription</th>
|
||||
<th>ways</th>
|
||||
<th>type</th>
|
||||
<th>boat</th>
|
||||
<th>name:fr</th>
|
||||
<th>type</th>
|
||||
<th>building:part</th>
|
||||
<th>architect</th>
|
||||
</tr>
|
||||
@@ -472,7 +463,7 @@ plot.geodataframes['building']
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>(node, 2407915698)</th>
|
||||
<td>POINT (-51.23212 -30.03670)</td>
|
||||
<td>POINT (-51.23212 -30.0367)</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -495,14 +486,62 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(way, 126665330)</th>
|
||||
<td>POLYGON ((-51.23518 -30.03275, -51.23512 -30.0...</td>
|
||||
<th>(relation, 2798271)</th>
|
||||
<td>POLYGON ((-51.23097 -30.03377, -51.2309 -30.03...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>387</td>
|
||||
<td>NaN</td>
|
||||
<td>Praça Marechal Deodoro</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>https://www.estado.rs.gov.br/</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>Palais Piratini</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 2895718)</th>
|
||||
<td>POLYGON ((-51.23445 -30.03076, -51.23441 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>736</td>
|
||||
<td>Rua dos Andradas</td>
|
||||
<td>place_of_worship</td>
|
||||
<td>arts_centre</td>
|
||||
<td>NaN</td>
|
||||
<td>https://www.ccmq.com.br/</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>no</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 3532262)</th>
|
||||
<td>POLYGON ((-51.22935 -30.03693, -51.22923 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -512,23 +551,23 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(way, 126665331)</th>
|
||||
<td>POLYGON ((-51.23167 -30.03066, -51.23160 -30.0...</td>
|
||||
<th>(relation, 3532263)</th>
|
||||
<td>POLYGON ((-51.22916 -30.037, -51.22903 -30.036...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>1001</td>
|
||||
<td>Rua dos Andradas</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>https://www.ruadapraiashopping.com.br/</td>
|
||||
<td>parking</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
@@ -536,55 +575,7 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(way, 129176990)</th>
|
||||
<td>POLYGON ((-51.23117 -30.02891, -51.23120 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>1020</td>
|
||||
<td>Rua 7 de Setembro</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>http://www.memorial.rs.gov.br</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(way, 129176991)</th>
|
||||
<td>POLYGON ((-51.23153 -30.02914, -51.23156 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>Praça da Alfândega</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>https://www.margs.rs.gov.br/</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -615,8 +606,8 @@ plot.geodataframes['building']
|
||||
<td>...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 6760281)</th>
|
||||
<td>POLYGON ((-51.23238 -30.03337, -51.23223 -30.0...</td>
|
||||
<th>(way, 1082776706)</th>
|
||||
<td>POLYGON ((-51.22975 -30.02912, -51.22974 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -631,16 +622,16 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>[457506887, 457506886]</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 6760282)</th>
|
||||
<td>POLYGON ((-51.23203 -30.03340, -51.23203 -30.0...</td>
|
||||
<th>(way, 1082776707)</th>
|
||||
<td>POLYGON ((-51.22992 -30.02954, -51.22987 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -655,16 +646,16 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>[457506875, 457506889, 457506888]</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 6760283)</th>
|
||||
<td>POLYGON ((-51.23284 -30.03367, -51.23288 -30.0...</td>
|
||||
<th>(way, 1082787655)</th>
|
||||
<td>POLYGON ((-51.22601 -30.03038, -51.22602 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
@@ -679,64 +670,64 @@ plot.geodataframes['building']
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>[457506897, 457506896]</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>Theodor Wiederspahn</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 6760284)</th>
|
||||
<td>POLYGON ((-51.23499 -30.03412, -51.23498 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>[457506910, 457506913]</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(relation, 14393526)</th>
|
||||
<td>POLYGON ((-51.23125 -30.02813, -51.23128 -30.0...</td>
|
||||
<th>(way, 1354523569)</th>
|
||||
<td>POLYGON ((-51.23248 -30.03341, -51.23244 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>1044</td>
|
||||
<td>Rua Siqueira Campos</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>https://www.sefaz.rs.gov.br</td>
|
||||
<td>pharmacy</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>[236213286, 1081974882]</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>multipolygon</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>(way, 1423336172)</th>
|
||||
<td>POLYGON ((-51.23399 -30.03092, -51.23389 -30.0...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>788</td>
|
||||
<td>Rua dos Andradas</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>...</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
<td>NaN</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>2420 rows × 167 columns</p>
|
||||
<p>2415 rows × 137 columns</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -750,7 +741,7 @@ plot.geodataframes['building'][
|
||||
].geometry[0]
|
||||
```
|
||||
|
||||
/opt/anaconda3/envs/prettymaps/lib/python3.11/site-packages/geopandas/geoseries.py:648: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
|
||||
/opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/geopandas/geoseries.py:772: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
|
||||
val = getattr(super(), mtd)(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -777,7 +768,7 @@ plot = prettymaps.plot('Porto Alegre', show = False)
|
||||
# Get list of buildings from plot's geodataframes dict
|
||||
buildings = plot.geodataframes['building']
|
||||
# Project from lat / long
|
||||
buildings = ox.project_gdf(buildings)
|
||||
buildings = ox.projection.project_gdf(buildings)
|
||||
buildings = [b for b in buildings.geometry if b.area > 0]
|
||||
|
||||
# Draw Matplotlib mosaic of n x n building footprints
|
||||
@@ -797,7 +788,7 @@ for ax,building in zip(np.concatenate(axes),buildings):
|
||||
ax.autoscale(); ax.axis('off'); ax.axis('equal')
|
||||
```
|
||||
|
||||
Fetching geodataframes took 2.01 seconds
|
||||
Fetching geodataframes took 16.54 seconds
|
||||
|
||||
|
||||
|
||||
@@ -828,7 +819,7 @@ _ = plot.ax.set_title(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 3.78 seconds
|
||||
Fetching geodataframes took 12.52 seconds
|
||||
|
||||
|
||||
Use **plotter** mode to export a pen plotter-compatible SVG (thanks to abey79's amazing [vsketch](https://github.com/abey79/vsketch) library)
|
||||
@@ -847,7 +838,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 3.89 seconds
|
||||
Fetching geodataframes took 4.82 seconds
|
||||
|
||||
|
||||
|
||||
@@ -871,7 +862,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 16.55 seconds
|
||||
Fetching geodataframes took 23.53 seconds
|
||||
|
||||
|
||||
|
||||
@@ -972,14 +963,18 @@ plot = prettymaps.multiplot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 0.97 seconds
|
||||
Fetching geodataframes took 1.15 seconds
|
||||
Fetching geodataframes took 0.79 seconds
|
||||
Fetching geodataframes took 8.95 seconds
|
||||
|
||||
|
||||
Fetching geodataframes took 7.03 seconds
|
||||
|
||||
|
||||
Fetching geodataframes took 8.45 seconds
|
||||
|
||||
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
@@ -1002,15 +997,29 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 24.92 seconds
|
||||
Fetching geodataframes took 37.53 seconds
|
||||
|
||||
|
||||
make: Entering directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
curl -s -o spool/N21/N21W158.hgt.gz.temp https://s3.amazonaws.com/elevation-tiles-prod/skadi/N21/N21W158.hgt.gz && mv spool/N21/N21W158.hgt.gz.temp spool/N21/N21W158.hgt.gz
|
||||
|
||||
|
||||
gunzip spool/N21/N21W158.hgt.gz 2>/dev/null || touch spool/N21/N21W158.hgt
|
||||
gdal_translate -q -co TILED=YES -co COMPRESS=DEFLATE -co ZLEVEL=9 -co PREDICTOR=2 spool/N21/N21W158.hgt cache/N21/N21W158.tif 2>/dev/null || touch cache/N21/N21W158.tif
|
||||
|
||||
|
||||
rm spool/N21/N21W158.hgt
|
||||
make: Leaving directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
make: Entering directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
gdalbuildvrt -q -overwrite SRTM1.vrt cache/N21/N21W158.tif
|
||||
cp SRTM1.vrt SRTM1.5af18c5270144c688522a27abf3b23a0.vrt
|
||||
gdal_translate -q -co TILED=YES -co COMPRESS=DEFLATE -co ZLEVEL=9 -co PREDICTOR=2 -projwin -157.90125854957773 21.364471426268274 -157.81006761682832 21.244615177105377 SRTM1.5af18c5270144c688522a27abf3b23a0.vrt /Users/marceloprates/Projects/Art/07_Data_Visualization_and_Maps/prettymaps/notebooks/elevation.tif
|
||||
rm -f SRTM1.5af18c5270144c688522a27abf3b23a0.vrt
|
||||
make: Leaving directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
make: Entering directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
cp SRTM1.vrt SRTM1.3faa36cc8cab4dfda9edabe3b5a4ddc1.vrt
|
||||
make: Leaving directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
make: Entering directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
gdal_translate -q -co TILED=YES -co COMPRESS=DEFLATE -co ZLEVEL=9 -co PREDICTOR=2 -projwin -157.90125854957773 21.364471426268267 -157.81006761682832 21.244615177105388 SRTM1.3faa36cc8cab4dfda9edabe3b5a4ddc1.vrt /home/runner/work/prettymaps/prettymaps/notebooks/elevation.tif
|
||||
rm -f SRTM1.3faa36cc8cab4dfda9edabe3b5a4ddc1.vrt
|
||||
make: Leaving directory '/home/runner/work/prettymaps/prettymaps/notebooks/SRTM1'
|
||||
|
||||
|
||||
WARNING:matplotlib.axes._base:Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.
|
||||
@@ -1018,7 +1027,7 @@ plot = prettymaps.plot(
|
||||
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
@@ -1043,7 +1052,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 21.47 seconds
|
||||
Fetching geodataframes took 17.09 seconds
|
||||
|
||||
|
||||
|
||||
|
72
app.py
Executable file → Normal file
@@ -5,6 +5,16 @@ import sys
|
||||
import os
|
||||
import io
|
||||
|
||||
|
||||
def download_svg():
|
||||
"""
|
||||
Creates additional map in SVG format
|
||||
"""
|
||||
fig_path = "/tmp/generated_map_download.svg"
|
||||
plt.savefig(fig_path, format="svg", bbox_inches="tight", dpi=150)
|
||||
return fig_path
|
||||
|
||||
|
||||
# Set Streamlit to use the wide layout
|
||||
st.set_page_config(layout="wide")
|
||||
|
||||
@@ -65,8 +75,10 @@ with cols[0]:
|
||||
page_size_col, dpi_col = st.columns(2)
|
||||
with page_size_col:
|
||||
page_size = st.selectbox(
|
||||
"Page Size", ["A4", "A5", "Square"], index = 0
|
||||
#, "A3", "A2", "A1", "Custom"], index=0
|
||||
"Page Size",
|
||||
["A4", "A5", "Square"],
|
||||
index=0,
|
||||
# , "A3", "A2", "A1", "Custom"], index=0
|
||||
)
|
||||
with dpi_col:
|
||||
dpi = st.number_input("DPI", min_value=50, max_value=300, value=100, step=50)
|
||||
@@ -130,7 +142,7 @@ with cols[1]:
|
||||
use_container_width=True,
|
||||
)
|
||||
|
||||
if button: # or "last_image" in st.session_state:
|
||||
if button:
|
||||
hillshade_params = (
|
||||
{
|
||||
"azdeg": azdeg,
|
||||
@@ -166,23 +178,43 @@ with cols[1]:
|
||||
with open(fig_path, "wb") as f:
|
||||
f.write(st.session_state.last_image.getbuffer())
|
||||
|
||||
# Provide a download button
|
||||
with open(fig_path, "rb") as file:
|
||||
btn = st.download_button(
|
||||
label="Download Map",
|
||||
data=file,
|
||||
file_name=f"{query}.png",
|
||||
mime="image/png",
|
||||
use_container_width=True,
|
||||
)
|
||||
# Save SVG for persistent download
|
||||
svg_path = download_svg()
|
||||
st.session_state.last_png_path = fig_path
|
||||
st.session_state.last_svg_path = svg_path
|
||||
|
||||
st.image(st.session_state.last_image, use_container_width=True)
|
||||
# Always show download buttons (disabled if no image)
|
||||
png_ready = "last_png_path" in st.session_state and os.path.exists(
|
||||
st.session_state["last_png_path"]
|
||||
)
|
||||
svg_ready = "last_svg_path" in st.session_state and os.path.exists(
|
||||
st.session_state["last_svg_path"]
|
||||
)
|
||||
btn_cols = st.columns(2)
|
||||
with btn_cols[0]:
|
||||
st.download_button(
|
||||
label="Download PNG",
|
||||
data=open(st.session_state["last_png_path"], "rb") if png_ready else b"",
|
||||
file_name=f"{query}.png",
|
||||
mime="image/png",
|
||||
use_container_width=True,
|
||||
disabled=not png_ready,
|
||||
)
|
||||
with btn_cols[1]:
|
||||
st.download_button(
|
||||
label="Download SVG",
|
||||
data=open(st.session_state["last_svg_path"], "rb") if svg_ready else b"",
|
||||
file_name=f"{query}.svg",
|
||||
mime="image/svg",
|
||||
use_container_width=True,
|
||||
disabled=not svg_ready,
|
||||
)
|
||||
|
||||
# Always show image (generated or placeholder)
|
||||
if st.session_state.get("last_image"):
|
||||
st.image(st.session_state.last_image, use_container_width=True)
|
||||
else:
|
||||
if st.session_state.last_image:
|
||||
st.image(st.session_state.last_image, use_container_width=True)
|
||||
else:
|
||||
st.image(
|
||||
"https://github.com/marceloprates/prettymaps/blob/main/prints/app_placeholder.png?raw=true",
|
||||
use_container_width=True,
|
||||
)
|
||||
st.image(
|
||||
"https://github.com/marceloprates/prettymaps/blob/main/pictures/app_placeholder.png?raw=true",
|
||||
use_container_width=True,
|
||||
)
|
||||
|
18
docs/api.md
@@ -1,21 +1,7 @@
|
||||
# API Reference
|
||||
|
||||
This page documents the main modules and functions of the `prettymaps` library. The API documentation is auto-generated from the code and includes all public classes and functions.
|
||||
|
||||
## Modules
|
||||
|
||||
- **draw**: Core drawing and plotting functions, including map rendering, layer management, and style handling.
|
||||
- **fetch**: Functions for fetching and processing OpenStreetMap data and elevation.
|
||||
- **utils**: Utility functions for logging, timing, and other helpers.
|
||||
|
||||
---
|
||||
This section is auto-generated from the Prettymaps source code.
|
||||
|
||||
::: prettymaps.draw
|
||||
|
||||
---
|
||||
|
||||
::: prettymaps.fetch
|
||||
|
||||
---
|
||||
|
||||
::: prettymaps.utils
|
||||
::: prettymaps.fetch
|
@@ -1,27 +1,24 @@
|
||||
# prettymaps
|
||||
# Prettymaps Documentation
|
||||
|
||||
A minimal Python library to draw pretty maps from OpenStreetMap data.
|
||||
Welcome to the Prettymaps documentation site.
|
||||
|
||||
- [Usage](usage.md)
|
||||
- [API Reference](api.md)
|
||||
Prettymaps is a minimal Python library to draw beautiful maps from OpenStreetMap data.
|
||||
It allows you to easily generate artistic, customizable maps for any location in the world.
|
||||
|
||||
## Features
|
||||
- Draw beautiful maps from OSM data
|
||||
- Highly customizable layers and styles
|
||||
- Preset management
|
||||
- Keypoint highlighting
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
pip install prettymaps
|
||||
```
|
||||
- Fetches and visualizes OpenStreetMap data with minimal code
|
||||
- Highly customizable layers and styles
|
||||
- Supports elevation, hillshading, and keypoints
|
||||
- Preset system for reusable map styles
|
||||
- Export to PNG, SVG, and plotter-friendly formats
|
||||
|
||||
## Quick Example
|
||||
|
||||
```python
|
||||
import prettymaps
|
||||
prettymaps.plot("Porto Alegre")
|
||||
|
||||
prettymaps.plot("Porto Alegre, Brazil")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Data © OpenStreetMap contributors
|
||||
Explore the [Usage](usage.md) and [API Reference](api.md) for more details.
|
@@ -1,54 +1,41 @@
|
||||
# Usage
|
||||
|
||||
## Installation
|
||||
|
||||
Install Prettymaps and its dependencies:
|
||||
|
||||
```sh
|
||||
pip install prettymaps
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
The main entry point is the `plot()` function:
|
||||
Generate a map for a location:
|
||||
|
||||
```python
|
||||
import prettymaps
|
||||
prettymaps.plot("Porto Alegre")
|
||||
```
|
||||
|
||||
This will generate a map for the given location using default layers and styles.
|
||||
prettymaps.plot("Paris, France")
|
||||
```
|
||||
|
||||
## Customizing Layers and Styles
|
||||
|
||||
You can customize which OpenStreetMap layers are shown and how they are styled:
|
||||
You can customize which map layers to show and their appearance:
|
||||
|
||||
```python
|
||||
layers = {
|
||||
"perimeter": {},
|
||||
"streets": {"width": 8},
|
||||
"buildings": {},
|
||||
"water": {},
|
||||
}
|
||||
style = {
|
||||
"perimeter": {"fc": "#f2efe9"},
|
||||
"streets": {"fc": "#cccccc", "ec": "#333333"},
|
||||
"buildings": {"fc": "#bdbdbd"},
|
||||
"perimeter": {"fc": "#f2efe9", "ec": "#333"},
|
||||
"streets": {"fc": "#cccccc"},
|
||||
"buildings": {"fc": "#b0b0b0"},
|
||||
"water": {"fc": "#aadaff"},
|
||||
}
|
||||
prettymaps.plot("Porto Alegre", layers=layers, style=style)
|
||||
```
|
||||
|
||||
## Using Presets
|
||||
|
||||
Presets are reusable configurations for layers and styles. You can load, save, or update presets:
|
||||
|
||||
```python
|
||||
prettymaps.plot("Porto Alegre", preset="default")
|
||||
```
|
||||
|
||||
You can also create your own presets and save them for later use.
|
||||
|
||||
## Highlighting Keypoints
|
||||
|
||||
You can highlight specific keypoints (e.g., landmarks) on the map:
|
||||
|
||||
```python
|
||||
keypoints = {
|
||||
"tags": {"tourism": "attraction"},
|
||||
"kwargs": {"bbox": {"fc": "yellow"}},
|
||||
}
|
||||
prettymaps.plot("Porto Alegre", keypoints=keypoints)
|
||||
prettymaps.plot("Berlin, Germany", layers=layers, style=style)
|
||||
```
|
||||
|
||||
## Saving Maps
|
||||
@@ -56,9 +43,13 @@ prettymaps.plot("Porto Alegre", keypoints=keypoints)
|
||||
You can save the generated map to a file:
|
||||
|
||||
```python
|
||||
prettymaps.plot("Porto Alegre", save_as="map.png")
|
||||
prettymaps.plot("Tokyo, Japan", save_as="tokyo_map.png")
|
||||
```
|
||||
|
||||
---
|
||||
## Advanced Features
|
||||
|
||||
See the [API Reference](api.md) for details on all functions and parameters.
|
||||
- **Keypoints:** Highlight specific places or features on the map.
|
||||
- **Presets:** Save and reuse your favorite map styles.
|
||||
- **Hillshade:** Add elevation shading for a 3D effect.
|
||||
|
||||
See the [API Reference](api.md) for all available options.
|
678
notebooks/examples.ipynb
Executable file → Normal file
0
packages.txt
Executable file → Normal file
0
pictures/NFT_theft_AeternaCivitas.jpg
Executable file → Normal file
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
0
pictures/NFT_theft_geoart.jpg
Executable file → Normal file
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 3.4 MiB After Width: | Height: | Size: 3.6 MiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 2.4 MiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.6 MiB |
BIN
pictures/README/temp_readme_files/temp_readme_33_3.png
Normal file
After Width: | Height: | Size: 782 KiB |
BIN
pictures/README/temp_readme_files/temp_readme_35_5.png
Normal file
After Width: | Height: | Size: 6.6 MiB |
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.3 MiB |
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 958 KiB After Width: | Height: | Size: 1.1 MiB |
BIN
pictures/app_placeholder.png
Normal file
After Width: | Height: | Size: 913 KiB |
BIN
pictures/heerhugowaard.png
Normal file
After Width: | Height: | Size: 773 KiB |
0
prettymaps/__init__.py
Executable file → Normal file
12
prettymaps/draw.py
Executable file → Normal file
@@ -277,7 +277,7 @@ def gdf_to_shapely(
|
||||
|
||||
# Project gdf if applicable
|
||||
if not gdf.empty and gdf.crs is not None:
|
||||
gdf = ox.project_gdf(gdf)
|
||||
gdf = ox.projection.project_gdf(gdf)
|
||||
|
||||
if layer in ["streets", "railway", "waterway"]:
|
||||
geometries = graph_to_shapely(gdf, width)
|
||||
@@ -426,7 +426,7 @@ def plot_legends(
|
||||
texts = []
|
||||
for i in range(len(keypoints_df)):
|
||||
x, y = np.concatenate(
|
||||
ox.project_gdf(keypoints_df.iloc[[i]]).geometry.iloc[0].centroid.xy
|
||||
ox.projection.project_gdf(keypoints_df.iloc[[i]]).geometry.iloc[0].centroid.xy
|
||||
)
|
||||
name = keypoints_df.name.iloc[i]
|
||||
kwargs = keypoints_df.kwargs.iloc[i]
|
||||
@@ -554,7 +554,7 @@ def draw_hillshade(
|
||||
|
||||
min_x, max_x = ax.get_xlim()
|
||||
min_y, max_y = ax.get_ylim()
|
||||
min_lon, min_lat, max_lon, max_lat = ox.project_gdf(
|
||||
min_lon, min_lat, max_lon, max_lat = ox.projection.project_gdf(
|
||||
gdfs["perimeter"]
|
||||
).total_bounds
|
||||
ax.imshow(
|
||||
@@ -601,7 +601,7 @@ def create_background(
|
||||
|
||||
background = shapely.affinity.scale(
|
||||
box(
|
||||
*shapely.ops.unary_union(ox.project_gdf(gdfs["perimeter"]).geometry).bounds
|
||||
*shapely.ops.unary_union(ox.projection.project_gdf(gdfs["perimeter"]).geometry).bounds
|
||||
),
|
||||
background_pad,
|
||||
background_pad,
|
||||
@@ -670,7 +670,7 @@ def transform_gdfs(
|
||||
"""
|
||||
# Project geometries
|
||||
gdfs = {
|
||||
name: ox.project_gdf(gdf) if len(gdf) > 0 else gdf for name, gdf in gdfs.items()
|
||||
name: ox.projection.project_gdf(gdf) if len(gdf) > 0 else gdf for name, gdf in gdfs.items()
|
||||
}
|
||||
# Create geometry collection from gdfs' geometries
|
||||
collection = GeometryCollection(
|
||||
@@ -685,7 +685,7 @@ def transform_gdfs(
|
||||
gdfs[layer].geometry = list(collection.geoms[i].geoms)
|
||||
# Reproject
|
||||
if len(gdfs[layer]) > 0:
|
||||
gdfs[layer] = ox.project_gdf(gdfs[layer], to_crs="EPSG:4326")
|
||||
gdfs[layer] = ox.projection.project_gdf(gdfs[layer], to_crs="EPSG:4326")
|
||||
|
||||
return gdfs
|
||||
|
||||
|
30
prettymaps/fetch.py
Executable file → Normal file
@@ -95,7 +95,7 @@ def get_keypoints(
|
||||
Returns:
|
||||
geopandas.GeoDataFrame: A GeoDataFrame containing the keypoints that match the specified tags within the given perimeter.
|
||||
"""
|
||||
keypoints_df = ox.features_from_polygon(perimeter, tags=tags)
|
||||
keypoints_df = ox.features.features_from_polygon(perimeter, tags=tags)
|
||||
|
||||
return keypoints_df
|
||||
|
||||
@@ -150,7 +150,7 @@ def obtain_elevation(gdf):
|
||||
|
||||
raster = rxr.open_rasterio(output_file).squeeze()
|
||||
|
||||
raster = raster.rio.reproject(CRS.from_string(ox.project_gdf(gdf).crs.to_string()))
|
||||
raster = raster.rio.reproject(CRS.from_string(ox.projection.project_gdf(gdf).crs.to_string()))
|
||||
|
||||
# convert to numpy array
|
||||
elevation_data = raster.data
|
||||
@@ -200,9 +200,9 @@ def parse_query(query):
|
||||
def get_boundary(query, radius, circle=False, rotation=0):
|
||||
|
||||
# Get point from query
|
||||
point = query if parse_query(query) == "coordinates" else ox.geocode(query)
|
||||
point = query if parse_query(query) == "coordinates" else ox.geocoder.geocode(query)
|
||||
# Create GeoDataFrame from point
|
||||
boundary = ox.project_gdf(
|
||||
boundary = ox.projection.project_gdf(
|
||||
GeoDataFrame(geometry=[Point(point[::-1])], crs="EPSG:4326")
|
||||
)
|
||||
|
||||
@@ -252,19 +252,19 @@ def get_perimeter(
|
||||
perimeter = query
|
||||
else:
|
||||
# Fetch perimeter from OSM
|
||||
perimeter = ox.geocode_to_gdf(
|
||||
perimeter = ox.geocoder.geocode_to_gdf(
|
||||
query,
|
||||
by_osmid=by_osmid,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# Scale according to aspect ratio
|
||||
perimeter = ox.project_gdf(perimeter)
|
||||
perimeter = ox.projection.project_gdf(perimeter)
|
||||
perimeter.loc[0, "geometry"] = scale(perimeter.loc[0, "geometry"], aspect_ratio, 1)
|
||||
perimeter = perimeter.to_crs(4326)
|
||||
|
||||
# Apply dilation
|
||||
perimeter = ox.project_gdf(perimeter)
|
||||
perimeter = ox.projection.project_gdf(perimeter)
|
||||
if dilate is not None:
|
||||
perimeter.geometry = perimeter.geometry.buffer(dilate)
|
||||
perimeter = perimeter.to_crs(4326)
|
||||
@@ -404,7 +404,7 @@ def get_gdf(
|
||||
|
||||
# Apply tolerance to the perimeter
|
||||
perimeter_with_tolerance = (
|
||||
ox.project_gdf(perimeter).buffer(perimeter_tolerance).to_crs(4326)
|
||||
ox.projection.project_gdf(perimeter).buffer(perimeter_tolerance).to_crs(4326)
|
||||
)
|
||||
perimeter_with_tolerance = unary_union(perimeter_with_tolerance.geometry).buffer(0)
|
||||
|
||||
@@ -423,7 +423,7 @@ def get_gdf(
|
||||
elif layer == "sea":
|
||||
# Fetch geometries from OSM
|
||||
coastline = unary_union(
|
||||
ox.features_from_polygon(
|
||||
ox.features.features_from_polygon(
|
||||
bbox, tags={"natural": "coastline"}
|
||||
).geometry.tolist()
|
||||
)
|
||||
@@ -461,11 +461,11 @@ def get_gdf(
|
||||
else:
|
||||
if osmid is None:
|
||||
# Fetch geometries from OSM
|
||||
gdf = ox.features_from_polygon(
|
||||
gdf = ox.features.features_from_polygon(
|
||||
bbox, tags={tags: True} if type(tags) == str else tags
|
||||
)
|
||||
else:
|
||||
gdf = ox.geocode_to_gdf(osmid, by_osmid=True)
|
||||
gdf = ox.geocoder.geocode_to_gdf(osmid, by_osmid=True)
|
||||
except Exception as e:
|
||||
# print(f"Error fetching {layer}: {e}")
|
||||
gdf = GeoDataFrame(geometry=[])
|
||||
@@ -584,7 +584,7 @@ def unified_osm_request(
|
||||
dict: Dictionary of GeoDataFrames for each layer.
|
||||
"""
|
||||
# Apply tolerance to the perimeter
|
||||
perimeter_with_tolerance = ox.project_gdf(perimeter).buffer(0).to_crs(4326)
|
||||
perimeter_with_tolerance = ox.projection.project_gdf(perimeter).buffer(0).to_crs(4326)
|
||||
perimeter_with_tolerance = unary_union(perimeter_with_tolerance.geometry).buffer(0)
|
||||
|
||||
# Fetch from perimeter's bounding box, to avoid missing some geometries
|
||||
@@ -605,7 +605,7 @@ def unified_osm_request(
|
||||
|
||||
# Fetch all features in one request
|
||||
try:
|
||||
all_features = ox.features_from_polygon(bbox, tags=combined_tags)
|
||||
all_features = ox.features.features_from_polygon(bbox, tags=combined_tags)
|
||||
except Exception as e:
|
||||
all_features = GeoDataFrame(geometry=[])
|
||||
|
||||
@@ -624,7 +624,7 @@ def unified_osm_request(
|
||||
elif layer == "sea":
|
||||
try:
|
||||
coastline = unary_union(
|
||||
ox.features_from_polygon(
|
||||
ox.features.features_from_polygon(
|
||||
bbox, tags={"natural": "coastline"}
|
||||
).geometry.tolist()
|
||||
)
|
||||
@@ -682,7 +682,7 @@ def unified_osm_request(
|
||||
]
|
||||
gdf = pd.concat([gdf, filtered_features], axis=0)
|
||||
else:
|
||||
gdf = ox.geocode_to_gdf(kwargs.get("osmid"), by_osmid=True)
|
||||
gdf = ox.geocoder.geocode_to_gdf(kwargs.get("osmid"), by_osmid=True)
|
||||
|
||||
gdf = gdf.copy()
|
||||
gdf.geometry = gdf.geometry.intersection(perimeter_with_tolerance)
|
||||
|
0
prettymaps/presets/abraca-redencao.json
Executable file → Normal file
0
prettymaps/presets/barcelona-plotter.json
Executable file → Normal file
0
prettymaps/presets/barcelona.json
Executable file → Normal file
0
prettymaps/presets/cb-bf-f.json
Executable file → Normal file
13
prettymaps/presets/default.json
Executable file → Normal file
@@ -54,7 +54,16 @@
|
||||
"wood",
|
||||
"wetland"
|
||||
],
|
||||
"leisure": "park"
|
||||
"leisure": [
|
||||
"dog_park",
|
||||
"disc_golf_course",
|
||||
"garden",
|
||||
"golf_course",
|
||||
"park",
|
||||
"pitch",
|
||||
"sports_centre",
|
||||
"track"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rock": {
|
||||
@@ -162,4 +171,4 @@
|
||||
},
|
||||
"circle": null,
|
||||
"radius": 500
|
||||
}
|
||||
}
|
||||
|
0
prettymaps/presets/heerhugowaard.json
Executable file → Normal file
0
prettymaps/presets/macao.json
Executable file → Normal file
0
prettymaps/presets/minimal.json
Executable file → Normal file
0
prettymaps/presets/plotter.json
Executable file → Normal file
0
prettymaps/presets/tijuca.json
Executable file → Normal file
0
prettymaps/utils.py
Executable file → Normal file
6
requirements.txt
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
numpy>=1.20,<1.25
|
||||
numpy>=1.26.4
|
||||
matplotlib>=3.9.0
|
||||
shapely>=2.0.0
|
||||
osmnx>=1.9.3,<2.0
|
||||
osmnx>=2.0.5
|
||||
ipykernel>=6.29.5
|
||||
rasterio>=1.4.3
|
||||
rioxarray>=0.18.2
|
||||
@@ -12,4 +12,4 @@ thefuzz>=0.22.1
|
||||
elevation>=1.1.3
|
||||
streamlit>=1.42.2
|
||||
tqdm>=4.67.1
|
||||
scikit-learn>=1.6.1
|
||||
scikit-learn>=1.6.1
|
||||
|
2
scripts/notebooks_to_readme.sh
Normal file → Executable file
@@ -27,7 +27,7 @@ mv "$PICTURES_DIR/temp_readme.md" "$README_FILE"
|
||||
# (No-op if already in place)
|
||||
|
||||
# Update image links in README.md to point to pictures/README/
|
||||
sed -i '' 's|(temp_readme_files/|(pictures/README/temp_readme_files/|g' "$README_FILE"
|
||||
sed -i 's|(temp_readme_files/|(pictures/README/temp_readme_files/|g' "$README_FILE"
|
||||
|
||||
# Optionally, clean up any old temp_readme_files in root
|
||||
# rm -rf temp_readme_files
|
||||
|
2
setup.py
Executable file → Normal file
@@ -22,5 +22,5 @@ setup(
|
||||
],
|
||||
package_dir={"prettymaps": "prettymaps"},
|
||||
package_data={"prettymaps": ["presets/*.json"]},
|
||||
python_requires=">=3.11",
|
||||
python_requires=">=3.12",
|
||||
)
|
||||
|
6
setup.sh
@@ -15,7 +15,7 @@ if [[ "$OS" == "Linux" ]]; then
|
||||
# Linux (Debian/Ubuntu)
|
||||
echo "Updating package list and installing dependencies for Linux..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential make gcc python3-dev libgdal-dev gdal-bin
|
||||
sudo apt-get install -y build-essential make gcc libgdal-dev gdal-bin
|
||||
sudo apt-get clean
|
||||
|
||||
elif [[ "$OS" == "Darwin" ]]; then
|
||||
@@ -34,14 +34,10 @@ elif [[ "$OS" =~ "MINGW" || "$OS" =~ "MSYS" || "$OS" =~ "CYGWIN" ]]; then
|
||||
echo "- GDAL (https://gdal.org/download.html or via Conda: conda install -c conda-forge gdal)"
|
||||
echo "- Make and GCC (optional, for advanced features)"
|
||||
echo "- Python 3 and pip"
|
||||
echo "Then run: pip install -e ."
|
||||
exit 0
|
||||
else
|
||||
echo "Unsupported OS: $OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install Python dependencies
|
||||
pip install -e .
|
||||
|
||||
echo "Setup complete!"
|