Skip to content

Lines & Polygons

Points are useful, but maps really come alive with shapes. Let's draw a walking route and highlight a neighbourhood in Utrecht.

Make this Notebook Trusted to load map: File -> Trust Notebook

from shapely.geometry import LineString, Polygon
from mapyta import Map, StrokeStyle, FillStyle

m = Map(title="Utrecht Walk")

route = LineString([
    (5.1097, 52.0894),  # Centraal Station
    (5.1133, 52.0934),  # Vredenburg
    (5.1197, 52.0919),  # Neude
    (5.1213, 52.0908),  # Dom Tower
])
m.add_linestring(
    line=route,
    tooltip="**Walking route**\n*Centraal → Dom Tower*",
    stroke=StrokeStyle(color="#e74c3c", weight=4, dash_array="10 6"),
)

wittevrouwen = Polygon([
    (5.1195, 52.0915),  # SW near Dom Tower
    (5.1242, 52.0897),  # S along Drift
    (5.1298, 52.0893),  # SE bend
    (5.1362, 52.0908),  # E along Singel (south)
    (5.1378, 52.0948),  # NE corner
    (5.1318, 52.0975),  # N Wittevrouwensingel
    (5.1252, 52.0970),  # NW notch
    (5.1208, 52.0952),  # W back toward Dom
])
m.add_polygon(
    polygon=wittevrouwen,
    tooltip="**Wittevrouwen**\nHistoric neighbourhood",
    stroke=StrokeStyle(color="#2ecc71", weight=2),
    fill=FillStyle(color="#2ecc71", opacity=0.15),
)

m.to_html("utrecht_walk.html")

How it works

Coordinates are always (longitude, latitude), that's the Shapely convention (x, y). Map handles the flip to Leaflet's (lat, lon) internally.

StrokeStyle controls borders and lines. Fields: color, weight (pixels), opacity, and dash_array (SVG pattern like "10 6" for dashes).

FillStyle controls polygon fills: color and opacity. Skip it for the default blue at 20% opacity.

Markdown in tooltips supports **bold**, *italic*, `code`, [links](url), # headers, and - list items. Use \n for line breaks.

All geometry types

Map handles every Shapely geometry: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, and LinearRing. Use specific methods or add_geometry() which auto-dispatches by type:

m.add_geometry(some_shapely_object, tooltip="Works for any type")

Style with dicts or dataclass objects

StrokeStyle, FillStyle, and CircleStyle accept either a dataclass instance or a plain dict with the same keys:

from shapely.geometry import Polygon
from mapyta import Map

m = Map(title="Quick styling")
poly = Polygon([
    (5.100, 52.080), (5.120, 52.076), (5.138, 52.083),
    (5.133, 52.095), (5.114, 52.099), (5.101, 52.090),
])

m.add_polygon(
    poly,
    stroke={"color": "red", "weight": 4},
    fill={"color": "red", "opacity": 0.15},
)

Make this Notebook Trusted to load map: File -> Trust Notebook

Use dataclass objects when you want IDE autocomplete or want to reuse a style across multiple geometries:

from shapely.geometry import Polygon
from mapyta import Map, StrokeStyle

m = Map(title="Reusable styles")
my_stroke = StrokeStyle(color="red", weight=4)

poly1 = Polygon([
    (5.100, 52.080), (5.120, 52.076), (5.138, 52.083),
    (5.133, 52.095), (5.114, 52.099), (5.101, 52.090),
])
poly2 = Polygon([
    (5.082, 52.088), (5.098, 52.083), (5.108, 52.091),
    (5.102, 52.101), (5.083, 52.098), (5.076, 52.093),
])
m.add_polygon(poly1, stroke=my_stroke)
m.add_polygon(poly2, stroke=my_stroke)

Make this Notebook Trusted to load map: File -> Trust Notebook

Polygons with holes

Pass interior rings as the second argument to Polygon, they render as cutouts:

from shapely.geometry import Polygon
from mapyta import Map

m = Map(title="Wilhelminapark")
wilhelminapark = Polygon(
    [
        (5.1215, 52.0835), (5.1252, 52.0828), (5.1278, 52.0838),
        (5.1282, 52.0863), (5.1262, 52.0880), (5.1232, 52.0881),
        (5.1203, 52.0868), (5.1198, 52.0848),
    ],
    [[
        (5.1228, 52.0848), (5.1255, 52.0845), (5.1260, 52.0860),
        (5.1242, 52.0867), (5.1222, 52.0859),
    ]],
)
m.add_polygon(wilhelminapark, tooltip="**Wilhelminapark**, the hole is the pond!")

Make this Notebook Trusted to load map: File -> Trust Notebook