folium
folium copied to clipboard
Generated HTML could be much smaller
The HTML generated by folium is quite verbose which leads to big files when you have 2000 markers for example.
- The javascript is not separate from the HTML which makes it harder to minimise. Running the javascript through the closure compiler reduced it to about 70% of the original size.
- Variables names are very long which adds a significant length to the generated file.
I'm sure there are more savings but these two seemed like the most obvious.
You're right that the generated HTML/JS could be more efficient. Right now it is necessary for everything to render into one HTML file, so they can be embedded in Jupyter notebooks.
- Interesting idea to compile/minimize the JavaScript before embedding. Would this be possible while still embedding it?
- Names could indeed be shorter. Though they have to be long enough to guarantee unique names, so I don't know how much can be saved here.
Consider this generated code, which adds a circle with a popup to a layer:
var circle_f4cd3b21ebb84d1897bee067cc1de213 = L.circle(
[49.87654, 12.34567],
{
"bubblingMouseEvents": true,
"color": "#0033ff",
"dashArray": null,
"dashOffset": null,
"fill": true,
"fillColor": "#0033ff",
"fillOpacity": 0.2,
"fillRule": "evenodd",
"lineCap": "round",
"lineJoin": "round",
"opacity": 1.0,
"radius": 1234.0,
"stroke": true,
"weight": 3
}
)
.addTo(feature_group_bdeeee916f2b4309b25004b362ad675b);
var popup_f103219425994b68951c51e0e03459e9 = L.popup({maxWidth: '300'
});
var html_912b7a603e5b4194bca0d327f238d88e = $('<div id="html_912b7a603e5b4194bca0d327f238d88e"
style="width: 100.0%; height: 100.0%;">
t=0: 2029-12-15 09:35:28: id 12345678</div>')[0];
popup_f103219425994b68951c51e0e03459e9.setContent(
html_912b7a603e5b4194bca0d327f238d88e);
circle_f4cd3b21ebb84d1897bee067cc1de213.bindPopup(
popup_f103219425994b68951c51e0e03459e9)
;
So i have two questions:
-
Do we really need to generate the values of all styling parameters of Leaflet's Path class, or we could simply omit them and Leaflet will use default values mentioned here ?
-
Could you give an example of a use case where we need to access/modify popups and their html? In other words, where do we access html_....... , popup_........... variables?
I think there definetely should be a reason we do all this, instead of simply chaining Leaflet instructions like this, for example (this code displays exactly the same circle and popup):
L.circle([49.87654, 12.34567], {'radius': 1234.0, 'color': '#0033ff'}).bindPopup("t=0: 2029-12-15 09:35:28: id 12345678").addTo(feature_group_bdeeee916f2b4309b25004b362ad675b)
Thanks.
I've been looking around to find something to contribute, and this seemed like an interesting issue (and something I definitely thought of before when using Folium!)
- Compressing JS before embedding is possible, and I think this would have to be done in Branca. The template interpolation process is somewhat complicated, so I might have overlooked something, but it seems that HTML and JS are glued outside of Folium.
- Ostensibly names can be unique without including UUIDs: for example, names in the form
marker_0
,marker_1
,marker_2
, etc., where the class keeps an ID, incremented on every object instantiation. Thread safety is an obvious question here.
I can confirm ~30% size reduction from minifying JS alone (I used slimit.minify
).
@Norrius that sounds like a good plan. There are many whitespaces to trim too.
@ocefpaf @Norrius what about default values of styling parameters (cf. my question just above), omitting them could reduce the size by 50% or something (rough estimation), right?
I think @DenisFLASH is right about the default parameters but I wonder if a good minimiser will eliminate the common expressions anyway?
Generating shorter code in the first place (@DenisFLASH) will of course help a lot, but I don't know enough about Leaflet.js to do it and having compressed JS should be beneficial in any case. I tried out a couple of available minifiers:
- slimit (MIT license) initially looked very promising, but it panics on the following code from examples, on the $(` combination:
var html_abc = $(`<div id="html_abc" style="width: 100.0%; height: 100.0%;"><i>Mt. Hood Meadows</i></div>`)[0];
popup_def.setContent(html_abc);
It also has a mangler, which (in theory) could have helped with long names as well (it renames things into a, b, c, ... Y, Z, ab, ac, ...
), but in practice simply breaks the code.
- jsmin (MIT license) claims not to support ES6, but works fine on what I tested, and I think backticks are a part of ES6?
- rJSmin (Apache License 2.0) appears to be based on the same original project as jsmin and produces very similar (often identical) results. It is however much faster.
All of these only apply simple transformations such as removing whitespace, so no clever replacements (as suggested by @mpickering).
I also want to check if django-compressor would work here. Unlike the rest, it is not a drop-in compressor function, so it needs some more investigation.
Hi @Norrius, thanks for taking on this project! Having smaller htmls is a good goal so I’ll be happy to review any PRs related to this.
As I see it there are three things we need to decide on:
- which minifier/ compressor to use
- where to hook it in
- how to expose the option to users
Other ideas in this thread are interesting as well, thanks for bringing them up @denisFLASH. But as @mpickering said a good JS processor might already solve some of these.
I’ll list the other ideas here, so someone can open another issue or PR for them if still relevant after the JS compression project.
- using Leaflet defaults instead of explicitly defining them in folium
- reusing object options for multiple similar objects
- shorter variable names
While we're on the topic, I was expecting that the save
method wouldn't pull the geoJSON files and embed them inside the HTML files if they could just be used as a reference? Or would this break too many things?
@mpickering is this issue resolved?