python-visualization / folium

Python Data. Leaflet.js Maps.
https://python-visualization.github.io/folium/
MIT License
6.92k stars 2.23k forks source link

Maps with complex polygon layers not rendering in Jupyter Lab/Notebook #812

Closed EMarcantonio closed 4 years ago

EMarcantonio commented 6 years ago

Please add a code sample or a nbviewer link, copy-pastable if possible

# Your code here

Problem description

I have been trying to run your sample notebook in examples/Geopandas.ipnyb in both Jupyter Lab and Jupyter Notebook. When I execute the cells, they all execute with no error but no map is rendered. I have had a similar problem in my own notebooks that seems to occur when the polygons are complex and have a lot of data points. I can get it to render simple polygons and so it doesn't seem to be a library problem. Can you confirm this example still works with the latest release?

Versions below: notebook: 5.2.2 Jupyter Lab: 0.30 (note I upgraded to 0.31 but was having issues getting Lab to load) python: 3.6 Folium: 0.5.0

Expected Output

Rendered map in the examples/Geopandas.ipnyb

Output of folium.__version__

0.5.0

mgoldwasser commented 6 years ago

@EMarcantonio does this work on Firefox?

tayloraune commented 6 years ago

I have also seen this (or a very similar) problem. Maps will render correctly in jupyter with Firefox and with Safari, but not with Chrome. These were larger maps I was trying to display. I have not tested with smaller maps. Chrome (and firefox and safari) will open the html just fine if opened directly.

mgoldwasser commented 6 years ago

When I simplify the geometry in examples/Geopandas.ipynb it works in chrome:

import geopandas

nybb = os.path.join('data', 'nybb.shp')
boros = geopandas.GeoDataFrame.from_file(nybb)
boros['geometry'] = boros['geometry'].simplify(500, preserve_topology=False)
robroc commented 6 years ago

I'm having the same problem. Adding about 500 circle markers to a folium map. Nothing renders in JupyterLab using Chrome. Saving as HTML file, the map also does not appear when opened in Chrome or IE 11.

jasongrout commented 6 years ago

(reposting here for visibility from https://github.com/jupyterlab/jupyterlab/issues/3991)

For rendering in JupyterLab: As far as I can tell, looking at the folium code, folium needs to have a jupyterlab extension to expose itself as a renderer in the system. See the extension developer guide - likely folium will want to provide a rendermime extension.

For example, here's a geojson jupyterlab plugin to render geojson data using leaflet: https://github.com/jupyterlab/jupyter-renderers/tree/master/packages/geojson-extension

s-cork commented 6 years ago

i experienced this problem today - the following maps for london boroughs will not display in chrome but will display in firefox or safari: http://nbviewer.jupyter.org/github/s-cork/OCR_LDS/blob/master/LondonMaps.ipynb

I found that if I reduced the number of London boroughs to 23 boroughs rather than 33 it would display fine in chrome.

Conengmo commented 6 years ago

If someone wants to look into better integration of folium's output with Jupyter, that would be welcome!

GregHilston commented 6 years ago

I'm having this exact problem when displaying a lot of data, using a layer. Works in every browser but Chrome.

Something to note, this doesn't seem to be strictly a Jupyter Notebook situation, as the hex iFrame doesn't load in Chrome in just a regular webpage, independent form Jupyter Notebook.

ColinTalbert commented 6 years ago

I'm getting this issue as well. Also I've found that when I save the map out to an html file, I can open the html file in Chrome and view it with no issues. Perhaps some setting in Jupyter?

ocefpaf commented 6 years ago

There are two separated issues here:

The former is not in our roadmap! People can try ipyleaflet or, if that works, saving the folium HTML and seeing if JupyterLab can load it. The reason is b/c folium devs have no bandwidth to write a JupyterLab extension (and that was quite te moving target in the past which drove me away from it).

For the latter there is a workaround:

def embed_map(m):
    from IPython.display import IFrame

    m.save('index.html')
    return IFrame('index.html', width='100%', height='750px')

I don't know the details of why everything works in all the browsers I tested but Chrome so I'm closing this as "won't fix." (PRs are still welcome though :wink:)

Geradav commented 5 years ago

I have the same issue trying to load a folium choropleth map with a GeoJSON dataset as a layer using Visual Studio Code. The result shows an empty map frame and no error message. The GeoJSON has more than 100 districts featured as polygon shapes.

image

Same scenario as for the others, saving the map as HTML and opening it in a browser displays the map correctly. image

Using Visual Studio Code version 1.38.1 Python extension for VSCode 2019.9.34911 Python 3.7.4 64bit folium 0.10.0

It's difficult continuing to work in the dark in VSCode

AnneEstoppey commented 5 years ago

Hello, I am also experiencing the same issue. My map shows exploration wells on the Norwegian shelf (offshore), I am using folium in my notebook. I am using Jupyter Lab.

It works fine with showing my wells which are points, but as soon as I add polygons (production licences), the map turns blank. This is when I use Chrome.

When I use Jupyter Lab from Firefox or Safari, the map displays properly, with the polygons, see below:

folium_with_polygons

r-or commented 5 years ago

https://github.com/python-visualization/folium/issues/812#issuecomment-437483792 ^ This workaround doesn't work if using colab. The IFrame just shows "localhost refused to connect." I assume it's some issue with cross origin content?

dstein64 commented 5 years ago

Chrome has a 2MB data URI limit.

I believe this issue may be from surpassing 2MB in a data URI in an iframe.

For example, in the link that @s-cork posted above, the Jupyter notebook embeds the first map in an <iframe> element. The data URI, data:text/html;charset=utf-8;base64,PCFET0NUW..., is 2.7MB.

A possibility for reducing the likelihood of this issue is to have folium generate minified html/javascript. That would result in a shorter length of the corresponding data URI.

This explains why the maps don't work in Jupyter (where they're encoded in data URIs), but work fine when loaded as html files directly into Chrome (outside the context of Jupyter).

Conengmo commented 5 years ago

Interesting find @dstein64, thanks for sharing!

We have another ticket on minifying html/js: https://github.com/python-visualization/folium/issues/975#issuecomment-451550054

Given this issue we could consider applying a minifyer in Jupyter context.

But it would be better IMO, more robust, to circumvent this limit entirely. Possibly in addition to minifying. In the Stackoverflow post you link to they mention some alternatives, such as saving data to disk or using some blob URL thing (I haven't thorougly read it).

Help is welcome to work on this.

dstein64 commented 5 years ago

But it would be better IMO, more robust, to circumvent this limit entirely.

I agree, although that would seemingly have to be done by Jupyter, as that software presumably creates the iframe and converts folium's HTML to a data URI.

Conengmo commented 5 years ago

That's actually done in branca, which the base library folium extends on. We can make changes or customise if needed. You can see the code here: https://github.com/python-visualization/branca/blob/master/branca/element.py#L324

dstein64 commented 5 years ago

I've implemented a workaround in https://github.com/python-visualization/branca/pull/66.

Conengmo commented 5 years ago

Thanks for your work on this @dstein64! I'll review your PR.

dstein64 commented 4 years ago

In the meantime, others encountering this issue can workaround the problem by using the following monkey patch, which works for folium==0.10.0 and branca==0.3.1. This code would have to be executed before using folium (e.g., in an early cell of a Jupyter notebook).

import base64

import folium

def _repr_html_(self, **kwargs):
    html = base64.b64encode(self.render(**kwargs).encode('utf8')).decode('utf8')
    onload = (
        'this.contentDocument.open();'
        'this.contentDocument.write(atob(this.getAttribute(\'data-html\')));'
        'this.contentDocument.close();'
    )
    if self.height is None:
        iframe = (
            '<div style="width:{width};">'
            '<div style="position:relative;width:100%;height:0;padding-bottom:{ratio};">'
            '<iframe src="about:blank" style="position:absolute;width:100%;height:100%;left:0;top:0;'
            'border:none !important;" '
            'data-html={html} onload="{onload}" '
            'allowfullscreen webkitallowfullscreen mozallowfullscreen>'
            '</iframe>'
            '</div></div>').format
        iframe = iframe(html=html, onload=onload, width=self.width, ratio=self.ratio)
    else:
        iframe = ('<iframe src="about:blank" width="{width}" height="{height}"'
                  'style="border:none !important;" '
                  'data-html={html} onload="{onload}" '
                  '"allowfullscreen" "webkitallowfullscreen" "mozallowfullscreen">'
                  '</iframe>').format
        iframe = iframe(html=html, onload=onload, width=self.width, height=self.height)
    return iframe

folium.branca.element.Figure._repr_html_ = _repr_html_
jwhendy commented 4 years ago

Confirming that the monkey patch above resolves the issue I ran into in #1244 (a duplicate, as I didn't see this issue). Previously my limit was 3167 points and I just ran a test with 5k and 15k points with no problems. Thanks, @dstein64 !

Conengmo commented 4 years ago

Thanks for confirming @jwhendy. Next thing I'll do is review that PR.

nagarajbhat commented 4 years ago

Thanks for providing the monkey patch code @dstein64 . My code had some large maps which did not render in chrome before. Will this be added to folium?

dstein64 commented 4 years ago

@nagarajbhat, I don't know the schedule, but the update has been merged into branca in branca PR #66.

Given that folium specifies branca>=0.3.0 as a dependency, once an updated branca is released, this fix should be available in folium (after e.g., upgrading folium's branca dependency).

Conengmo commented 4 years ago

@nagarajbhat could you install branca from the git master branch and test if you can now render your notebooks without problems?

nagarajbhat commented 4 years ago

@Conengmo I used the branca from git master branch (updates in branca/element.py included). It works fine in chrome - local.

python version - '3.7.4' folium - '0.10.1' branca - '0.3.1+26.gf0dfe2e'

But I want to use it in kaggle, not sure how to integrate that (since branca has not been updated in pip yet).

@dstein64 I am using folium.plugins.HeatMapWithTime() in the map. And used the monkey patch code in kaggle , And the play/slider button layer collapsed(even the icons are not visible) whenever I used the monkey patch code

python - '3.6.6' folium - '0.10.1' branca - '0.3.1'

Here's how it responded to different environments in kaggle -

Check the screenshots below

dstein64 commented 4 years ago

@nagarajbhat, I was unable to replicate the HeatMapWithTime issue locally using this example here: https://github.com/python-visualization/folium/blob/master/examples/HeatMapWithTime.ipynb

I tried on Chrome and Firefox with both the monkey patch and also by installing the updated branca with:

pip install git+https://github.com/python-visualization/branca

Do you only encounter the problem in Kaggle, or also when running locally?

Can you provide example code that exhibits the problem?

nagarajbhat commented 4 years ago

@dstein64 Thanks for the git install code. Just a clarification . It works fine locally (both in chrome and firefox) .And both by installing from github and monkey patch.

But I am not able to get it to work in Kaggle (chrome). You can use the same example, but increase the data points from 100 to around 500.

You can copy the kernel and try it out here in kaggle - https://www.kaggle.com/nagarajbhat/test-folium-heatmapwithtime

dstein64 commented 4 years ago

@nagarajbhat, thanks for the link.

I've replicated the issue you've encountered. I had to move the following line earlier in the notebook (prior to importing folium) in order to use the updated version of branca:

!pip install git+https://github.com/python-visualization/branca

After making this change, restarting the session, then running the notebook, I see that the branca version printed is 0.3.1+26.gf0dfe2e.

I saw the problematic play button and slider in Chrome, and not Firefox.

After I revert the updated branca version by removing the pip install statement, restarting the session, then running the notebook, I see that the branca version printed is 0.3.1.

With this reverted version, the map won't display, but if I reduce the amount of data by changing 500 to 10:

data = [(initial_data + move_data * i).tolist() for i in range(10)]

... the map displays.

However, I am encountering the same issue with the play button and slider, even when using the older version of branca without updating nor patching.

Can you confirm whether you are also encountering the issue in Kaggle with a reduced data size and the existing version of branca (without updating nor patching)? If so, that suggests that the issue is separate (i.e., not related to the update recently merged into branca).

nagarajbhat commented 4 years ago

@dstein64 I have followed the steps above and can confirm I got the same results. So yes, it does suggest the issue is unrelated to the recent branca update.

However I would appriciate any solution to layer issue - HeatMapWithTime in chrome (for kaggle). Here's another kaggle user facing the same issue - https://www.kaggle.com/grebublin/air-pollution-in-tamil-nadu-india-starter

You can see that TimestampedGeoJson is working fine , but HeatMapWithTime is not (in chrome).

dstein64 commented 4 years ago

@nagarajbhat, it looks like a pull request was opened about 4 hours ago that seemingly addresses the issue you're encountering: https://github.com/python-visualization/folium/pull/1256

nagarajbhat commented 4 years ago

@dstein64 Cool ,does it resolve the issue?

Also a correction to my previous statement, I increased the data points to 1000 and tested in firefox - kaggle . And without branca update the slider layer worked fine (although without branca update nothing is displayed in chrome)

But with the branca update the slider layer collapses (both firefox and chrome -kaggle). Could you try it out? https://www.kaggle.com/nagarajbhat/test-folium-heatmapwithtime

dstein64 commented 4 years ago

Cool ,does it resolve the issue?

I confirmed that it resolves the issue, by using the following line in the notebook to install folium from the branch of the PR (this line has to precede import folium and the notebook has to be restarted).

!pip install git+https://github.com/sknzl/folium@update-css-url-to-https

Could you try it out?

I tried using the patched branca combined with the patched folium, and everything worked as expected.

!pip install git+https://github.com/python-visualization/branca
!pip install git+https://github.com/sknzl/folium@update-css-url-to-https
nagarajbhat commented 4 years ago

@dstein64 Thanks a lot! Was Finally able to put out my code in kaggle - Australian bushfire - map analysis.

jmaralcZ commented 4 years ago

In the meantime, others encountering this issue can workaround the problem by using the following monkey patch, which works for folium==0.10.0 and branca==0.3.1. This code would have to be executed before using folium (e.g., in an early cell of a Jupyter notebook).

import base64

import folium

def _repr_html_(self, **kwargs):
    html = base64.b64encode(self.render(**kwargs).encode('utf8')).decode('utf8')
    onload = (
        'this.contentDocument.open();'
        'this.contentDocument.write(atob(this.getAttribute(\'data-html\')));'
        'this.contentDocument.close();'
    )
    if self.height is None:
        iframe = (
            '<div style="width:{width};">'
            '<div style="position:relative;width:100%;height:0;padding-bottom:{ratio};">'
            '<iframe src="about:blank" style="position:absolute;width:100%;height:100%;left:0;top:0;'
            'border:none !important;" '
            'data-html={html} onload="{onload}" '
            'allowfullscreen webkitallowfullscreen mozallowfullscreen>'
            '</iframe>'
            '</div></div>').format
        iframe = iframe(html=html, onload=onload, width=self.width, ratio=self.ratio)
    else:
        iframe = ('<iframe src="about:blank" width="{width}" height="{height}"'
                  'style="border:none !important;" '
                  'data-html={html} onload="{onload}" '
                  '"allowfullscreen" "webkitallowfullscreen" "mozallowfullscreen">'
                  '</iframe>').format
        iframe = iframe(html=html, onload=onload, width=self.width, height=self.height)
    return iframe

folium.branca.element.Figure._repr_html_ = _repr_html_

@dstein64 Thanks a lot for the work around. I would like to understand the fix but I do not get it completely. How is the fix reducing the length of html? is by using atob? Thanks again.

Conengmo commented 4 years ago

@jmaralcZ the work around has been applied in branca, so you can install from the master branch to use it.

pip install git+https://github.com/python-visualization/branca

jmaralcZ commented 4 years ago

@jmaralcZ the work around has been applied in branca, so you can install from the master branch to use it.

pip install git+https://github.com/python-visualization/branca

@Conengmo Thanks, I just want to understand the solution....It is just I do not see how that short the html URI...I know this is not critical, but for me understanding could bring opportunities in the future to solve issues myself and collaborate :)

Conengmo commented 4 years ago

That's okay, always good to learn from other peoples code :) But apart from understanding, can you let us know if this indeed solved your issue?

Conengmo commented 4 years ago

We just released branca 0.4.0 which includes @dstein64's change 🚀 so issues with folium in Chrome can now be solved by upgrading the version of branca: pip install branca --upgrade

dstein64 commented 4 years ago

@jmaralcZ, in Chrome there is a 2MB limit on URI length for the current document. "current document" refers to pages with URLs entered directly in the URL bar or accessed through iframes. This limit does not apply to page resources, like images, which do permit URIs larger than 2MB (as long as they're not viewed directly as a "current document").

The branca workaround avoids using a data URI for a current document (the iframe), which prevents this issue. Rather than constructing an iframe using a data URI for its src, the iframe is constructed by retaining its base64-encoded html data in an attribute called data-html, and using JavaScript to inject this html data into the iframe, avoiding the 2MB limit.

Conengmo commented 4 years ago

Since this issue got resolved I'm closing it.