mirror of
https://github.com/marceloprates/prettymaps.git
synced 2025-09-09 05:30:52 +02:00
Compare commits
13 Commits
c7d0ab8548
...
9141ae3377
Author | SHA1 | Date | |
---|---|---|---|
|
9141ae3377 | ||
|
dd05f6094d | ||
|
fe3d73c2c9 | ||
|
726fb4c67c | ||
|
d85ab21070 | ||
|
f62ed5fbb7 | ||
|
598aa6b0ef | ||
|
b8c7abc10f | ||
|
6ad8f8a1a9 | ||
|
ded7e41e08 | ||
|
7c8d465e55 | ||
|
da87a351ef | ||
|
98eabec453 |
0
.github/FUNDING.yml
vendored
Executable file → Normal file
0
.github/FUNDING.yml
vendored
Executable file → Normal file
0
.github/workflows/publish-package.yml
vendored
Executable file → Normal file
0
.github/workflows/publish-package.yml
vendored
Executable file → Normal file
0
.gitignore
vendored
Executable file → Normal file
0
.gitignore
vendored
Executable file → Normal file
0
MANIFEST.in
Executable file → Normal file
0
MANIFEST.in
Executable file → Normal file
134
app.py
134
app.py
@@ -1,9 +1,20 @@
|
||||
import streamlit as st
|
||||
import logging
|
||||
from matplotlib import pyplot as plt
|
||||
import sys
|
||||
import os
|
||||
import io
|
||||
|
||||
# Set Streamlit to use the wide layout
|
||||
st.set_page_config(layout="wide")
|
||||
|
||||
# Add repo root to sys.path
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
||||
import prettymaps
|
||||
|
||||
# Initialize session state for last_image
|
||||
if "last_image" not in st.session_state:
|
||||
st.session_state.last_image = None
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
@@ -19,16 +30,29 @@ with cols[0]:
|
||||
query = st.text_area(
|
||||
"Location", value="Stad van de Zon, Heerhugowaard, Netherlands", height=86
|
||||
)
|
||||
radius = st.slider("Radius (km)", 0.5, 10.0, 0.1, step=0.5)
|
||||
radius = st.slider("Radius (km)", 0.5, 10.0, 0.75, step=0.5)
|
||||
circular = st.checkbox("Circular map", value=False)
|
||||
|
||||
# Preset selector
|
||||
preset_options = list(presets["preset"].values())
|
||||
selected_preset = st.selectbox(
|
||||
"Select a Preset", preset_options, index=preset_options.index("default")
|
||||
)
|
||||
|
||||
# Add input for number of colors
|
||||
num_colors = st.number_input("Number of colors", min_value=1, value=2, step=1)
|
||||
style = prettymaps.preset(selected_preset).params["style"]
|
||||
palette = (
|
||||
style["building"]["palette"]
|
||||
if "building" in style and "palette" in style["building"]
|
||||
else ["#433633", "#FF5E5B"]
|
||||
)
|
||||
num_colors = st.number_input(
|
||||
"Number of colors", min_value=1, value=len(palette), step=1
|
||||
)
|
||||
|
||||
custom_palette = {}
|
||||
color_cols = st.columns(4)
|
||||
palette = ["#433633", "#FF5E5B"]
|
||||
for i in range((num_colors + 3) // 4): # Calculate the number of rows needed
|
||||
color_cols = st.columns(len(palette))
|
||||
for i in range(len(palette) // 1): # Calculate the number of rows needed
|
||||
for j, col in enumerate(color_cols):
|
||||
idx = i * 4 + j
|
||||
if idx < num_colors:
|
||||
@@ -38,15 +62,13 @@ with cols[0]:
|
||||
custom_palette[idx] = color
|
||||
|
||||
# Add page size options
|
||||
page_size = st.selectbox(
|
||||
"Page Size", ["A4", "A5", "A3", "A2", "A1", "Custom"], index=0
|
||||
)
|
||||
|
||||
# Preset selector
|
||||
preset_options = list(presets["preset"].values())
|
||||
selected_preset = st.selectbox(
|
||||
"Select a Preset", preset_options, index=preset_options.index("default")
|
||||
)
|
||||
page_size_col, dpi_col = st.columns(2)
|
||||
with page_size_col:
|
||||
page_size = st.selectbox(
|
||||
"Page Size", ["A4", "A5", "A3", "A2", "A1", "Custom"], index=0
|
||||
)
|
||||
with dpi_col:
|
||||
dpi = st.number_input("DPI", min_value=72, max_value=600, value=300, step=50)
|
||||
|
||||
if page_size == "Custom":
|
||||
width = st.number_input("Custom Width (inches)", min_value=1.0, value=8.27)
|
||||
@@ -65,22 +87,22 @@ with cols[0]:
|
||||
st.subheader("Select Layers")
|
||||
|
||||
layers = {
|
||||
"hillshade": st.checkbox("Hillshade", value=False),
|
||||
"buildings": st.checkbox("Buildings", value=True),
|
||||
"streets": st.checkbox("Streets", value=True),
|
||||
"waterway": st.checkbox("Waterway", value=True),
|
||||
"building": st.checkbox("Building", value=True),
|
||||
"water": st.checkbox("Water", value=True),
|
||||
"sea": st.checkbox("Sea", value=True),
|
||||
"forest": st.checkbox("Forest", value=True),
|
||||
"green": st.checkbox("Green", value=True),
|
||||
"rock": st.checkbox("Rock", value=True),
|
||||
"beach": st.checkbox("Beach", value=True),
|
||||
"parking": st.checkbox("Parking", value=True),
|
||||
# "hillshade": st.checkbox("Hillshade", value="hillshade" in style),
|
||||
"buildings": st.checkbox("Buildings", value="buildings" in style),
|
||||
"streets": st.checkbox("Streets", value="streets" in style),
|
||||
"waterway": st.checkbox("Waterway", value="waterway" in style),
|
||||
"building": st.checkbox("Building", value="building" in style),
|
||||
"water": st.checkbox("Water", value="water" in style),
|
||||
"sea": st.checkbox("Sea", value="sea" in style),
|
||||
"forest": st.checkbox("Forest", value="forest" in style),
|
||||
"green": st.checkbox("Green", value="green" in style),
|
||||
"rock": st.checkbox("Rock", value="rock" in style),
|
||||
"beach": st.checkbox("Beach", value="beach" in style),
|
||||
"parking": st.checkbox("Parking", value="parking" in style),
|
||||
}
|
||||
|
||||
# Hillshade parameters
|
||||
if layers["hillshade"]:
|
||||
if False: # layers["hillshade"]:
|
||||
st.subheader("Hillshade Parameters")
|
||||
azdeg = st.number_input(
|
||||
"Azimuth (degrees)", min_value=0, max_value=360, value=315
|
||||
@@ -105,7 +127,8 @@ with cols[1]:
|
||||
icon=":material/map:",
|
||||
use_container_width=True,
|
||||
)
|
||||
if button:
|
||||
|
||||
if button: # or "last_image" in st.session_state:
|
||||
hillshade_params = (
|
||||
{
|
||||
"azdeg": azdeg,
|
||||
@@ -115,18 +138,49 @@ with cols[1]:
|
||||
"dy": dy,
|
||||
"alpha": alpha,
|
||||
}
|
||||
if layers["hillshade"]
|
||||
if False # layers["hillshade"]
|
||||
else {}
|
||||
)
|
||||
prettymaps.plot(
|
||||
query,
|
||||
radius=1000 * radius,
|
||||
circle=circular,
|
||||
layers={k: (False if v == False else {}) for k, v in layers.items()},
|
||||
style={"building": {"palette": list(custom_palette.values())}},
|
||||
figsize=(width, height),
|
||||
)
|
||||
st.pyplot(plt)
|
||||
with st.spinner("Generating map..."):
|
||||
fig, ax = plt.subplots(figsize=(width, height), dpi=300)
|
||||
prettymaps.plot(
|
||||
query,
|
||||
radius=1000 * radius,
|
||||
circle=circular,
|
||||
layers={k: (False if v == False else {}) for k, v in layers.items()},
|
||||
style={"building": {"palette": list(custom_palette.values())}},
|
||||
figsize=(width, height),
|
||||
preset=selected_preset,
|
||||
show=False,
|
||||
ax=ax,
|
||||
)
|
||||
buf = io.BytesIO()
|
||||
plt.savefig(buf, format="png", bbox_inches="tight", dpi=150)
|
||||
buf.seek(0)
|
||||
st.session_state.last_image = buf
|
||||
|
||||
# Save the figure to a file
|
||||
fig_path = "/tmp/generated_map.png"
|
||||
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,
|
||||
)
|
||||
|
||||
st.image(st.session_state.last_image, use_container_width=True)
|
||||
|
||||
else:
|
||||
fig_path = "https://github.com/marceloprates/prettymaps/raw/main/prints/heerhugowaard.png"
|
||||
st.image(fig_path, use_container_width=True)
|
||||
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,
|
||||
)
|
||||
|
@@ -888,14 +888,17 @@ def override_preset(
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def draw_text(params: Dict[str, dict], background: BaseGeometry) -> None:
|
||||
def draw_text(
|
||||
ax: matplotlib.axes.Axes, params: Dict[str, Any], background: BaseGeometry
|
||||
) -> None:
|
||||
"""
|
||||
Draw text with content and matplotlib style parameters specified by 'params' dictionary.
|
||||
params['text'] should contain the message to be drawn
|
||||
params['text'] should contain the message to be drawn.
|
||||
|
||||
Args:
|
||||
params (Dict[str, dict]): matplotlib style parameters for drawing text. params['text'] should contain the message to be drawn.
|
||||
background (BaseGeometry): Background layer
|
||||
ax (matplotlib.axes.Axes): Matplotlib axis object.
|
||||
params (Dict[str, Any]): Matplotlib style parameters for drawing text. params['text'] should contain the message to be drawn.
|
||||
background (BaseGeometry): Background layer.
|
||||
"""
|
||||
# Override default osm_credit dict with provided parameters
|
||||
params = override_params(
|
||||
@@ -923,19 +926,31 @@ def draw_text(params: Dict[str, dict], background: BaseGeometry) -> None:
|
||||
x = np.interp([x], [0, 1], [xmin, xmax])[0]
|
||||
y = np.interp([y], [0, 1], [ymin, ymax])[0]
|
||||
|
||||
plt.text(x, y, text, **params)
|
||||
ax.text(x, y, text, zorder=1000, **params)
|
||||
|
||||
|
||||
@log_execution_time
|
||||
def draw_credit(
|
||||
background,
|
||||
credit,
|
||||
mode,
|
||||
multiplot,
|
||||
logging=False,
|
||||
):
|
||||
ax: matplotlib.axes.Axes,
|
||||
background: BaseGeometry,
|
||||
credit: Dict[str, Any],
|
||||
mode: str,
|
||||
multiplot: bool,
|
||||
logging: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Draws credit text on the plot.
|
||||
|
||||
Args:
|
||||
ax (matplotlib.axes.Axes): Matplotlib axis object.
|
||||
background (BaseGeometry): Background layer.
|
||||
credit (Dict[str, Any]): Dictionary containing credit text and style parameters.
|
||||
mode (str): Drawing mode. Options: 'matplotlib', 'plotter'.
|
||||
multiplot (bool): Whether the plot is part of a multiplot.
|
||||
logging (bool, optional): Whether to enable logging. Defaults to False.
|
||||
"""
|
||||
if (mode == "matplotlib") and (credit != False) and (not multiplot):
|
||||
draw_text(credit, background)
|
||||
draw_text(ax, credit, background)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -1186,7 +1201,7 @@ def plot(
|
||||
draw_background(background, ax, style, mode, logging=logging)
|
||||
|
||||
# 10. Draw credit message
|
||||
draw_credit(background, credit, mode, multiplot, logging=logging)
|
||||
draw_credit(ax, background, credit, mode, multiplot, logging=logging)
|
||||
|
||||
# 11. Draw hillshade
|
||||
draw_hillshade(
|
||||
|
@@ -125,9 +125,12 @@ def obtain_elevation(gdf):
|
||||
|
||||
# Configure the bounding box for the elevation library
|
||||
|
||||
output_file = os.path.join(os.getcwd(), "elevationa.tif")
|
||||
output_file = os.path.join(os.getcwd(), "elevation.tif")
|
||||
elevation.clip(
|
||||
bounds=(min_lon, min_lat, max_lon, max_lat), output=output_file, margin="10%"
|
||||
bounds=(min_lon, min_lat, max_lon, max_lat),
|
||||
output=output_file,
|
||||
margin="10%",
|
||||
cache_dir=".",
|
||||
)
|
||||
|
||||
# subprocess.run(
|
||||
|
BIN
prints/app_placeholder.png
Normal file
BIN
prints/app_placeholder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 985 KiB |
0
script/bootstrap
Executable file → Normal file
0
script/bootstrap
Executable file → Normal file
2
setup.py
2
setup.py
@@ -7,7 +7,7 @@ presets_dir = os.path.abspath(os.path.join(os.path.pardir, "presets"))
|
||||
|
||||
setup(
|
||||
name="prettymaps",
|
||||
version="v1.4",
|
||||
version="v1.4.2",
|
||||
description="A simple python library to draw pretty maps from OpenStreetMap data",
|
||||
long_description=parent_dir.joinpath("README.md").read_text(),
|
||||
long_description_content_type="text/markdown",
|
||||
|
17
setup.sh
17
setup.sh
@@ -1 +1,18 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Change permissions for STRM folder
|
||||
chmod -R 755 ./SRTM1
|
||||
|
||||
# Update package list
|
||||
apt-get update
|
||||
|
||||
# Install essential build tools including make and gcc
|
||||
apt-get install -y build-essential make gcc
|
||||
|
||||
# Optionally install other dependencies (e.g., for elevation or other libraries)
|
||||
apt-get install -y python3-dev libgdal-dev
|
||||
|
||||
# Clean up to reduce the image size
|
||||
apt-get clean
|
||||
|
||||
pip install git+https://github.com/marceloprates/prettymaps.git
|
Reference in New Issue
Block a user