Skip to main content

Generate Leaflet maps from Python with browser event emission.

Project description

CartoLeaf

CartoLeaf is a lightweight Python library for generating interactive Leaflet.js maps from Python.

It is designed for developers who want the convenience of defining maps in Python, while still keeping the generated map as part of the surrounding web page DOM. This makes it easier to integrate Leaflet maps into dashboards, static pages, server-rendered apps, and custom frontend workflows.

Unlike tools that render maps inside an iframe, CartoLeaf generates HTML and JavaScript that can interact directly with the page. Map objects can emit browser events, expose layer references, and communicate with other DOM elements.

PyPI version Python versions License Documentation

Why CartoLeaf?

CartoLeaf is built for cases where you want more control over how a Python-generated map interacts with the rest of your web application.

It is useful when you want to:

  • Generate interactive Leaflet.js maps from Python
  • Avoid writing repetitive Leaflet JavaScript by hand
  • Keep the map directly accessible in the page DOM
  • Emit browser events from map objects
  • Connect map interactions to other frontend components
  • Add simple maps to dashboards, static pages, server-rendered apps, and custom frontend workflows
  • Render markers, circles, polygons, polylines, and GeoJSON layers with minimal setup

CartoLeaf is not intended to replace full GIS tools. It is designed as a lightweight bridge between Python and Leaflet.js for practical web map generation.

Features

  • Generate interactive Leaflet maps from Python
  • Render maps directly into the page instead of an iframe
  • Add markers, circles, polygons, polylines, and GeoJSON layers
  • Add text or HTML popups
  • Customize map layer styles
  • Support click and hover interactions
  • Emit browser CustomEvent events from map objects
  • Store Leaflet layer references on window.cartoleaf
  • Integrate map interactions with the surrounding DOM
  • Lightweight and dependency-minimal
  • Works well with static HTML, server-rendered apps, dashboards, and custom frontend workflows

Installation

pip install cartoleaf

For local development:

git clone https://github.com/your-username/cartoleaf.git
cd cartoleaf
pip install -e .

Quick Start

from cartoleaf import Map, Marker, Circle, Polygon, Polyline

m = Map(
    center=(1.3521, 103.8198),
    zoom=12,
)

m.add_marker(
    Marker(
        lat=1.3521,
        lng=103.8198,
        popup="Singapore"
    )
)

m.add_circle(
    Circle(
        lat=1.3521,
        lng=103.8198,
        radius=500,
        popup="500m radius",
        style={
            "color": "#2879e4",
            "fillColor": "#2879e4",
            "fillOpacity": 0.2,
        },
    )
)

m.add_polyline(
    Polyline(
        points=[
            (1.3521, 103.8198),
            (1.3000, 103.8500),
        ],
        popup="Sample route",
        style={
            "color": "#2879e4",
            "weight": 4,
            "opacity": 0.8,
        },
    )
)

m.save("map.html")

Open map.html in your browser to view the generated map.

Documentation

Read the full documentation here:

CartoLeaf Documentation

Basic Usage

Create a Map

from cartoleaf import Map

m = Map(
    center=(1.3521, 103.8198),
    zoom=12,
    height="600px",
)

Add a Marker

from cartoleaf import Marker

m.add_marker(
    Marker(
        lat=1.3521,
        lng=103.8198,
        popup="Singapore"
    )
)

Add a Circle

from cartoleaf import Circle

m.add_circle(
    Circle(
        lat=1.3521,
        lng=103.8198,
        radius=500,
        popup="500m radius",
        style={
            "color": "blue",
            "fillColor": "blue",
            "fillOpacity": 0.2,
        },
    )
)

Add a Polygon

from cartoleaf import Polygon

m.add_polygon(
    Polygon(
        coordinates=[
            (1.35, 103.81),
            (1.36, 103.82),
            (1.34, 103.83),
        ],
        popup="Sample polygon",
        style={
            "color": "green",
            "fillOpacity": 0.3,
        },
    )
)

Add a Polyline

from cartoleaf import Polyline

m.add_polyline(
    Polyline(
        points=[
            (1.3521, 103.8198),
            (1.3000, 103.8500),
            (1.2800, 103.8600),
        ],
        popup="Sample path",
        style={
            "color": "#2879e4",
            "weight": 4,
        },
    )
)

Add GeoJSON

from cartoleaf import GeoJson

geojson_data = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {
                "name": "Sample Area"
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [103.81, 1.35],
                    [103.82, 1.36],
                    [103.83, 1.34],
                    [103.81, 1.35],
                ]]
            }
        }
    ]
}

m.add_geojson(
    GeoJson(
        data=geojson_data,
        popup_field="name",
        style={
            "color": "purple",
            "fillOpacity": 0.2,
        },
    )
)

DOM Interaction and Browser Events

CartoLeaf is designed to make map interactions available to the surrounding page.

Map objects can emit browser events that other JavaScript code can listen for.

m.add_marker(
    Marker(
        lat=1.3521,
        lng=103.8198,
        popup="Clickable marker",
        events={
            "click": "marker_clicked"
        },
        data={
            "name": "Singapore"
        }
    )
)

Listen for the event in the browser:

<script>
window.addEventListener("marker_clicked", function (e) {
  console.log("Marker clicked:", e.detail);
});
</script>

This allows you to connect map interactions to other UI elements, such as tables, cards, filters, sidebars, charts, or custom application logic.

Supported event aliases include:

{
    "click": "click",
    "hoverin": "mouseover",
    "hoverout": "mouseout",
}

Leaflet Layer References

CartoLeaf stores generated Leaflet objects on window.cartoleaf, making them accessible from normal browser JavaScript.

Examples:

window.cartoleaf.markers
window.cartoleaf.circles
window.cartoleaf.polygons
window.cartoleaf.polylines
window.cartoleaf.geojsonLayers

This makes it possible to inspect or interact with generated Leaflet layers after the map has rendered.

Popups

CartoLeaf supports both plain text popups and HTML popups.

Text Popup

Marker(
    lat=1.3521,
    lng=103.8198,
    popup="Singapore"
)

HTML Popup

Marker(
    lat=1.3521,
    lng=103.8198,
    popup_html="<strong>Singapore</strong><br>Central location"
)

Use either popup or popup_html, not both.

Hover Popups

You can configure popups to open on hover and close when the cursor leaves the object.

Marker(
    lat=1.3521,
    lng=103.8198,
    popup="Hover popup",
    popup_open_on_hover=True,
    popup_close_on_hoverout=True,
)

This pattern is also supported for other supported map layers.

Styling

Layer styles are passed as dictionaries and mapped to Leaflet style options.

Polygon(
    coordinates=[
        (1.35, 103.81),
        (1.36, 103.82),
        (1.34, 103.83),
    ],
    style={
        "color": "#2879e4",
        "weight": 3,
        "opacity": 0.9,
        "fillColor": "#2879e4",
        "fillOpacity": 0.25,
    },
)

Common style options include:

{
    "color": "#2879e4",
    "weight": 3,
    "opacity": 0.8,
    "fillColor": "#2879e4",
    "fillOpacity": 0.2,
}

Server-rendered Example via Flask

Using Cartoleaf inside a Flask app.

from flask import Flask, render_template_string
from cartoleaf import Map, Marker

app = Flask(__name__)

@app.route("/")
def index():
    m = Map(
        center=(1.3521, 103.8198),
        zoom=12,
    )

    m.add_marker(
        Marker(
            lat=1.3521,
            lng=103.8198,
            popup="Singapore"
        )
    )

    return render_template_string(m.render())

if __name__ == "__main__":
    app.run(debug=True)

Coordinate Format

CartoLeaf uses the standard latitude/longitude format:

(lat, lng)

Example:

(1.3521, 103.8198)

Latitude must be between -90 and 90.

Longitude must be between -180 and 180.

Supported Layers

Layer Description
Marker A point marker on the map
Circle A circular area with a radius in meters
Polygon A closed shape made from multiple points
Polyline A connected line made from multiple points
GeoJson A GeoJSON Feature or FeatureCollection layer

CartoLeaf vs iframe-based map output

CartoLeaf is designed for situations where the map should be part of the page, not isolated from it.

This is useful when you want map interactions to affect other DOM elements, or when other frontend components need to interact with map layers.

Instead of treating the map as a self-contained iframe, CartoLeaf aims to generate Leaflet output that can participate in the rest of your application.

Roadmap

  1. Additional tile provider options
  2. Map-level popup defaults
  3. More marker presets
  4. HTMX integration examples and event helpers
  5. Framework-agnostic integration examples for static HTML, Django, Flask, FastAPI, and server-rendered apps
  6. Layer groups
  7. Layer toggles
  8. Drawing/editing tools
  9. Routing integration with OSM-based services such as OSRM

License

MIT License.

Status

CartoLeaf is currently in early development.

Version 0.1 includes core map generation features, basic Leaflet layer support, styling, popups, and browser event emission.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cartoleaf-0.1.1.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cartoleaf-0.1.1-py3-none-any.whl (22.9 kB view details)

Uploaded Python 3

File details

Details for the file cartoleaf-0.1.1.tar.gz.

File metadata

  • Download URL: cartoleaf-0.1.1.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cartoleaf-0.1.1.tar.gz
Algorithm Hash digest
SHA256 51690de9c9e30f72e92ab30db53efa409589541287d3539a47cadd967c462807
MD5 0293edb06a224200d7327c28686989cb
BLAKE2b-256 ab6d1bad03d56dc79acca926ddbc9d81fa98f2fe118478a22633dd4bf6ee2c5d

See more details on using hashes here.

File details

Details for the file cartoleaf-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: cartoleaf-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 22.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cartoleaf-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4bc16850f345ad2a25859394263632d8a67ffaf2c50a1dcd1b216cd2c0e00c93
MD5 0c9cd0618ff2667c60af563f3e653081
BLAKE2b-256 147a6f8396d4a988d206b21af9bce33420b24de4169a0704b31629c670cf455d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page