Will
Will

Reputation: 315

Adding a Mapbox geocoder to a Folium map

I am working on building out a simple web map in Folium that adds the functionality of a Mapbox geocoder to the index.html file that is generated from my map script. From what I can find, I don't see any way to add a geocoder directly in my Python script (which uses the Folium library), so this seems just about the only way to accomplish this.

I've looked at Mapbox's documentation, and while I'm very new to Javascript, I'm hoping that I can just copy & paste pieces of the Javascript in the referenced documentation directly into the index.html file that's spit out.

Here's my Python script that initially creates the map in Folium. It only contains a single marker in downtown Atlanta with a Layer Control box in the top-left corner of the map. For the sake of brevity, I've made this map as practically stripped down as possible:

# dependencies
import folium

# Declare map variable
m = folium.Map(location=[33.756290532017985, -84.39698869622109],
               tiles=None,
               zoom_start=11,
               zoom_control=False)

# Mapbox street layer
folium.TileLayer(
    tiles = 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1Ijoid3dyaWdodDIxIiwiYSI6ImNsNmNnbW92cjF3YXczY281NXRua25xMHgifQ.1Xa_wr0DUhuoNGP0Cbe5Kg',
    attr = 'Mapbox',
    name = 'Streets',
    overlay = False,
    control = True,
    show = True,
    min_zoom = 11,
    max_zoom = 30
    ).add_to(m)

# Add marker in Atlanta
folium.Marker([33.74908343904121, -84.38812827298649]).add_to(m)

# Add in layer control
folium.LayerControl(position='topleft').add_to(m)

m.save("../index.html")

The resulting index.html (when opened in VSCode) looks very ugly. To my eyes, it's practically unreadable but nevertheless reproduced here:

<!DOCTYPE html>
<head>    
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    
        <script>
            L_NO_TOUCH = false;
            L_DISABLE_3D = false;
        </script>
    
    <style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
    <style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js"></script>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css"/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css"/>
    
            <meta name="viewport" content="width=device-width,
                initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
            <style>
                #map_c8f6a7d59d7e0d75d463b5df65347ca6 {
                    position: relative;
                    width: 100.0%;
                    height: 100.0%;
                    left: 0.0%;
                    top: 0.0%;
                }
            </style>
        
</head>
<body>    
    
            <div class="folium-map" id="map_c8f6a7d59d7e0d75d463b5df65347ca6" ></div>
        
</body>
<script>    
    
            var map_c8f6a7d59d7e0d75d463b5df65347ca6 = L.map(
                "map_c8f6a7d59d7e0d75d463b5df65347ca6",
                {
                    center: [33.756290532017985, -84.39698869622109],
                    crs: L.CRS.EPSG3857,
                    zoom: 11,
                    zoomControl: false,
                    preferCanvas: false,
                }
            );

            var tile_layer_57433496d1534b262b2ead21a58cd5f2 = L.tileLayer(
                "https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1Ijoid3dyaWdodDIxIiwiYSI6ImNsNmNnbW92cjF3YXczY281NXRua25xMHgifQ.1Xa_wr0DUhuoNGP0Cbe5Kg",
                {"attribution": "Mapbox", "detectRetina": false, "maxNativeZoom": 30, "maxZoom": 30, "minZoom": 11, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
            ).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
        
    
            var marker_c56903aa791d9f42199fb8edd7fbf18e = L.marker(
                [33.74908343904121, -84.38812827298649],
                {}
            ).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
        
    
            var layer_control_31fb53235cbe88479bc47b285b10ca9c = {
                base_layers : {
                    "Streets" : tile_layer_57433496d1534b262b2ead21a58cd5f2,
                },
                overlays :  {
                },
            };
            L.control.layers(
                layer_control_31fb53235cbe88479bc47b285b10ca9c.base_layers,
                layer_control_31fb53235cbe88479bc47b285b10ca9c.overlays,
                {"autoZIndex": true, "collapsed": true, "position": "topleft"}
            ).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
        
</script>

Once I get to this step, I've tried nearly every possible combination of copy/pasting in the various bits of JS from the Mapbox geocoder documentation (referenced at the beginning of this post), but I'm not sure where exactly it goes or if this is even possible to do. I've made sure to properly change all the necessary references to the map object once I copy it over, but I can't get it working properly. That is, I can't get the index.html file that is generated from my Python script to correctly show an autofill geocoder box (similar to what you get with Google Maps). The error that I get most often from my browser console is RangeError: Maximum call stack size exceeded

Is it even possible to "add in" a Mapbox geocoder to a Folium map that's built in a Python environment? If not, is there a better way to build out a Folium map in Python but still manage to incorporate some of the really cool Mapbox features, like the geocoder?

Upvotes: 0

Views: 728

Answers (1)

Steve Bennett
Steve Bennett

Reputation: 126245

You can't do what you're trying to do.

Folium generates code for Mapbox.js, which is based on Leaflet.

Mapbox-GL-Geocoder, as its name suggests, works with Mapbox GL JS.

Different, incompatible libraries.

Upvotes: 1

Related Questions