opened
Alcampopiano
username_0
Hi guys,

Hopefully an easy one. I'm making a few changes to the html once the map is saved to a file. Is there a way to access the html directly, without using m.save()?
access the map's html, without saving the file
issue
created
Conengmo
username_1
I was wondering this myself as well. I think I found out how, by following the parent classes from `Map` to `LegacyMap` and then `MacroElement` and `Element` in Branca. That last one has the `save()` method you want to imitate.
You can call `get_root()` on the `Map` object and get the `Figure` object that is created in the initialization of `Map`. On that you can call `render()` to create the complete html:
`m = folium.Map()`
`html_string = m.get_root().render()`
comment
created
Alcampopiano
username_0
Hi Frank. Thanks for digging into this. What I am trying to do is to be able to make changes to the map's HTML, but still display it so that it will show up in the notebook when it's exported as HTML.

When I use iPython like so,
`display(HTML('<iframe src=' + myMap.html + ' width=100% height=1000></iframe>'))`

The resulting map is not fully embedded/portable in the HTML notebook (it can't be sent to colleagues). 

So basically, is there a way to be able to make changes to the map's HTML, but still have it fully embedded in the notebook when it's exported as HTML? 

Sincerely,
Al
comment
created
Alcampopiano
username_0
@username_2 That will display the map with base64 encoding, which is great, but I am trying to make adjustments ("hacks") to the HTML string first, and then have it get rendered with base64 encoding.

So for example, as @username_1 suggested, if I wanted to force a heat map to stay on top of a choropleth, I could append some HTML to the main HTML that Folium creates, as follows:

`html_data=html_data + '<style>.leaflet-heatmap-layer{z-index:300 !important}</style>'`

The question now is how to display this new map, with base64 encoding, so that the map is nice and portable.

I've tried converting my altered HTML to base64, prior to displaying it by using,
```
import base64
b64 = base64.b64encode(html_data.encode())
```
But that just shows a blank page. 
Any ideas?
comment
created
Conengmo
username_1
I tested two ways to do this with this example map:

```import folium
m = folium.Map(location=[45.372, -121.6972], zoom_start=12, tiles='Stamen Terrain')
folium.Marker(location=[45.3288, -121.6625], popup='Mt. Hood Meadows').add_to(m)
LayerControl(collapsed=False).add_to(m)
m.save('_map.html') 
```

A dirty way to do it is to replicate the `_render_html_()` method in wrapper class. That way you can do anything with the output of `m.get_root().render()` before putting it in an iframe with a `_render_html_()` function.

```import base64
class MapWrapper:
    def __init__(self, m):
        self.html = m.get_root().render()
    
    def add_html(self, html_string):
        self.html += html_string

    def _repr_html_(self):
        # Copied from folium.element.Figure
        html = "data:text/html;charset=utf-8;base64," + base64.b64encode(self.html.encode('utf8')).decode('utf8')
        iframe = (
        '<div style="width:100%;">'
        '<div style="position:relative;width:100%;height:0;padding-bottom:60%;">'
        '<iframe src="{html}" style="position:absolute;width:100%;height:100%;left:0;top:0;'
        'border:none !important;" '
        'allowfullscreen webkitallowfullscreen mozallowfullscreen>'
        '</iframe>'
        '</div></div>').format
        return iframe(html=html)
    
mapper = MapWrapper(m)
mapper.add_html(('<style>.leaflet-popup-content{color:#FF0000 !important}'
                 '.leaflet-control{color:#00FF00}</style>'))
mapper
```

A probably better way is to make a class that inherits from Branca's `MacroElement` class. You can add this to a map object. Maybe this is something to add to Branca/Folium?

```import branca.element
import jinja2
class Styling(branca.element.MacroElement):
    def __init__(self, style):
        super(Styling, self).__init__()
        self._name = 'styling'
        self.style_statements = style
        self._template = jinja2.Template("""
            {% macro header(this, kwargs) %}
                <style>{{ this.style_statements }}</style>
            {% endmacro %}
            """)

Styling(('.leaflet-popup-content-wrapper{color:#FF0000 !important}'
         '.leaflet-control{color:#00FF00}')).add_to(m)
m
```
comment
created
Conengmo
username_1
I found a much easier way in #370: 
```
style_statement = '<style>.leaflet-control{color:#00FF00}</style>'
m.get_root().html.add_child(folium.Element(style_statement))
m
```
comment
created
fitoprincipe
username_2
I am following along, shouldn't style go in head tag? like

``` python
style_statement = '<style>.leaflet-control{color:#00FF00}</style>'
m.get_root().header.add_child(folium.Element(style_statement))
m
```
comment
created
Alcampopiano
username_0
@username_1 Frank this is fantastic!

The "dirty" way you described allows me to do everything I need. Specifically I am hacking two things:

1) Force a heat map to be on top of a choropleth via:
`<style>.leaflet-heatmap-layer{z-index:300 !important}</style>`

2) Force the layer control checkboxes for my heatmaps to be unchecked by default. To do this I use  some regular expression to remove the ".add_to(map)" that occurs when the heatmap is created. This keeps the checkbox unchecked when the map is loaded:

``` 
html_string = re.sub(r"gradient.*\s*}\).*\s*.*;", 'gradient: {"0.1": "white", "0.5": "black", "1": "white"}})', html_string)
```

I realise that this is heavy handed, but it works. Importantly, when exporting the notebook as HTML, the maps still need to be working when I send the file to someone else. Thanks to your help, this seems to be working consistently in Firefox with maps that are ~3MB in size. In Chrome, the maps only show up if they are very basic (like the test example above). I'm sure there is an explanation for that though, which I will investigate. 

I am using Folium maps to analyze how census data relates to specific schools. I think that is important work, and you have helped to make it possible. 

Thanks again,
Allan
comment
created
Conengmo
username_1
Glad to help Allen. By the way, your second point is something I encountered as well. I made a PR for it (#772) so maybe we'll see it in a next version.

@username_2 you're right, it should be in header. Thanks for the learning.
comment
closed
Alcampopiano
username_0
issue
created
ocefpaf
username_3
```
style_statement = '<style>.leaflet-control{color:#00FF00}</style>'
m.get_root().html.add_child(folium.Element(style_statement))
m
```

Maybe we should document that somewhere...
comment
created
nomadcreator
username_4
Maybe I am asking a quite preliminary question, but how can I show this on a website, such as Django? 
"m" won't show anything when I do.
comment
created
Conengmo
username_1
You mean the entire map? If you render the `Figure` object above your `Map` object you get the full html page. Like this:

```
m = folium.Map()
html_string = m.get_root().render()
```

I once made Flask app that just returns the html, I believe it was something like this.
```
flask.render_template_string(html_string)
```

Alternatively, you can try the `_repr_html_()` method that is used to display maps in Jupyter Notebooks. It outputs html that contains the map in an iframe, so you'd have to include it in your own template. I haven't tried this before.
```
m = folium.Map()
html_string = m._repr_html_()
```
comment
created
nomadcreator
username_4
Thank you. Will try Jupyter Notebooks one.
comment
created
GrazingScientist
username_5
html_string = m.get_root().render()

This did the trick for me, returning the HTML as string. Awesome!
comment