49 Commits
v0.1.3 ... v0.2

Author SHA1 Message Date
marceloprates
f017bea2da Updated version number (v0.2-beta.3 -> v0.2) in setup.py, updated examples notebook 2023-02-15 16:53:26 -03:00
marceloprates
2eeec0c610 Updated version number (v0.2-beta.2 -> v0.2-beta.3) in setup.py, removed unnecessary dependencies, updated README.md 2023-02-15 16:48:08 -03:00
marceloprates
0b45685010 Merge branch 'main' of github.com:marceloprates/prettymaps into main 2023-02-13 17:26:45 -03:00
marceloprates
af94eed6bd Changed version number (v0.2-beta -> v0.2-beta.2) in setup.py 2023-02-13 17:26:29 -03:00
marceloprates
a40c64e25d Changed package_dir location in setup.py 2023-02-13 17:21:33 -03:00
marceloprates
54339657fb Changed version number (v0.1.9 -> v0.2-beta) 2023-02-13 16:41:29 -03:00
marceloprates
dd2fd80544 Added tabulate and descartes dependencies to requirements.txt 2023-02-13 16:33:48 -03:00
marceloprates
e3a176a0b1 Removed ipykernel dependency from requirements.txt due to dependency conflicts 2023-02-13 15:57:13 -03:00
marceloprates
c0eb528301 Changed version number (v0.1.7 -> v0.1.8), added shapely, ipykernel and pyyaml dependencies to requirements.txt, removed unused imports from draw.py and fetch.py 2023-02-13 14:39:10 -03:00
marceloprates
d024b83954 Changed version number v0.1.6 -> v.0.1.7 and downgraded osmnx to v1.1.2 in an effort to solve a dependency conflict 2023-02-13 13:43:30 -03:00
marceloprates
8679cccf9e Updated version number v0.1.5 -> v0.1.6 and removed unnecessary dependencies from requirements.txt 2023-02-13 13:32:35 -03:00
marceloprates
cdebb322ec Updated version number 2023-02-13 13:22:39 -03:00
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 4238 additions and 5254 deletions

1107
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,208 @@ 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 xmlrpc.client import Boolean
import osmnx as ox
from osmnx import utils_geo
from osmnx._errors import EmptyOverpassResponse
import re
import warnings
import numpy as np
from shapely.geometry import Point, Polygon, MultiPolygon, LineString, MultiLineString
import osmnx as ox
from copy import deepcopy
from shapely.geometry import (
box,
Point,
Polygon,
MultiPolygon,
LineString,
MultiLineString,
)
from geopandas import GeoDataFrame
from shapely.affinity import rotate
from shapely.ops import unary_union
from geopandas import GeoDataFrame, read_file
from shapely.errors import ShapelyDeprecationWarning
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,3 @@
osmnx==1.0.1
tabulate==0.8.9
#vsketch==1.0.0
osmnx==1.2.2
Shapely>=1.8,<2.0
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.2-beta.3",
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': 'prettymaps'},
package_data={'prettymaps': ['presets/*.json']},
)