Merge branch 'main' into main

pull/47/head
Marcelo de Oliveira Rosa Prates 2021-09-06 09:10:17 -03:00 zatwierdzone przez GitHub
commit 25884a2be5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 323 dodań i 200 usunięć

Wyświetl plik

@ -1 +1 @@
from .draw import plot
from .draw import plot

Wyświetl plik

@ -8,8 +8,9 @@ class CurvedText(mtext.Text):
"""
A text object that follows an arbitrary curve.
"""
def __init__(self, x, y, text, axes, **kwargs):
super(CurvedText, self).__init__(x[0],y[0],' ', **kwargs)
super(CurvedText, self).__init__(x[0], y[0], " ", **kwargs)
axes.add_artist(self)
@ -21,29 +22,28 @@ class CurvedText(mtext.Text):
##creating the text objects
self.__Characters = []
for c in text:
if c == ' ':
if c == " ":
##make this an invisible 'a':
t = mtext.Text(0,0,'a')
t = mtext.Text(0, 0, "a")
t.set_alpha(0.0)
else:
t = mtext.Text(0,0,c, **kwargs)
t = mtext.Text(0, 0, c, **kwargs)
#resetting unnecessary arguments
t.set_ha('center')
# resetting unnecessary arguments
t.set_ha("center")
t.set_rotation(0)
t.set_zorder(self.__zorder +1)
t.set_zorder(self.__zorder + 1)
self.__Characters.append((c,t))
self.__Characters.append((c, t))
axes.add_artist(t)
##overloading some member functions, to assure correct functionality
##on update
def set_zorder(self, zorder):
super(CurvedText, self).set_zorder(zorder)
self.__zorder = self.get_zorder()
for c,t in self.__Characters:
t.set_zorder(self.__zorder+1)
for c, t in self.__Characters:
t.set_zorder(self.__zorder + 1)
def draw(self, renderer, *args, **kwargs):
"""
@ -53,12 +53,12 @@ class CurvedText(mtext.Text):
"""
self.update_positions(renderer)
def update_positions(self,renderer):
def update_positions(self, renderer):
"""
Update positions and rotations of the individual text elements.
"""
#preparations
# preparations
##determining the aspect ratio:
##from https://stackoverflow.com/a/42014041/2454357
@ -71,94 +71,98 @@ class CurvedText(mtext.Text):
## Ratio of display units
_, _, w, h = self.axes.get_position().bounds
##final aspect ratio
aspect = ((figW * w)/(figH * h))*(ylim[1]-ylim[0])/(xlim[1]-xlim[0])
aspect = ((figW * w) / (figH * h)) * (ylim[1] - ylim[0]) / (xlim[1] - xlim[0])
#points of the curve in figure coordinates:
x_fig,y_fig = (
np.array(l) for l in zip(*self.axes.transData.transform([
(i,j) for i,j in zip(self.__x,self.__y)
]))
# points of the curve in figure coordinates:
x_fig, y_fig = (
np.array(l)
for l in zip(
*self.axes.transData.transform(
[(i, j) for i, j in zip(self.__x, self.__y)]
)
)
)
#point distances in figure coordinates
x_fig_dist = (x_fig[1:]-x_fig[:-1])
y_fig_dist = (y_fig[1:]-y_fig[:-1])
r_fig_dist = np.sqrt(x_fig_dist**2+y_fig_dist**2)
# point distances in figure coordinates
x_fig_dist = x_fig[1:] - x_fig[:-1]
y_fig_dist = y_fig[1:] - y_fig[:-1]
r_fig_dist = np.sqrt(x_fig_dist ** 2 + y_fig_dist ** 2)
#arc length in figure coordinates
l_fig = np.insert(np.cumsum(r_fig_dist),0,0)
# arc length in figure coordinates
l_fig = np.insert(np.cumsum(r_fig_dist), 0, 0)
#angles in figure coordinates
rads = np.arctan2((y_fig[1:] - y_fig[:-1]),(x_fig[1:] - x_fig[:-1]))
# angles in figure coordinates
rads = np.arctan2((y_fig[1:] - y_fig[:-1]), (x_fig[1:] - x_fig[:-1]))
degs = np.rad2deg(rads)
rel_pos = 10
for c,t in self.__Characters:
#finding the width of c:
for c, t in self.__Characters:
# finding the width of c:
t.set_rotation(0)
t.set_va('center')
bbox1 = t.get_window_extent(renderer=renderer)
t.set_va("center")
bbox1 = t.get_window_extent(renderer=renderer)
w = bbox1.width
h = bbox1.height
#ignore all letters that don't fit:
if rel_pos+w/2 > l_fig[-1]:
# ignore all letters that don't fit:
if rel_pos + w / 2 > l_fig[-1]:
t.set_alpha(0.0)
rel_pos += w
continue
elif c != ' ':
elif c != " ":
t.set_alpha(1.0)
#finding the two data points between which the horizontal
#center point of the character will be situated
#left and right indices:
il = np.where(rel_pos+w/2 >= l_fig)[0][-1]
ir = np.where(rel_pos+w/2 <= l_fig)[0][0]
# finding the two data points between which the horizontal
# center point of the character will be situated
# left and right indices:
il = np.where(rel_pos + w / 2 >= l_fig)[0][-1]
ir = np.where(rel_pos + w / 2 <= l_fig)[0][0]
#if we exactly hit a data point:
# if we exactly hit a data point:
if ir == il:
ir += 1
#how much of the letter width was needed to find il:
used = l_fig[il]-rel_pos
# how much of the letter width was needed to find il:
used = l_fig[il] - rel_pos
rel_pos = l_fig[il]
#relative distance between il and ir where the center
#of the character will be
fraction = (w/2-used)/r_fig_dist[il]
# relative distance between il and ir where the center
# of the character will be
fraction = (w / 2 - used) / r_fig_dist[il]
##setting the character position in data coordinates:
##interpolate between the two points:
x = self.__x[il]+fraction*(self.__x[ir]-self.__x[il])
y = self.__y[il]+fraction*(self.__y[ir]-self.__y[il])
x = self.__x[il] + fraction * (self.__x[ir] - self.__x[il])
y = self.__y[il] + fraction * (self.__y[ir] - self.__y[il])
#getting the offset when setting correct vertical alignment
#in data coordinates
# getting the offset when setting correct vertical alignment
# in data coordinates
t.set_va(self.get_va())
bbox2 = t.get_window_extent(renderer=renderer)
bbox2 = t.get_window_extent(renderer=renderer)
bbox1d = self.axes.transData.inverted().transform(bbox1)
bbox2d = self.axes.transData.inverted().transform(bbox2)
dr = np.array(bbox2d[0]-bbox1d[0])
dr = np.array(bbox2d[0] - bbox1d[0])
#the rotation/stretch matrix
# the rotation/stretch matrix
rad = rads[il]
rot_mat = np.array([
[math.cos(rad), math.sin(rad)*aspect],
[-math.sin(rad)/aspect, math.cos(rad)]
])
rot_mat = np.array(
[
[math.cos(rad), math.sin(rad) * aspect],
[-math.sin(rad) / aspect, math.cos(rad)],
]
)
##computing the offset vector of the rotated character
drp = np.dot(dr,rot_mat)
drp = np.dot(dr, rot_mat)
#setting final position and rotation:
t.set_position(np.array([x,y])+drp)
# setting final position and rotation:
t.set_position(np.array([x, y]) + drp)
t.set_rotation(degs[il])
t.set_va('center')
t.set_ha('center')
t.set_va("center")
t.set_ha("center")
#updating rel_pos to right edge of character
rel_pos += w-used
# updating rel_pos to right edge of character
rel_pos += w - used

Wyświetl plik

@ -6,7 +6,7 @@ import pandas as pd
from geopandas import GeoDataFrame
import numpy as np
from numpy.random import choice
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, GeometryCollection
from shapely.geometry import box, Polygon, MultiLineString, GeometryCollection
from shapely.affinity import translate, scale, rotate
from descartes import PolygonPatch
from tabulate import tabulate
@ -19,88 +19,93 @@ from .fetch import get_perimeter, get_layer
def get_hash(key):
return frozenset(key.items()) if type(key) == dict else key
# Drawing functions
def show_palette(palette, description = ''):
'''
def show_palette(palette, description=""):
"""
Helper to display palette in Markdown
'''
"""
colorboxes = [
f'![](https://placehold.it/30x30/{c[1:]}/{c[1:]}?text=)'
for c in palette
f"![](https://placehold.it/30x30/{c[1:]}/{c[1:]}?text=)" for c in palette
]
display(Markdown((description)))
display(Markdown(tabulate(pd.DataFrame(colorboxes), showindex = False)))
display(Markdown(tabulate(pd.DataFrame(colorboxes), showindex=False)))
def get_patch(shape, **kwargs):
'''
"""
Convert shapely object to matplotlib patch
'''
#if type(shape) == Path:
"""
# if type(shape) == Path:
# return patches.PathPatch(shape, **kwargs)
if type(shape) == Polygon and shape.area > 0:
return PolygonPatch(list(zip(*shape.exterior.xy)), **kwargs)
else:
return None
# Plot a single shape
def plot_shape(shape, ax, vsketch = None, **kwargs):
'''
def plot_shape(shape, ax, vsketch=None, **kwargs):
"""
Plot shapely object
'''
"""
if isinstance(shape, Iterable) and type(shape) != MultiLineString:
for shape_ in shape:
plot_shape(shape_, ax, vsketch = vsketch, **kwargs)
plot_shape(shape_, ax, vsketch=vsketch, **kwargs)
else:
if not shape.is_empty:
if vsketch is None:
ax.add_patch(PolygonPatch(shape, **kwargs))
else:
if ('draw' not in kwargs) or kwargs['draw']:
if ("draw" not in kwargs) or kwargs["draw"]:
if 'stroke' in kwargs:
vsketch.stroke(kwargs['stroke'])
if "stroke" in kwargs:
vsketch.stroke(kwargs["stroke"])
else:
vsketch.stroke(1)
if 'penWidth' in kwargs:
vsketch.penWidth(kwargs['penWidth'])
if "penWidth" in kwargs:
vsketch.penWidth(kwargs["penWidth"])
else:
vsketch.penWidth(0.3)
if 'fill' in kwargs:
vsketch.fill(kwargs['fill'])
if "fill" in kwargs:
vsketch.fill(kwargs["fill"])
else:
vsketch.noFill()
vsketch.geometry(shape)
# Plot a collection of shapes
def plot_shapes(shapes, ax, vsketch = None, palette = None, **kwargs):
'''
def plot_shapes(shapes, ax, vsketch=None, palette=None, **kwargs):
"""
Plot collection of shapely objects (optionally, use a color palette)
'''
"""
if not isinstance(shapes, Iterable):
shapes = [shapes]
for shape in shapes:
if palette is None:
plot_shape(shape, ax, vsketch = vsketch, **kwargs)
plot_shape(shape, ax, vsketch=vsketch, **kwargs)
else:
plot_shape(shape, ax, vsketch = vsketch, fc = choice(palette), **kwargs)
plot_shape(shape, ax, vsketch=vsketch, fc=choice(palette), **kwargs)
# Parse query (by coordinates, OSMId or name)
def parse_query(query):
if isinstance(query, GeoDataFrame):
return 'polygon'
return "polygon"
elif isinstance(query, tuple):
return 'coordinates'
elif re.match('''[A-Z][0-9]+''', query):
return 'osmid'
return "coordinates"
elif re.match("""[A-Z][0-9]+""", query):
return "osmid"
else:
return 'address'
return "address"
# Apply transformation (translation & scale) to layers
def transform(layers, x, y, scale_x, scale_y, rotation):
@ -118,38 +123,46 @@ def transform(layers, x, y, scale_x, scale_y, rotation):
layers = dict(zip(k, v))
return layers
def draw_text(ax, text, x, y, **kwargs):
ax.text(x, y, text, **kwargs)
# Plot
def plot(
# Address
query,
# Whether to use a backup for the layers
backup = None,
backup=None,
# Custom postprocessing function on layers
postprocessing = None,
postprocessing=None,
# Radius (in case of circular plot)
radius = None,
radius=None,
# Which layers to plot
layers = {'perimeter': {}},
layers={"perimeter": {}},
# Drawing params for each layer (matplotlib params such as 'fc', 'ec', 'fill', etc.)
drawing_kwargs = {},
drawing_kwargs={},
# OSM Caption parameters
osm_credit = {},
osm_credit={},
# Figure parameters
figsize = (10, 10), ax = None, title = None,
figsize=(10, 10),
ax=None,
title=None,
# Vsketch parameters
vsketch = None,
vsketch=None,
# Transform (translation & scale) params
x = None, y = None, scale_x = None, scale_y = None, rotation = None,
):
x=None,
y=None,
scale_x=None,
scale_y=None,
rotation=None,
):
# Interpret query
query_mode = parse_query(query)
# Save maximum dilation for later use
dilations = [kwargs['dilate'] for kwargs in layers.values() if 'dilate' in kwargs]
dilations = [kwargs["dilate"] for kwargs in layers.values() if "dilate" in kwargs]
max_dilation = max(dilations) if len(dilations) > 0 else 0
####################
@ -164,20 +177,20 @@ def plot(
# Define base kwargs
if radius:
base_kwargs = {
'point': query if query_mode == 'coordinates' else ox.geocode(query),
'radius': radius
"point": query if query_mode == "coordinates" else ox.geocode(query),
"radius": radius,
}
else:
base_kwargs = {
'perimeter': query if query_mode == 'polygon' else get_perimeter(query, by_osmid = query_mode == 'osmid')
"perimeter": query
if query_mode == "polygon"
else get_perimeter(query, by_osmid=query_mode == "osmid")
}
# Fetch layers
layers = {
layer: get_layer(
layer,
**base_kwargs,
**(kwargs if type(kwargs) == dict else {})
layer, **base_kwargs, **(kwargs if type(kwargs) == dict else {})
)
for layer, kwargs in layers.items()
}
@ -196,28 +209,22 @@ def plot(
# Matplot-specific stuff (only run if vsketch mode isn't activated)
if vsketch is None:
# Ajust axis
ax.axis('off')
ax.axis('equal')
ax.axis("off")
ax.axis("equal")
ax.autoscale()
# Plot background
if 'background' in drawing_kwargs:
xmin, ymin, xmax, ymax = layers['perimeter'].bounds
geom = scale(Polygon([
(xmin, ymin),
(xmin, ymax),
(xmax, ymax),
(xmax, ymin)
]), 2, 2)
if "background" in drawing_kwargs:
geom = scale(box(*layers["perimeter"].bounds), 2, 2)
if vsketch is None:
ax.add_patch(PolygonPatch(geom, **drawing_kwargs['background']))
ax.add_patch(PolygonPatch(geom, **drawing_kwargs["background"]))
else:
vsketch.geometry(geom)
# Adjust bounds
xmin, ymin, xmax, ymax = layers['perimeter'].buffer(max_dilation).bounds
dx, dy = xmax-xmin, ymax-ymin
xmin, ymin, xmax, ymax = layers["perimeter"].buffer(max_dilation).bounds
dx, dy = xmax - xmin, ymax - ymin
if vsketch is None:
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
@ -225,27 +232,58 @@ def plot(
# Draw layers
for layer, shapes in layers.items():
kwargs = drawing_kwargs[layer] if layer in drawing_kwargs else {}
if 'hatch_c' in kwargs:
if "hatch_c" in kwargs:
# Draw hatched shape
plot_shapes(shapes, ax, vsketch = vsketch, lw = 0, ec = kwargs['hatch_c'], **{k:v for k,v in kwargs.items() if k not in ['lw', 'ec', 'hatch_c']})
plot_shapes(
shapes,
ax,
vsketch=vsketch,
lw=0,
ec=kwargs["hatch_c"],
**{k: v for k, v in kwargs.items() if k not in ["lw", "ec", "hatch_c"]},
)
# Draw shape contour only
plot_shapes(shapes, ax, vsketch = vsketch, fill = False, **{k:v for k,v in kwargs.items() if k not in ['hatch_c', 'hatch', 'fill']})
plot_shapes(
shapes,
ax,
vsketch=vsketch,
fill=False,
**{
k: v
for k, v in kwargs.items()
if k not in ["hatch_c", "hatch", "fill"]
},
)
else:
# Draw shape normally
plot_shapes(shapes, ax, vsketch = vsketch, **kwargs)
plot_shapes(shapes, ax, vsketch=vsketch, **kwargs)
if ((isinstance(osm_credit, dict)) or (osm_credit is True)) and (vsketch is None):
x, y = figsize
d = .8*(x**2+y**2)**.5
d = 0.8 * (x ** 2 + y ** 2) ** 0.5
draw_text(
ax,
(osm_credit['text'] if 'text' in osm_credit else 'data © OpenStreetMap contributors\ngithub.com/marceloprates/prettymaps'),
x = xmin + (osm_credit['x']*dx if 'x' in osm_credit else 0),
y = ymax - 4*d - (osm_credit['y']*dy if 'y' in osm_credit else 0),
fontfamily = (osm_credit['fontfamily'] if 'fontfamily' in osm_credit else 'Ubuntu Mono'),
fontsize = (osm_credit['fontsize']*d if 'fontsize' in osm_credit else d),
zorder = (osm_credit['zorder'] if 'zorder' in osm_credit else len(layers)+1),
**{k:v for k,v in osm_credit.items() if k not in ['text', 'x', 'y', 'fontfamily', 'fontsize', 'zorder']}
(
osm_credit["text"]
if "text" in osm_credit
else "data © OpenStreetMap contributors\ngithub.com/marceloprates/prettymaps"
),
x=xmin + (osm_credit["x"] * dx if "x" in osm_credit else 0),
y=ymax - 4 * d - (osm_credit["y"] * dy if "y" in osm_credit else 0),
fontfamily=(
osm_credit["fontfamily"]
if "fontfamily" in osm_credit
else "Ubuntu Mono"
),
fontsize=(osm_credit["fontsize"] * d if "fontsize" in osm_credit else d),
zorder=(
osm_credit["zorder"] if "zorder" in osm_credit else len(layers) + 1
),
**{
k: v
for k, v in osm_credit.items()
if k not in ["text", "x", "y", "fontfamily", "fontsize", "zorder"]
},
)
# Return perimeter

Wyświetl plik

@ -9,23 +9,34 @@ from geopandas import GeoDataFrame, read_file
# Compute circular or square boundary given point, radius and crs
def get_boundary(point, radius, crs, circle = True, dilate = 0):
def get_boundary(point, radius, crs, circle=True, dilate=0):
if circle:
return ox.project_gdf(
GeoDataFrame(geometry = [Point(point[::-1])], crs = crs)
).geometry[0].buffer(radius)
return (
ox.project_gdf(GeoDataFrame(geometry=[Point(point[::-1])], crs=crs))
.geometry[0]
.buffer(radius)
)
else:
x, y = np.stack(ox.project_gdf(
GeoDataFrame(geometry = [Point(point[::-1])], crs = crs)
).geometry[0].xy)
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 Polygon(
[(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)]
).buffer(dilate)
# Get perimeter
def get_perimeter(query, by_osmid = False, **kwargs):
return ox.geocode_to_gdf(query, by_osmid = by_osmid, **kwargs, **{x: kwargs[x] for x in ['circle', 'dilate'] if x in kwargs.keys()})
def get_perimeter(query, by_osmid=False, **kwargs):
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 coastline
def get_coast(perimeter = None, point = None, radius = None, perimeter_tolerance = 0, union = True, buffer = 0, circle = True, dilate = 0, file_location = None):
@ -68,20 +79,37 @@ def get_coast(perimeter = None, point = None, radius = None, perimeter_tolerance
return geometries
# Get geometries
def get_geometries(perimeter = None, point = None, radius = None, tags = {}, perimeter_tolerance = 0, union = True, circle = True, dilate = 0):
def get_geometries(
perimeter=None,
point=None,
radius=None,
tags={},
perimeter_tolerance=0,
union=True,
circle=True,
dilate=0,
):
if perimeter is not None:
# Boundary defined by polygon (perimeter)
geometries = ox.geometries_from_polygon(
unary_union(perimeter.geometry).buffer(perimeter_tolerance) if perimeter_tolerance > 0 else unary_union(perimeter.geometry),
tags = {tags: True} if type(tags) == str else tags
unary_union(perimeter.geometry).buffer(perimeter_tolerance)
if 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)
elif (point is not None) and (radius is not None):
# Boundary defined by circle with radius 'radius' around point
geometries = ox.geometries_from_point(point, dist = radius+dilate, tags = {tags: True} if type(tags) == str else tags)
perimeter = get_boundary(point, radius, geometries.crs, circle = circle, dilate = dilate)
geometries = ox.geometries_from_point(
point,
dist=radius + dilate,
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:
@ -91,82 +119,135 @@ def get_geometries(perimeter = None, point = None, radius = None, tags = {}, per
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]
], []))
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]
],
[],
)
)
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]
], []))
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
# Get streets
def get_streets(perimeter = None, point = None, radius = None, layer = 'streets', width = 6, custom_filter = None, buffer = 0, retain_all = False, circle = True, dilate = 0):
if layer == 'streets':
layer = 'highway'
# Get streets
def get_streets(
perimeter=None,
point=None,
radius=None,
layer="streets",
width=6,
custom_filter=None,
buffer=0,
retain_all=False,
circle=True,
dilate=0,
):
if layer == "streets":
layer = "highway"
# Boundary defined by polygon (perimeter)
if perimeter is not None:
# Fetch streets data, project & convert to GDF
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.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)
streets = ox.graph_to_gdfs(streets, nodes=False)
# Boundary defined by polygon (perimeter)
elif (point is not None) and (radius is not None):
# Fetch streets data, save CRS & project
streets = ox.graph_from_point(point, dist = radius+dilate+buffer, retain_all = retain_all, custom_filter = custom_filter)
crs = ox.graph_to_gdfs(streets, nodes = False).crs
streets = ox.graph_from_point(
point,
dist=radius + dilate + buffer,
retain_all=retain_all,
custom_filter=custom_filter,
)
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)
perimeter = get_boundary(point, radius, crs, circle=circle, dilate=dilate)
# Convert to GDF
streets = ox.graph_to_gdfs(streets, nodes = False)
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]
if type(width) == dict:
streets = unary_union([
# Dilate streets of each highway type == 'highway' using width 'w'
MultiLineString(
streets[(streets[layer] == highway) & (streets.geometry.type == 'LineString')].geometry.tolist() +
list(reduce(lambda x, y: x+y, [
list(lines)
for lines in streets[(streets[layer] == highway) & (streets.geometry.type == 'MultiLineString')].geometry
], []))
).buffer(w)
for highway, w in width.items()
])
streets = unary_union(
[
# Dilate streets of each highway type == 'highway' using width 'w'
MultiLineString(
streets[
(streets[layer] == highway)
& (streets.geometry.type == "LineString")
].geometry.tolist()
+ list(
reduce(
lambda x, y: x + y,
[
list(lines)
for lines in streets[
(streets[layer] == highway)
& (streets.geometry.type == "MultiLineString")
].geometry
],
[],
)
)
).buffer(w)
for highway, w in width.items()
]
)
else:
# Dilate all streets by same amount 'width'
streets = MultiLineString(streets.geometry.tolist()).buffer(width)
return streets
# Get any layer
def get_layer(layer, **kwargs):
# Fetch perimeter
if layer == 'perimeter':
if layer == "perimeter":
# If perimeter is already provided:
if 'perimeter' in kwargs:
return unary_union(ox.project_gdf(kwargs['perimeter']).geometry)
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:
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()}
kwargs["point"],
kwargs["radius"],
crs,
**{x: kwargs[x] for x in ["circle", "dilate"] if x in kwargs.keys()}
)
return perimeter
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)
return get_streets(**kwargs, layer=layer)
# Fetch Coastline
elif layer == 'coastline':
return get_coast(**kwargs)

Wyświetl plik

@ -4,18 +4,18 @@ from pathlib import Path
parent_dir = Path(__file__).resolve().parent
setup(
name='prettymaps',
version='1.0.0',
description='A simple python library to draw pretty maps from OpenStreetMap data',
name="prettymaps",
version="1.0.0",
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",
url='https://github.com/marceloprates/prettymaps',
author='Marcelo Prates',
author_email='marceloorp@gmail.com',
license='MIT License',
url="https://github.com/marceloprates/prettymaps",
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(),
classifiers=[
'Intended Audience :: Science/Research',
"Intended Audience :: Science/Research",
],
)
)