Skip to content

Showcase

One import. A few method calls. A full interactive map.

This page is the whole of mapyta on a single scroll. Every map below is real β€” rendered live in your browser from the exact code shown. Skim it top to bottom to see what mapyta can do, then follow the β†’ Full tutorial link under any section for the details.

New to mapyta? Install it and you're ready:

uv add mapyta
# or
pip install mapyta

Your first map

The smallest complete map: one point, a hover tooltip, and a click popup.

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

from shapely.geometry import Point
from mapyta import Map

m = Map(title="Hello Utrecht")
m.add_point(
    point=Point(5.121311, 52.090648),
    tooltip="**Utrecht**",
    popup="**Utrecht**\nCity in the Netherlands\nPopulation: ~350k",
    caption="UTR",
)

β†’ Full tutorial: Your First Map


Shapely-native geometry

Pass Point, LineString, and Polygon straight from Shapely β€” no conversion, no wrappers. Style each with plain dicts.

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

from shapely.geometry import Point, LineString, Polygon
from mapyta import Map

m = Map(title="Geometries")
m.add_polygon(
    polygon=Polygon([(5.10, 52.08), (5.14, 52.08), (5.14, 52.10), (5.10, 52.10)]),
    tooltip="**Binnenstad**",
    stroke={"color": "green", "weight": 2},
    fill={"color": "blue", "opacity": 0.15},
)
m.add_linestring(
    line=LineString([(5.108, 52.089), (5.117, 52.086), (5.127, 52.084)]),
    tooltip="**Tram route**",
    stroke={"color": "red", "weight": 4, "dash_array": "10 6"},
)
m.add_point(Point(5.121, 52.091), marker="πŸ“", tooltip="**Dom Tower**")
m.set_bounds(padding=0.005)

β†’ Full tutorial: Lines & Polygons


Markers your way

Emoji, Font Awesome icons, or fixed-size circle markers β€” mix them freely, styled with CSS dicts.

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

from shapely.geometry import Point
from mapyta import Map, CircleStyle, StrokeStyle, FillStyle

m = Map(title="Marker Styles")
m.add_point(Point(5.1213, 52.0908), marker="πŸ›οΈ", tooltip="**Dom Tower** (emoji)")
m.add_point(
    point=Point(5.1178, 52.0865),
    marker="fa-house",
    tooltip="**Centraal Museum** (Font Awesome)",
    marker_style={"font-size": "24px", "color": "green"},
)
m.add_circle(
    point=Point(5.1378, 52.0871),
    tooltip="**Rietveld House** (circle)",
    style=CircleStyle(radius=12, stroke=StrokeStyle(color="#8e44ad", weight=2), fill=FillStyle(color="#8e44ad", opacity=0.5)),
)
m.set_bounds(padding=0.005)

β†’ Full tutorial: Markers


Markdown tooltips and popups

Tooltips and popups take Markdown β€” bold, italic, links, lists, and code β€” so hover and click text stays readable without hand-written HTML.

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

from shapely.geometry import Point
from mapyta import Map

m = Map(title="Rich Text")
m.add_point(
    point=Point(5.1213, 52.0908),
    marker="πŸ“–",
    tooltip="**Dom Tower**\n*tallest church tower in NL*",
    popup="### Dom Tower\n\n- Built: **1382**\n- Height: `112.5 m`\n- [Wikipedia](https://en.wikipedia.org/wiki/Dom_Tower,_Utrecht)",
    popup_style={"width": 280, "height": 150},
)

β†’ Full tutorial: Tooltips & Popups


Choropleth

Shade regions by a numeric value and get a color legend automatically.

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

from mapyta import Map

geojson = {
    "type": "FeatureCollection",
    "features": [
        {"type": "Feature", "properties": {"name": "Binnenstad", "score": 92},
         "geometry": {"type": "Polygon", "coordinates": [[[5.10, 52.08], [5.14, 52.08], [5.14, 52.10], [5.10, 52.10], [5.10, 52.08]]]}},
        {"type": "Feature", "properties": {"name": "West", "score": 74},
         "geometry": {"type": "Polygon", "coordinates": [[[5.06, 52.08], [5.10, 52.08], [5.10, 52.10], [5.06, 52.10], [5.06, 52.08]]]}},
        {"type": "Feature", "properties": {"name": "Oost", "score": 85},
         "geometry": {"type": "Polygon", "coordinates": [[[5.14, 52.08], [5.18, 52.08], [5.18, 52.10], [5.14, 52.10], [5.14, 52.08]]]}},
    ],
}

m = Map(title="Neighbourhood Scores")
m.add_choropleth(
    geojson_data=geojson,
    value_column="score",
    key_on="feature.properties.name",
    legend_name="Liveability Score",
    hover_fields=["name", "score"],
    fill_opacity=0.7,
)

β†’ Full tutorial: Choropleth Maps


Heatmap

For dense point data, a heatmap shows intensity patterns at a glance.

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

import random
from shapely.geometry import Point
from mapyta import Map, HeatmapStyle

random.seed(42)
points = [Point(5.12 + random.gauss(0, 0.03), 52.09 + random.gauss(0, 0.015)) for _ in range(200)]

m = Map(title="Activity Heatmap")
m.add_heatmap(points=points, style=HeatmapStyle(radius=20, blur=15, min_opacity=0.4))

β†’ Full tutorial: Heatmaps


Marker clusters

Hundreds of markers stay readable β€” nearby points group into numbered bubbles that expand as you zoom in.

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

import random
from shapely.geometry import Point
from mapyta import Map

random.seed(42)
cafes = [Point(5.12 + random.uniform(-0.02, 0.02), 52.09 + random.uniform(-0.01, 0.01)) for _ in range(50)]

m = Map(title="Utrecht CafΓ©s")
m.add_marker_cluster(
    points=cafes,
    labels=["β˜•"] * 50,
    tooltips=[f"**CafΓ© #{i + 1}**" for i in range(50)],
    name="CafΓ©s",
)

β†’ Full tutorial: Marker Clusters


DataFrame in one line

Already have your data in Pandas or Polars? Point add_dataframe() at a WKT geometry column and every other column becomes a hover field.

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

import pandas as pd
from mapyta import Map

df = pd.DataFrame({
    "geometry": ["POINT (4.9041 52.3676)", "POINT (5.1214 52.0907)", "POINT (4.4777 51.9244)"],
    "city": ["Amsterdam", "Utrecht", "Rotterdam"],
    "population": [872_680, 361_924, 651_446],
})

m = Map(title="Dutch Cities")
m.add_dataframe(df, hover_fields=["city", "population"])

β†’ Full tutorial: DataFrames Β· GeoPandas


add_search_control() drops in a search box that centers the map on the matching feature β€” labels are inferred automatically.

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

from shapely.geometry import Point
from mapyta import Map

m = Map(title="City Finder")
m.add_point(Point(4.9003, 52.3728), marker="πŸ™οΈ", caption="Amsterdam")
m.add_point(Point(5.1214, 52.0907), marker="πŸ™οΈ", caption="Utrecht")
m.add_point(Point(4.4777, 51.9244), marker="πŸ™οΈ", caption="Rotterdam")
m.add_point(Point(4.3007, 52.0705), marker="πŸ™οΈ", caption="Den Haag")
m.add_point(Point(5.4697, 51.4416), marker="πŸ™οΈ", caption="Eindhoven")
m.add_search_control(placeholder="Find city...")

β†’ Full tutorial: Search Control


Let users draw

Turn on drawing tools and let users sketch markers, lines, and polygons β€” then capture what they drew.

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

from mapyta import Map, MapConfig

m = Map(title="Drawing demo", center=(52.0907, 5.1214), config=MapConfig(zoom_start=13))
m.enable_draw()

Use the toolbar in the map's top-left corner to draw a shape.

β†’ Full tutorial: Drawing Tools


Animation

Ant paths trace a route with marching-ants motion, making direction of travel obvious at a glance.

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

from shapely.geometry import LineString
from mapyta import Map

m = Map(title="Intercity route β€” Amsterdam to Eindhoven")
route = LineString([
    (4.9041, 52.3676),  # Amsterdam
    (5.1214, 52.0907),  # Utrecht
    (5.3037, 51.6978),  # 's-Hertogenbosch
    (5.4697, 51.4416),  # Eindhoven
])
m.add_ant_path(route, tooltip="**Amsterdam β†’ Eindhoven**", color="#e74c3c", pulse_color="#ffffff", weight=5, delay=400)
m.set_bounds(padding=0.08)

β†’ Full tutorial: Animated Layers


Export anywhere

The same map exports to HTML, PNG (file, raw bytes, or an in-memory buffer), and GeoJSON β€” sync or async.

# HTML β€” always works, no extra dependencies
m.to_html("map.html")               # write a standalone file
html_string = m.to_html()           # or get it as a string

# PNG β€” needs mapyta[export] and a Chromium-based browser
m.to_image("map.png", scale=2.0)    # high-DPI file
png_bytes = m.to_image()            # raw PNG bytes in memory
buf = m.to_bytesio()                # io.BytesIO, for Flask/FastAPI/Django responses
png_bytes = await m.to_image_async()  # async variant

# GeoJSON β€” every feature you added, back out as a FeatureCollection
fc = m.to_geojson()                 # a dict
m.to_geojson("map.geojson")         # or a file

β†’ Full tutorial: Export


Where to next

  • πŸ“š Tutorial β€” learn mapyta from zero, one concept per page.
  • πŸ”§ API reference β€” every class, method, and parameter.
  • πŸ™ GitHub β€” source, issues, and releases.