Search code examples
javascriptpythonleafletfolium

Python: How to extend Folium functionality (such as measuring distance) by using JS Leaflet inside python code?


I have begun to use Folium to publish some maps inside a GUI. The user is able to enter start and end coordinates and they show up as Folium Markers. I know that Folium library is just a wrapper around Leaflet, so could we use the parent library for methods that do not exist in Folium?

For instance, I want to use Leaflet.LatLng.distanceTo method to calculate the distance between start and end coordinates using the implemented spherical law of cosines. How I could use them inside my .py files?

I Attached this example code to represent where I'm stuck:

       .
       ..
       ...
       self.map = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
       ..
       ..
        self.m = folium.Map(
            location=[32.5236, 54], tiles="Stamen terrain", zoom_start=5, control_scale= True,
            box_zoom= True)

        # adds the markers
        self.marker1 =  folium.Marker((lat_1, lng_1)).add_to(self.m)
        self.marker2 =  folium.Marker((lat_2, lng_2)).add_to(self.m)

        #add above to the map
        self.data = io.BytesIO()
        self.m.save(self.data, close_file=False)
        self.map.setHtml(self.data.getvalue().decode())
        self.m.add_child(folium.LatLngPopup())

        """ 
        Enter the JavaScript Leaflet
        {
         Here I want "Leaflet.distanceTo((lat_1, lng_1), (lat_2, lng_2))" method
         }
        """

One of the other disadvantages of Foilum is the inability to remove map elements such as the start marker that the user wants to edit (this part's irrelevant, I'm only saying it to make you more familiar with the situation). It would be really good to solve these using appropriate Leaflet methods.

Any idea would be much obliged...


Solution

  • You can add any html, css or Javascript you want to a map. Here's an example of how to create a custom folium element and then overwrite its template.

    el = folium.MacroElement().add_to(m)
    el._template = jinja2.Template("""
        {% macro script(this, kwargs) %}
        // write JS here
        {% endmacro %}
    """)
    

    The script macro is a custom Jinja2 macro that makes sure the code within is placed in the script tags at the bottom of the page. Other options are header for the head and html for the body.

    You can also access the name in Javascript of folium objects you made before:

    popup = folium.LatLngPopup()
    popup_js_name = popup.get_name()
    

    Since it seems you already know a bit about folium and Leaflet I hope this is enough to help!