Compare commits
29 Commits
5ffe050926
...
pr-136
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
21
.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,7 +10,7 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
build-and-deploy-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -14,12 +18,23 @@ jobs:
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
# 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:
|
||||
|
2
.github/workflows/generate-readme.yml
vendored
@@ -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: |
|
||||
|
0
.gitignore
vendored
Executable file → Normal file
0
MANIFEST.in
Executable file → Normal file
77
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 13.14 seconds
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +94,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 0.81 seconds
|
||||
Fetching geodataframes took 4.78 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>
|
||||
@@ -378,7 +369,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 15.97 seconds
|
||||
Fetching geodataframes took 27.07 seconds
|
||||
|
||||
|
||||
|
||||
@@ -402,7 +393,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 1.28 seconds
|
||||
Fetching geodataframes took 11.25 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 12.99 seconds
|
||||
|
||||
|
||||
|
||||
@@ -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.11.13/x64/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]`
|
||||
val = getattr(super(), mtd)(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -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 12.91 seconds
|
||||
|
||||
|
||||
|
||||
@@ -828,7 +819,7 @@ _ = plot.ax.set_title(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 3.78 seconds
|
||||
Fetching geodataframes took 12.92 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 3.91 seconds
|
||||
|
||||
|
||||
|
||||
@@ -871,7 +862,7 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 16.55 seconds
|
||||
Fetching geodataframes took 27.11 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.20 seconds
|
||||
|
||||
|
||||
Fetching geodataframes took 6.59 seconds
|
||||
|
||||
|
||||
Fetching geodataframes took 8.09 seconds
|
||||
|
||||
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
@@ -1002,15 +997,29 @@ plot = prettymaps.plot(
|
||||
)
|
||||
```
|
||||
|
||||
Fetching geodataframes took 24.92 seconds
|
||||
Fetching geodataframes took 47.61 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.65e8f0bb4b43451a865dc35dca4158a5.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.65e8f0bb4b43451a865dc35dca4158a5.vrt /home/runner/work/prettymaps/prettymaps/notebooks/elevation.tif
|
||||
rm -f SRTM1.65e8f0bb4b43451a865dc35dca4158a5.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.57 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.
|
710
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: 65 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: 779 KiB |
BIN
pictures/README/temp_readme_files/temp_readme_35_5.png
Normal file
After Width: | Height: | Size: 6.2 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!"
|