diff --git a/prettymaps/draw.py b/prettymaps/draw.py index e5fcb6c..4feecbd 100644 --- a/prettymaps/draw.py +++ b/prettymaps/draw.py @@ -528,13 +528,21 @@ def create_background( Tuple[BaseGeometry, float, float, float, float, float, float]: background geometry, bounds, width and height """ # Create background - background_pad = 1.1 + # pad is the value with which to scale the perimeter to get the background. + # dilate is the value in metter to add to the perimeter to get the background. + # the pad scaling is applied after the dilate addition. + + background_pad = 1 if "background" in style and "pad" in style["background"]: background_pad = style["background"].pop("pad") + background_dilate = 0 + if "background" in style and "dilate" in style["background"]: + background_dilate = style["background"].pop("dilate") + background = shapely.affinity.scale( box(* - shapely.ops.unary_union(ox.project_gdf(gdfs["perimeter"]).geometry).bounds), + shapely.ops.unary_union(ox.project_gdf(gdfs["perimeter"]).geometry.buffer(background_dilate)).bounds), background_pad, background_pad, ) @@ -801,10 +809,12 @@ def plot( update_preset=None, # Custom postprocessing function on layers postprocessing=None, - # Circular boundary? Default: square + # Circular boundary? Default: rectangular circle=None, - # Radius for circular or square boundary + # Radius for circular or rectangular boundary radius=None, + # Ratio width/height for rectangular boundary. Radius is the height of the rectangle. Default: square + ratio=1, # Dilate boundary by this much dilate=None, # Whether to save result @@ -894,7 +904,7 @@ def plot( layers = override_args(layers, circle, dilate) # 4. Fetch geodataframes - gdfs = get_gdfs(query, layers, radius, dilate, -rotation) + gdfs = get_gdfs(query, layers, radius, ratio, dilate, -rotation) # 5. Apply transformations to GeoDataFrames (translation, scale, rotation) gdfs = transform_gdfs(gdfs, x, y, scale_x, scale_y, rotation) diff --git a/prettymaps/fetch.py b/prettymaps/fetch.py index 633a7e3..68b701f 100644 --- a/prettymaps/fetch.py +++ b/prettymaps/fetch.py @@ -57,8 +57,8 @@ def parse_query(query): return "address" -# Get circular or square boundary around point -def get_boundary(query, radius, circle=False, rotation=0): +# Get circular or rectangular boundary around point +def get_boundary(query, radius, ratio, circle=False, rotation=0): # Get point from query point = query if parse_query(query) == "coordinates" else ox.geocode(query) @@ -70,15 +70,16 @@ def get_boundary(query, radius, circle=False, rotation=0): if circle: # Circular shape # use .buffer() to expand point into circle boundary.geometry = boundary.geometry.buffer(radius) - else: # Square shape + else: # rectangular shape x, y = np.concatenate(boundary.geometry[0].xy) - r = radius + dx = radius * ratio + dy = radius boundary = GeoDataFrame( geometry=[ rotate( Polygon( - [(x - r, y - r), (x + r, y - r), - (x + r, y + r), (x - r, y + r)] + [(x - dx, y - dy), (x + dx, y - dy), + (x + dx, y + dy), (x - dx, y + dy)] ), rotation, ) @@ -94,13 +95,13 @@ def get_boundary(query, radius, circle=False, rotation=0): # Get perimeter from query def get_perimeter( - query, radius=None, by_osmid=False, circle=False, dilate=None, rotation=0, **kwargs + query, radius=None, ratio=1, by_osmid=False, circle=False, dilate=None, rotation=0, **kwargs ): if radius: - # Perimeter is a circular or square shape + # Perimeter is a circular or rectangular shape perimeter = get_boundary( - query, radius, circle=circle, rotation=rotation) + query, radius, ratio, circle=circle, rotation=rotation) else: # Perimeter is a OSM or user-provided polygon if parse_query(query) == "polygon": @@ -128,6 +129,7 @@ def get_gdf( layer, perimeter, perimeter_tolerance=0, + dilate=0, tags=None, osmid=None, custom_filter=None, @@ -143,12 +145,15 @@ def get_gdf( **kwargs ): + if dilate == None: + dilate = 0 + # 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) + ox.project_gdf(perimeter).buffer(dilate + perimeter_tolerance).to_crs(4326) ) perimeter_with_tolerance = unary_union( perimeter_with_tolerance.geometry).buffer(0) @@ -204,7 +209,7 @@ def get_gdf( # Fetch GeoDataFrames given query and a dictionary of layers -def get_gdfs(query, layers_dict, radius, dilate, rotation=0) -> dict: +def get_gdfs(query, layers_dict, radius, ratio, dilate, rotation=0) -> dict: perimeter_kwargs = {} if "perimeter" in layers_dict: @@ -215,6 +220,7 @@ def get_gdfs(query, layers_dict, radius, dilate, rotation=0) -> dict: perimeter = get_perimeter( query, radius=radius, + ratio=ratio, rotation=rotation, dilate=dilate, **perimeter_kwargs diff --git a/prettymaps/presets/barcelona.json b/prettymaps/presets/barcelona.json index 34b8f15..0c98105 100644 --- a/prettymaps/presets/barcelona.json +++ b/prettymaps/presets/barcelona.json @@ -1 +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} \ No newline at end of file +{"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...", "pad": 1.1, "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} \ No newline at end of file diff --git a/prettymaps/presets/default.json b/prettymaps/presets/default.json index 2a555d0..a9dc5eb 100644 --- a/prettymaps/presets/default.json +++ b/prettymaps/presets/default.json @@ -69,6 +69,7 @@ }, "background": { "fc": "#F2F4CB", + "pad": 1.1, "zorder": -1 }, "green": { diff --git a/prettymaps/presets/heerhugowaard.json b/prettymaps/presets/heerhugowaard.json index df71591..6933273 100644 --- a/prettymaps/presets/heerhugowaard.json +++ b/prettymaps/presets/heerhugowaard.json @@ -69,6 +69,7 @@ }, "background": { "fc": "#F2F4CB", + "pad": 1.1, "zorder": -1 }, "green": { diff --git a/prettymaps/presets/macao.json b/prettymaps/presets/macao.json index 98d6c3e..7b0bbc7 100644 --- a/prettymaps/presets/macao.json +++ b/prettymaps/presets/macao.json @@ -59,6 +59,7 @@ "fc": "#F2F4CB", "ec": "#dadbc1", "hatch": "ooo...", + "pad": 1.1, "zorder": -1 }, "perimeter": { diff --git a/prettymaps/presets/minimal.json b/prettymaps/presets/minimal.json index 2d21eb1..2ed8d2d 100644 --- a/prettymaps/presets/minimal.json +++ b/prettymaps/presets/minimal.json @@ -25,6 +25,7 @@ }, "background": { "fc": "#fff", + "pad": 1.1, "zorder": -1 }, "streets": {