Insert the folium maps into the jinja template

11,454

Solution 1

You could save your generated html with folium_map.save('templates/map.html'). Then you can use jinja2 to {% include "map.html" %}. The generated html does not render a map when wrapped in div tags as indicated, if encapsulation is necessary consider using iframes or custom folium templates.

file structure

myapp
├── run.py
└── templates
    ├── index.html
    └── layout.html

run.py

from flask import Flask, render_template
import folium

app = Flask(__name__)

@app.route('/')
def index():
    start_coords = (46.9540700, 142.7360300)
    folium_map = folium.Map(location=start_coords, zoom_start=14)
    folium_map.save('templates/map.html')
    return render_template('index.html')

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

layout.html

<!DOCTYPE HTML>
<head>
  <title>{% block title %}{% endblock %}</title>
</head>
<body>
  <header>{% block head %}{% endblock %}</header>
  {% block body %}{% endblock %}
</body>
</html>

index.html

{% extends "layout.html" %}
{% block title %} Test {% endblock %}
{% block head %} {{ super() }} {% endblock %}
{% block body %}
    {% include "map.html" %}
{% endblock %}

Solution 2

Maybe it can be the solution. First we save a Folium map as an html file on templates folder. Then we create a Flask route to render another html file. On that html file, we create an iframe element that call our map.

Here is the file structure:

proectApp
├── app.py
└── templates
    ├── index.html
    └── map.html

Folium map file (map.html) will be created automatically from my app.py. On app.py I'll create 2 main route: the first one is the home route which will render index.html & create map.html. Then the other is to render folium map (map.html). Here are the codes:

app.py

from flask import Flask, render_template
import folium

app = Flask(__name__)

@app.route('/')
def index():
    start_coords = (-6.1753924, 106.8271528)
    folium_map = folium.Map(
        location=start_coords, 
        zoom_start=17
    )
    folium_map.save('templates/map.html')
    return render_template('index.html')

@app.route('/map')
def map():
    return render_template('7_map.html')

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

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Folium Map</title>
</head>
<body>
    <h1>Render Folium on Flask 🌏</h1>
    <iframe class="map", src="/map" width="600" height="600"></iframe>
    <h3><b style="background-color: lightcoral; color: lightcyan;">
        Render Folium on Flask done!
    </b></h3>
</body>
</html>

The result will be shown on browser like this:

folium on flask

Hope it helps you.

Solution 3

A different solution using iframe and render_template

<iframe class="map", src="/get_map" width="1100" height="600"></iframe>

Plus python flask code

# a hack going on here as web servers are caching folium generated template
# randomly move to a new name and then use render_template
@app.route('/get_map')
def get_map():
    r = int(random.triangular(0,100))
    t = "templates/map_{i}.html"
    for i in range(0,100):
        f = t.format(i=i)
        if os.path.exists(f):
            os.remove(f)
    f = t.format(i=r)
    shutil.copy("templates/map.html", f)

    r = make_response(render_template(os.path.split(f)[1]))
    r.cache_control.max_age = 0
    r.cache_control.no_cache = True
    r.cache_control.no_store = True
    r.cache_control.must_revalidate = True
    r.cache_control.proxy_revalidate = True
    return r

Without the copy to a random filename before rendering httpd (on AWS beanstalk) / flask debug environment was not picking up new instance of folium html template. cache_control is not needed but was part of what I trialed to come to a solution. Clearly this solution is not thread safe

Share:
11,454
Andrei
Author by

Andrei

Updated on June 14, 2022

Comments

  • Andrei
    Andrei almost 2 years

    I want to insert follium map into the jinja template.

    run.py

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    
    
    @app.route('/')
    def index():
        start_coords = (46.9540700, 142.7360300)
        folium_map = folium.Map(location=start_coords, zoom_start=14)
        folium_map.save()
        return render_template('index.html', folium_map=folium_map)
    
    
        if __name__ == '__main__':
        app.run(debug=True)
    

    template/index.html - jinja template for Flask

    {% extends "layout.html" %}
    {% block title %}Test{% endblock %}
    {% block head %}
    {{ super() }}
    {% endblock %}
    {% block body %}
    **<div><!--Folium map here-->{{ folium_map }}</div>**
    {% endblock %}
    

    My site shows current line:

    <folium.folium.Map object at 0x00000000069D5DA0>
    

    But I need map that generate method follium_map.save('map.html') in this div block.

    How can I do this?

  • Josh
    Josh almost 5 years
    Thank you! I've been struggling to do just this until I found your answer. I am hoping to add a javascript function that will return coordinate data to python. Is there a way to add JS to somehow be inserted into the html produced by folium?
  • brennan
    brennan almost 5 years
    In this example, I suppose that would be possible by modifying map.html or layout.html before calling render_template... or you could generate a temporary layout file and refer to it using a variable inside the extends block of index.html.
  • Josh
    Josh almost 5 years
    Thank you, modifying map.html before calling render_template worked!
  • airalcorn2
    airalcorn2 about 3 years
    You need to change return render_template('7_map.html') to return render_template('map.html') or you will get a jinja2.exceptions.TemplateNotFound: 7_map.html error.