37 Commits

Author SHA1 Message Date
marceloprates
f895570923 requirements.txt: Updated osmnx version to 1.2.2 2023-02-10 11:03:52 -03:00
marceloprates
78d050ee5b Updated version number, minor changes to draw.py and requirements.txt 2023-02-10 10:48:11 -03:00
marceloprates
3f3b8be923 Fixed problem with prettymaps.plot() 'save_as' parameter 2022-11-16 10:41:53 -03:00
marceloprates
f03d71f7da Added an extra cell to the examples notebook with instructions on how to run it on Google Colab 2022-11-08 16:54:11 -03:00
marceloprates
de41a2fd48 Updated examples notebook not to load fonts from external .ttf files anymore (enabling it to run smoothly on Google Colab) 2022-11-08 15:09:27 -03:00
marceloprates
e11b7e6289 Fixed presets directory path-related error with preset() function 2022-11-08 13:59:28 -03:00
marceloprates
c70f32a8e6 Merge branch 'main' of github.com:marceloprates/prettymaps 2022-11-08 13:27:34 -03:00
marceloprates
cca6564b22 Fixed presets directory path-related error with presets() function 2022-11-08 13:27:26 -03:00
Marcelo de Oliveira Rosa Prates
1389564c0c Update README.md 2022-11-08 12:59:17 -03:00
Marcelo de Oliveira Rosa Prates
066309e4b1 Update README.md 2022-11-08 12:57:53 -03:00
Marcelo de Oliveira Rosa Prates
0dbf445bf7 Update README.md 2022-11-08 12:56:04 -03:00
Marcelo de Oliveira Rosa Prates
fa56dc51e9 Update README.md 2022-11-08 12:55:31 -03:00
marceloprates
0c46fbb261 Minor textual correction to examples notebook 2022-11-08 12:01:53 -03:00
marceloprates
823c43d61c Minor textual correction to examples notebook 2022-11-08 12:00:01 -03:00
Marcelo de Oliveira Rosa Prates
a513c78490 Update README.md 2022-11-08 11:59:04 -03:00
marceloprates
4e731e2999 Fixed problem with relative path of README_files folder 2022-11-08 11:41:01 -03:00
marceloprates
245ee7b0ee Forgot to update examples notebook 2022-11-08 11:28:21 -03:00
marceloprates
4f71a8ee86 Updated README with instructions for local and google colab installation 2022-11-08 11:26:33 -03:00
marceloprates
39ad98cd16 Rewrote dict union operation with old syntax (dict.update()) for compatibility purposes 2022-11-08 11:09:24 -03:00
marceloprates
9f7de23d84 Downgraded ipykernelto 5.3.4 in requirements.txt to make prettymaps compatible with Google Colab 2022-11-08 10:48:33 -03:00
marceloprates
6b1a9fe79f Fixed relative path for presets folder in draw.py 2022-11-08 10:38:23 -03:00
marceloprates
03025d8232 Replaced setup.py 'data_files' with 'package_data' 2022-11-08 10:28:06 -03:00
marceloprates
18461d9d37 Fixed setup.py 'data_files' paths 2022-11-08 10:22:12 -03:00
marceloprates
246bd4a23b Fixed problem with presets folder location on draw.py and setup.py 2022-11-08 10:16:21 -03:00
marceloprates
d60744fbe7 Added presets JSON files to setup.py's 'data_files' 2022-11-08 10:00:08 -03:00
marceloprates
1bdaf93b9e merge 2022-11-08 09:38:50 -03:00
marceloprates
10d396065d Fixed missing import (pyyaml) and supressed vsketch features due to difficulties in making setup.py install vsketch automatically 2022-11-08 09:36:22 -03:00
Marcelo de Oliveira Rosa Prates
291d808fb3 Update requirements.txt 2022-11-08 09:10:24 -03:00
Marcelo de Oliveira Rosa Prates
8bf94ffbec Update README.md 2022-11-08 09:07:02 -03:00
marceloprates
3bcab3e4bb added prints/REAME_files/ folder 2022-11-08 09:06:16 -03:00
Marcelo de Oliveira Rosa Prates
cff431eae4 Merge pull request #102 from marceloprates/refactoring
Refactoring
2022-11-08 09:03:25 -03:00
Marcelo Prates
c6c8f19084 Refactored quite a bit of of the code, simplified the usage of some features, added option of saving / loading presets and updated the examples.ipynb notebook and the README with a short tutorial 2022-11-07 13:32:38 -03:00
Marcelo Prates
3d58c60221 Updated osmnx, shapely versions in requirements.txt 2022-07-12 14:22:10 -03:00
Marcelo de Oliveira Rosa Prates
72fd33ce5f Merge pull request #76 from worldpotato/add_aur
add AUR link and description to README
2022-01-07 10:32:00 -03:00
Marcelo de Oliveira Rosa Prates
a73cf493f0 Update README.md 2021-10-20 07:32:55 -03:00
Marcelo de Oliveira Rosa Prates
2765aafb9e Update README.md 2021-10-19 23:55:33 -03:00
Felix Strobel
1e526fb3bb add AUR link and description to README
There is an AUR in the repositories which makes it easy
to install and update pretty maps
2021-10-19 19:21:26 +02:00
27 changed files with 4241 additions and 5230 deletions

1092
README.md

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100.0" height="100.0" viewBox="-51.23032682800001 -30.034281028 0.0006073560000103839 0.0008053559999900983" preserveAspectRatio="xMinYMin meet"><g transform="matrix(1,0,0,-1,0,-60.067756700000004)"><path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="1.6107119999801965e-05" opacity="0.6" d="M -51.2298412,-30.03353870000001 L -51.2298154,-30.033540599999984 L -51.2298126,-30.0335408 L -51.2298129,-30.033544300000003 L -51.2297808,-30.033546699999988 L -51.2297805,-30.033544400000007 L -51.2297758,-30.0335447 L -51.2297562,-30.0335462 L -51.2297493,-30.033546700000002 L -51.2297572,-30.033626999999992 L -51.22975770000001,-30.033632 L -51.2298302,-30.03362630000001 L -51.2298538,-30.033865000000006 L -51.2298442,-30.0338658 L -51.2298477,-30.033909500000004 L -51.2298412,-30.03390990000001 L -51.2298357,-30.03390249999999 L -51.2298133,-30.033912799999996 L -51.2298168,-30.0339188 L -51.2297959,-30.0339406 L -51.2297906,-30.033938999999993 L -51.2297826,-30.0339586 L -51.2297866,-30.033959199999998 L -51.2297957,-30.034019000000004 L -51.2297902,-30.034021400000004 L -51.229800700000006,-30.0340417 L -51.2298073,-30.0340393 L -51.2298344,-30.034053999999994 L -51.2298319,-30.034065200000004 L -51.2298509,-30.0340704 L -51.2298558,-30.034059600000003 L -51.2298704,-30.0340585 L -51.2298741,-30.034097 L -51.2298921,-30.034095599999993 L -51.2298985,-30.03416019999999 L -51.2298609,-30.034163 L -51.2298683,-30.03423859999999 L -51.2299531,-30.0342322 L -51.2299549,-30.0342512 L -51.2301846,-30.034234 L -51.2301825,-30.0342134 L -51.2302643,-30.03420729999999 L -51.2302569,-30.034132200000002 L -51.2302241,-30.034134599999994 L -51.2302178,-30.0340702 L -51.2302266,-30.0340694 L -51.2302229,-30.034030399999995 L -51.2302285,-30.03403000000001 L -51.230236500000004,-30.0340294 L -51.2302396,-30.034038299999995 L -51.230256600000004,-30.034034099999996 L -51.2302532,-30.0340242 L -51.230280900000004,-30.034001600000003 L -51.2302902,-30.0340033 L -51.23029700000001,-30.033981200000003 L -51.2302871,-30.0339784 L -51.2302841,-30.033920999999996 L -51.2302898,-30.033919600000008 L -51.2302806,-30.0338995 L -51.2302726,-30.033902400000002 L -51.2302486,-30.0338856 L -51.2302511,-30.033877399999994 L -51.2302264,-30.033868700000003 L -51.2302198,-30.033880699999997 L -51.2302148,-30.033878999999995 L -51.230213000000006,-30.033838099999997 L -51.2302054,-30.033838700000004 L -51.2301818,-30.0336 L -51.2302499,-30.033594899999997 L -51.2302471,-30.033566499999996 L -51.2302452,-30.033566699999998 L -51.2302423,-30.0335373 L -51.2302448,-30.033537100000004 L -51.2302419,-30.0335085 L -51.2302051,-30.0335112 L -51.2302053,-30.033513599999992 L -51.2301756,-30.0335159 L -51.2301752,-30.033512399999992 L -51.23014450000001,-30.033514699999994 L -51.2301449,-30.033518200000003 L -51.2300854,-30.033522700000002 L -51.2300843,-30.033511399999984 L -51.2300823,-30.0335115 L -51.2300635,-30.033512799999997 L -51.2300628,-30.033505500000008 L -51.2300334,-30.0335078 L -51.2300336,-30.03350989999999 L -51.2300339,-30.033513 L -51.22995280000001,-30.033519099999996 L -51.229952600000004,-30.033516999999996 L -51.2299524,-30.0335151 L -51.2299225,-30.03351729999999 L -51.2299228,-30.033520499999998 L -51.2298995,-30.03352229999999 L -51.2299009,-30.033537 L -51.2298443,-30.033541300000003 L -51.229844,-30.0335385 L -51.2298412,-30.03353870000001 z" /></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
README_files/README_6_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 KiB

BIN
README_files/README_8_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 KiB

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
from .draw import plot
from .draw import plot, multiplot, Subplot, create_preset, delete_preset, preset, presets

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
'''
"""
Prettymaps - A minimal Python library to draw pretty maps from OpenStreetMap Data
Copyright (C) 2021 Marcelo Prates
@@ -14,373 +14,218 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
"""
from ast import Dict
from functools import reduce
from tokenize import Number, String
from typing import Optional, Union, Tuple
# from unittest.runner import _ResultClassType
from xmlrpc.client import Boolean
import re
import osmnx as ox
from osmnx import utils_geo
from osmnx._errors import EmptyOverpassResponse
import numpy as np
from shapely.geometry import Point, Polygon, MultiPolygon, LineString, MultiLineString
from shapely.geometry import (
box,
Point,
Polygon,
MultiPolygon,
LineString,
MultiLineString,
)
from shapely.affinity import rotate
from shapely.ops import unary_union
from geopandas import GeoDataFrame, read_file
import warnings
from shapely.errors import ShapelyDeprecationWarning
from copy import deepcopy
def get_boundary(
point: Tuple, radius: float, crs: String, circle: Boolean = True, dilate: float = 0
) -> Polygon:
"""
Compute circular or square boundary given point, radius and crs.
Args:
point (Tuple): GPS coordinates
radius (Number): radius in meters
crs (String): Coordinate Reference System
circle (bool, optional): Whether to use a circular (True) or square (False) boundary. Defaults to True.
dilate (int, optional): Dilate the boundary by this much, in meters. Defaults to 0.
Returns:
Polygon: a shapely Polygon representing the boundary
"""
if circle:
return (
ox.project_gdf(GeoDataFrame(geometry=[Point(point[::-1])], crs=crs))
.geometry[0]
.buffer(radius)
)
# Parse query (by coordinates, OSMId or name)
def parse_query(query):
if isinstance(query, GeoDataFrame):
return "polygon"
elif isinstance(query, tuple):
return "coordinates"
elif re.match("""[A-Z][0-9]+""", query):
return "osmid"
else:
x, y = np.stack(
ox.project_gdf(GeoDataFrame(geometry=[Point(point[::-1])], crs=crs))
.geometry[0]
.xy
)
r = radius
return Polygon(
[(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)]
).buffer(dilate)
return "address"
def get_perimeter(query, by_osmid: Boolean = False, **kwargs) -> GeoDataFrame:
"""
Fetch perimeter given query
# Get circular or square boundary around point
def get_boundary(query, radius, circle=False, rotation=0):
Args:
query (String): Query for the perimeter to be fetched (for example, "France")
by_osmid (bool, optional): Whether to fetch perimeter by OSM Id. Defaults to False.
Returns:
GeoDataFrame: GeoDataFrame representation of the perimeter
"""
return ox.geocode_to_gdf(
query,
by_osmid=by_osmid,
**kwargs,
**{x: kwargs[x] for x in ["circle", "dilate"] if x in kwargs.keys()}
# Get point from query
point = query if parse_query(query) == "coordinates" else ox.geocode(query)
# Create GeoDataFrame from point
boundary = ox.project_gdf(
GeoDataFrame(geometry=[Point(point[::-1])], crs="EPSG:4326")
)
if circle: # Circular shape
# use .buffer() to expand point into circle
boundary.geometry = boundary.geometry.buffer(radius)
else: # Square shape
x, y = np.concatenate(boundary.geometry[0].xy)
r = radius
boundary = GeoDataFrame(
geometry=[
rotate(
Polygon(
[(x - r, y - r), (x + r, y - r),
(x + r, y + r), (x - r, y + r)]
),
rotation,
)
],
crs=boundary.crs,
)
def get_coast(
perimeter=None,
point=None,
radius=None,
perimeter_tolerance=0,
union=True,
buffer=0,
circle=True,
dilate=0,
file_location=None,
# Unproject
boundary = boundary.to_crs(4326)
return boundary
# Get perimeter from query
def get_perimeter(
query, radius=None, by_osmid=False, circle=False, dilate=None, rotation=0, **kwargs
):
if perimeter is not None:
# Boundary defined by polygon (perimeter)
bbox = perimeter.to_crs(3174)
bbox = bbox.buffer(perimeter_tolerance + dilate + buffer)
bbox = bbox.to_crs(4326)
bbox = bbox.envelope
# Load the polygons for the coastline from a file
geometries = read_file(file_location, bbox=bbox)
perimeter = unary_union(ox.project_gdf(perimeter).geometry)
elif (point is not None) and (radius is not None):
# Boundary defined by circle with radius 'radius' around point
north, south, west, east = utils_geo.bbox_from_point(
point, dist=radius + dilate + buffer
)
bbox = (west, south, east, north)
# Load the polygons for the coastline from a file
geometries = read_file(file_location, bbox=bbox)
if radius:
# Perimeter is a circular or square shape
perimeter = get_boundary(
point, radius, geometries.crs, circle=circle, dilate=dilate
)
# Project GDF
if len(geometries) > 0:
geometries = ox.project_gdf(geometries)
# Intersect with perimeter
geometries = geometries.intersection(perimeter)
if union:
geometries = unary_union(
reduce(
lambda x, y: x + y,
[
[x] if type(x) == Polygon else list(x)
for x in geometries
if type(x) in [Polygon, MultiPolygon]
],
[],
)
)
query, radius, circle=circle, rotation=rotation)
else:
geometries = MultiPolygon(
reduce(
lambda x, y: x + y,
[
[x] if type(x) == Polygon else list(x)
for x in geometries
if type(x) in [Polygon, MultiPolygon]
],
[],
)
)
return geometries
def get_geometries(
perimeter: Optional[GeoDataFrame] = None,
point: Optional[Tuple] = None,
radius: Optional[float] = None,
tags: Dict = {},
perimeter_tolerance: float = 0,
union: Boolean = True,
buffer: float = 0,
circle: Boolean = True,
dilate: float = 0,
point_size: float = 1,
line_width: float = 1
) -> Union[Polygon, MultiPolygon]:
"""Get geometries
Args:
perimeter (Optional[GeoDataFrame], optional): Perimeter from within geometries will be fetched. Defaults to None.
point (Optional[Tuple], optional): GPS coordinates. Defaults to None.
radius (Optional[Number], optional): Radius in meters. Defaults to None.
tags (Dict, optional): OpenStreetMap tags for the geometries to be fetched. Defaults to {}.
perimeter_tolerance (Number, optional): Tolerance in meters for fetching geometries that fall outside the perimeter. Defaults to 0.
union (Boolean, optional): Whether to compute the union of all geometries. Defaults to True.
circle (Boolean, optional): Whether to fetch geometries in a circular (True) or square (False) shape. Defaults to True.
dilate (Number, optional): Dilate the boundary by this much in meters. Defaults to 0.
Returns:
[type]: [description]
"""
# Boundary defined by polygon (perimeter)
if perimeter is not None:
geometries = ox.geometries_from_polygon(
unary_union(perimeter.to_crs(3174).buffer(buffer+perimeter_tolerance).to_crs(4326).geometry)
if buffer >0 or perimeter_tolerance > 0
else unary_union(perimeter.geometry),
tags={tags: True} if type(tags) == str else tags,
)
perimeter = unary_union(ox.project_gdf(perimeter).geometry)
# Boundary defined by circle with radius 'radius' around point
elif (point is not None) and (radius is not None):
geometries = ox.geometries_from_point(
point,
dist=radius + dilate + buffer,
tags={tags: True} if type(tags) == str else tags,
)
perimeter = get_boundary(
point, radius, geometries.crs, circle=circle, dilate=dilate
)
# Project GDF
if len(geometries) > 0:
geometries = ox.project_gdf(geometries)
# Intersect with perimeter
geometries = geometries.intersection(perimeter)
# Get points, lines, polys & multipolys
points, lines, polys, multipolys = map(
lambda t: [x for x in geometries if isinstance(x, t)],
[Point, LineString, Polygon, MultiPolygon]
)
# Convert points, lines & polygons into multipolygons
points = [x.buffer(point_size) for x in points]
lines = [x.buffer(line_width) for x in lines]
# Concatenate multipolys
multipolys = reduce(lambda x,y: x+y, [list(x) for x in multipolys]) if len(multipolys) > 0 else []
# Group everything
geometries = MultiPolygon(points + lines + polys + multipolys)
# Compute union if specified
if union: geometries = unary_union(geometries);
return geometries
def get_streets(
perimeter: Optional[GeoDataFrame] = None,
point: Optional[Tuple] = None,
radius: Optional[float] = None,
layer: String = "streets",
width: float = 6,
custom_filter: Optional[str] = None,
buffer: float = 0,
retain_all: Boolean = False,
circle: Boolean = True,
dilate: float = 0,
truncate_by_edge: Boolean = True
) -> MultiPolygon:
"""
Get streets
Args:
perimeter (Optional[GeoDataFrame], optional): [description]. Defaults to None.
point (Optional[Tuple], optional): [description]. Defaults to None.
radius (Optional[Number], optional): [description]. Defaults to None.
layer (String, optional): [description]. Defaults to "streets".
width (Number, optional): [description]. Defaults to 6.
custom_filter (Optional[String], optional): [description]. Defaults to None.
buffer (Number, optional): [description]. Defaults to 0.
retain_all (Boolean, optional): [description]. Defaults to False.
circle (Boolean, optional): [description]. Defaults to True.
dilate (Number, optional): [description]. Defaults to 0.
truncate_by_edge (Boolean, optional): [description]. Defaults to True.
Returns:
MultiPolygon: [description]
"""
if layer == "streets":
layer = "highway"
# Boundary defined by polygon (perimeter)
if perimeter is not None:
# Fetch streets data, project & convert to GDF
try:
streets = ox.graph_from_polygon(
unary_union(perimeter.geometry).buffer(buffer)
if buffer > 0
else unary_union(perimeter.geometry),
custom_filter=custom_filter,
)
streets = ox.project_graph(streets)
streets = ox.graph_to_gdfs(streets, nodes=False)
except EmptyOverpassResponse:
return MultiLineString()
# Boundary defined by polygon (perimeter)
elif (point is not None) and (radius is not None):
# Fetch streets data, save CRS & project
try:
streets = ox.graph_from_point(
point,
dist=radius + dilate + buffer,
retain_all=retain_all,
custom_filter=custom_filter,
truncate_by_edge = truncate_by_edge,
)
crs = ox.graph_to_gdfs(streets, nodes=False).crs
streets = ox.project_graph(streets)
# Compute perimeter from point & CRS
perimeter = get_boundary(point, radius, crs, circle=circle, dilate=dilate)
# Convert to GDF
streets = ox.graph_to_gdfs(streets, nodes=False)
# Intersect with perimeter & filter empty elements
streets.geometry = streets.geometry.intersection(perimeter)
streets = streets[~streets.geometry.is_empty]
except EmptyOverpassResponse:
return MultiLineString()
if type(width) == dict:
streets = unary_union(
[
# Dilate streets of each highway type == 'highway' using width 'w'
MultiLineString(
streets[
[highway in value for value in streets[layer]]
& (streets.geometry.type == "LineString")
].geometry.tolist()
+ list(
reduce(
lambda x, y: x + y,
[
list(lines)
for lines in streets[
[highway in value for value in streets[layer]]
& (streets.geometry.type == "MultiLineString")
].geometry
],
[],
)
)
).buffer(w)
for highway, w in width.items()
]
)
else:
# Dilate all streets by same amount 'width'
streets= MultiLineString(
streets[streets.geometry.type == "LineString"].geometry.tolist()
+ list(
reduce(
lambda x, y: x + y,
[
list(lines)
for lines in streets[streets.geometry.type == "MultiLineString"].geometry
],
[],
)
)
).buffer(width)
return streets
def get_layer(layer: String, **kwargs) -> Union[Polygon, MultiPolygon]:
"""[summary]
Args:
layer (String): [description]
Raises:
Exception: [description]
Returns:
Union[Polygon, MultiPolygon]: [description]
"""
# Fetch perimeter
if layer == "perimeter":
# If perimeter is already provided:
if "perimeter" in kwargs:
return unary_union(ox.project_gdf(kwargs["perimeter"]).geometry)
# If point and radius are provided:
elif "point" in kwargs and "radius" in kwargs:
crs = "EPSG:4326"
perimeter = get_boundary(
kwargs["point"],
kwargs["radius"],
crs,
**{x: kwargs[x] for x in ["circle", "dilate"] if x in kwargs.keys()}
)
return perimeter
# Perimeter is a OSM or user-provided polygon
if parse_query(query) == "polygon":
# Perimeter was already provided
perimeter = query
else:
raise Exception("Either 'perimeter' or 'point' & 'radius' must be provided")
# Fetch streets or railway
if layer in ["streets", "railway", "waterway"]:
return get_streets(**kwargs, layer=layer)
# Fetch Coastline
# Fetch perimeter from OSM
perimeter = ox.geocode_to_gdf(
query,
by_osmid=by_osmid,
**kwargs,
)
# Apply dilation
perimeter = ox.project_gdf(perimeter)
if dilate is not None:
perimeter.geometry = perimeter.geometry.buffer(dilate)
perimeter = perimeter.to_crs(4326)
return perimeter
# Get a GeoDataFrame
def get_gdf(
layer,
perimeter,
perimeter_tolerance=0,
tags=None,
osmid=None,
custom_filter=None,
union=False,
elevation=None,
vert_exag=1,
azdeg=90,
altdeg=80,
pad=1,
min_height=30,
max_height=None,
n_curves=100,
**kwargs
):
# Supress shapely deprecation warning
warnings.simplefilter("ignore", ShapelyDeprecationWarning)
# Apply tolerance to the perimeter
perimeter_with_tolerance = (
ox.project_gdf(perimeter).buffer(perimeter_tolerance).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
bbox = box(*perimeter_with_tolerance.bounds)
if layer == "hillshade":
gdf = get_hillshade(
mask_elevation(get_elevation(elevation), perimeter),
pad=pad,
azdeg=azdeg,
altdeg=altdeg,
vert_exag=vert_exag,
min_height=min_height,
max_height=max_height,
)
elif layer == "level_curves":
gdf = get_level_curves(
mask_elevation(get_elevation(elevation), perimeter),
pad=pad,
n_curves=n_curves,
min_height=min_height,
max_height=max_height,
)
elif layer in ["streets", "railway", "waterway"]:
graph = ox.graph_from_polygon(
bbox,
custom_filter=custom_filter,
truncate_by_edge=True,
)
gdf = ox.graph_to_gdfs(graph, nodes=False)
elif layer == "coastline":
return get_coast(**kwargs)
# Fetch geometries
# Fetch geometries from OSM
gdf = ox.geometries_from_polygon(
bbox, tags={tags: True} if type(tags) == str else tags
)
else:
return get_geometries(**kwargs)
if osmid is None:
# Fetch geometries from OSM
gdf = ox.geometries_from_polygon(
bbox, tags={tags: True} if type(tags) == str else tags
)
else:
gdf = ox.geocode_to_gdf(osmid, by_osmid=True)
# Intersect with perimeter
gdf.geometry = gdf.geometry.intersection(perimeter_with_tolerance)
# gdf = gdf[~gdf.geometry.is_empty]
gdf.drop(gdf[gdf.geometry.is_empty].index, inplace=True)
return gdf
# Fetch GeoDataFrames given query and a dictionary of layers
def get_gdfs(query, layers_dict, radius, dilate, rotation=0) -> dict:
perimeter_kwargs = {}
if "perimeter" in layers_dict:
perimeter_kwargs = deepcopy(layers_dict["perimeter"])
perimeter_kwargs.pop("dilate")
# Get perimeter
perimeter = get_perimeter(
query,
radius=radius,
rotation=rotation,
dilate=dilate,
**perimeter_kwargs
)
# Get other layers as GeoDataFrames
gdfs = {"perimeter": perimeter}
gdfs.update({
layer: get_gdf(layer, perimeter, **kwargs)
for layer, kwargs in layers_dict.items()
if layer != "perimeter"
})
return gdfs

View File

@@ -0,0 +1,43 @@
{
"layers": {
"streets": {
"width": {
"primary": 5,
"secondary": 4,
"tertiary": 3,
"residential": 2,
"footway": 1
}
},
"building": {
"tags": {
"building": true
}
},
"green": {
"tags": {
"landuse": [
"grass",
"village_green"
],
"leisure": "park"
}
}
},
"style": {
"perimeter": {
"draw": false
},
"streets": {
"stroke": 1,
"fill": 1,
"penWidth": 2
},
"buildings": {
"stroke": 2
}
},
"circle": null,
"radius": 500,
"dilate": 100
}

View File

@@ -0,0 +1 @@
{"layers": {"perimeter": {"circle": false}, "streets": {"width": {"primary": 5, "secondary": 4, "tertiary": 3, "residential": 2, "footway": 1}}, "building": {"tags": {"building": true}}, "green": {"tags": {"landuse": ["grass", "village_green"], "leisure": "park"}}}, "style": {"background": {"fc": "#F2F4CB", "ec": "#dadbc1", "hatch": "ooo...", "zorder": -1}, "perimeter": {"fill": false, "lw": 0, "zorder": 0}, "green": {"fc": "#8BB174", "ec": "#2F3737", "hatch_c": "#A7C497", "hatch": "ooo...", "lw": 1, "zorder": 1}, "water": {"fc": "#a8e1e6", "ec": "#2F3737", "hatch_c": "#9bc3d4", "hatch": "ooo...", "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}}, "circle": null, "radius": 500, "dilate": 100}

View File

@@ -0,0 +1,96 @@
{
"layers": {
"streets": {
"width": {
"trunk": 6,
"primary": 6,
"secondary": 5,
"tertiary": 4,
"residential": 3.5,
"pedestrian": 3,
"footway": 3,
"path": 3
}
},
"building": {
"tags": {
"building": true,
"leisure": [
"track",
"pitch"
]
}
},
"water": {
"tags": {
"natural": [
"water",
"bay"
]
}
},
"park": {
"tags": {
"leisure": "park"
}
},
"forest": {
"tags": {
"landuse": "forest"
}
},
"garden": {
"tags": {
"leisure": "garden"
}
}
},
"style": {
"perimeter": {
"fill": false,
"lw": 0,
"zorder": 0
},
"park": {
"fc": "#AABD8C",
"ec": "#87996b",
"lw": 1,
"zorder": 1
},
"forest": {
"fc": "#78A58D",
"ec": "#658a76",
"lw": 1,
"zorder": 1
},
"garden": {
"fc": "#a9d1a9",
"ec": "#8ab58a",
"lw": 1,
"zorder": 1
},
"water": {
"fc": "#92D5F2",
"ec": "#6da8c2",
"lw": 1,
"zorder": 2
},
"streets": {
"fc": "#F1E6D0",
"ec": "#2F3737",
"lw": 1.5,
"zorder": 3
},
"building": {
"palette": [
"#fff"
],
"ec": "#2F3737",
"lw": 1,
"zorder": 4
}
},
"circle": null,
"radius": null,
"dilate": 0
}

View File

@@ -0,0 +1,129 @@
{
"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
}
},
"building": {
"tags": {
"building": true,
"landuse": "construction"
}
},
"water": {
"tags": {
"natural": [
"water",
"bay"
]
}
},
"forest": {
"tags": {
"landuse": "forest"
}
},
"green": {
"tags": {
"landuse": [
"grass",
"orchard"
],
"natural": [
"island",
"wood"
],
"leisure": "park"
}
},
"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": 3
},
"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
}
},
"circle": null,
"radius": 500
}

View File

@@ -0,0 +1,130 @@
{
"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
}
},
"building": {
"tags": {
"building": true,
"landuse": "construction"
}
},
"water": {
"tags": {
"natural": [
"water",
"bay"
]
}
},
"forest": {
"tags": {
"landuse": "forest"
}
},
"green": {
"tags": {
"landuse": [
"grass",
"orchard"
],
"natural": [
"island",
"wood"
],
"leisure": "park"
}
},
"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": 3
},
"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
}
},
"circle": null,
"radius": 800,
"dilate": 100
}

View File

@@ -0,0 +1,118 @@
{
"layers": {
"perimeter": {},
"streets": {
"custom_filter": "[\"highway\"~\"motorway|trunk|primary|secondary|tertiary|residential|service|unclassified|pedestrian|footway\"]",
"width": {
"motorway": 5,
"trunk": 5,
"primary": 4.5,
"secondary": 4,
"tertiary": 3.5,
"residential": 3,
"service": 2,
"unclassified": 2,
"pedestrian": 2,
"footway": 1
}
},
"building": {
"tags": {
"building": true,
"landuse": "construction"
},
"union": false
},
"water": {
"tags": {
"natural": [
"water",
"bay"
]
}
},
"green": {
"tags": {
"landuse": "grass",
"natural": [
"island",
"wood"
],
"leisure": "park"
}
},
"forest": {
"tags": {
"landuse": "forest"
}
},
"parking": {
"tags": {
"amenity": "parking",
"highway": "pedestrian",
"man_made": "pier"
}
}
},
"style": {
"background": {
"fc": "#F2F4CB",
"ec": "#dadbc1",
"hatch": "ooo...",
"zorder": -1
},
"perimeter": {
"fc": "#F2F4CB",
"ec": "#dadbc1",
"lw": 0,
"hatch": "ooo...",
"zorder": 0
},
"green": {
"fc": "#D0F1BF",
"ec": "#2F3737",
"lw": 1,
"zorder": 1
},
"forest": {
"fc": "#64B96A",
"ec": "#2F3737",
"lw": 1,
"zorder": 1
},
"water": {
"fc": "#a1e3ff",
"ec": "#2F3737",
"hatch": "ooo...",
"hatch_c": "#85c9e6",
"lw": 1,
"zorder": 2
},
"parking": {
"fc": "#F2F4CB",
"ec": "#2F3737",
"lw": 1,
"zorder": 3
},
"streets": {
"fc": "#2F3737",
"ec": "#475657",
"alpha": 1,
"lw": 0,
"zorder": 3
},
"building": {
"palette": [
"#FFC857",
"#E9724C",
"#C5283D"
],
"ec": "#2F3737",
"lw": 0.5,
"zorder": 4
}
},
"circle": true,
"radius": 1100,
"dilate": 0
}

View File

@@ -0,0 +1,44 @@
{
"layers": {
"perimeter": {},
"streets": {
"width": {
"motorway": 5,
"trunk": 5,
"primary": 4,
"secondary": 3,
"tertiary": 2,
"residential": 2
}
},
"building": {
"tags": {
"building": true
}
}
},
"style": {
"perimeter": {
"fill": false,
"lw": 0,
"zorder": 0
},
"background": {
"fc": "#fff",
"zorder": -1
},
"streets": {
"fc": "#000",
"lw": 0,
"zorder": 4
},
"building": {
"fc": "#fff",
"ec": "#000",
"lw": 0.5,
"zorder": 5
}
},
"circle": null,
"radius": 400
}

View File

@@ -0,0 +1 @@
{"layers": {"perimeter": {}, "streets": {"width": {"motorway": 12, "trunk": 12, "primary": 11, "secondary": 10, "tertiary": 9, "residential": 8}}, "park": {"tags": {"leisure": "nature_reserve", "landuse": "military", "boundary": "protected_area", "place": "square", "natural": "grassland", "amenity": "hospital"}}, "grass": {"tags": {"landuse": "grass", "natural": "wood"}}, "wetland": {"tags": {"natural": "scrub"}}, "beach": {"tags": {"natural": "beach"}}, "water": {"tags": {"natural": "water"}}, "pedestrian": {"tags": {"area:highway": "pedestrian"}}, "building": {"tags": {"building": true}}}, "style": {"perimeter": {"ec": "#0F110C", "fill": false, "lw": 0}, "park": {"fc": "#AAD897", "ec": "#8bc49e", "lw": 0, "zorder": 1, "hatch": "ooo..."}, "grass": {"fc": "#72C07A", "ec": "#64a38d", "lw": 0, "zorder": 1, "hatch": "ooo..."}, "wetland": {"fc": "#D2D68D", "ec": "#AEB441", "lw": 0, "zorder": 3, "hatch": "ooo..."}, "water": {"fc": "#6CCFF6", "ec": "#59adcf", "lw": 0, "zorder": 2, "hatch": "ooo..."}, "beach": {"fc": "#F2E3BC", "ec": "#EBD499", "lw": 0, "zorder": 2, "hatch": "ooo..."}, "pedestrian": {"fc": "#7BC950", "ec": "#638475", "lw": 0, "zorder": 2, "hatch": "ooo..."}, "streets": {"fc": "#898989", "ec": "#706f6f", "zorder": 3, "lw": 0, "hatch": "ooo..."}, "building": {"fc": "#E7A89C", "ec": "#E7A89C", "lw": 0, "zorder": 0}}, "circle": null, "radius": null, "dilate": 0}

View File

@@ -1,3 +1,6 @@
osmnx==1.0.1
osmnx==1.2.2
tabulate==0.8.9
#vsketch==1.0.0
Shapely>=1.8,<2.0
descartes==1.1.0
ipykernel==5.3.4
pyyaml==6.0.0

View File

@@ -1,11 +1,13 @@
from setuptools import setup, find_packages
import os
from pathlib import Path
from setuptools import setup, find_packages
parent_dir = Path(__file__).resolve().parent
presets_dir = os.path.abspath(os.path.join(os.path.pardir, 'presets'))
setup(
name="prettymaps",
version="v0.1.3",
version="v0.1.4",
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",
@@ -13,9 +15,13 @@ setup(
author="Marcelo Prates",
author_email="marceloorp@gmail.com",
license="MIT License",
packages=find_packages(exclude=("assets", "notebooks", "prints", "script")),
install_requires=parent_dir.joinpath("requirements.txt").read_text().splitlines(),
packages=find_packages(
exclude=("assets", "notebooks", "prints", "script")),
install_requires=parent_dir.joinpath(
"requirements.txt").read_text().splitlines(),
classifiers=[
"Intended Audience :: Science/Research",
],
package_dir={'prettymaps': '.'},
package_data={'prettymaps': ['presets/*.json']},
)