問題
Foliumを使って時系列のヒートマップを地図上に描写しようとしたところ、HeatMapWithTimeの結果が全く反映されなくなっていた。foliumのバージョンは0.10.0。
原因
htmlを裏で動かしているLeafletのバージョンが更新され、TimeDimensionに関する部分が変更されたのが原因。
詳しくはfoliumのissuefoliumのissueを参照。
解決策
https://github.com/python-visualization/folium/pull/1228/filesを参考にHeatMapWithTimeのクラスを継承したHeatMapWithTimeFixを作成した。
HeatMapWithFix
from branca.element import CssLink, Element, Figure, JavascriptLink
class HeatMapWithTimeFix(HeatMapWithTime):
def render(self, **kwargs):
super(HeatMapWithTime, self).render(**kwargs)
figure = self.get_root()
assert isinstance(figure, Figure), ('You cannot render this Element '
'if it is not in a Figure.')
figure.header.add_child(
JavascriptLink('https://rawcdn.githack.com/nezasa/iso8601-js-period/master/iso8601.min.js'), # noqa
name='iso8601')
figure.header.add_child(
JavascriptLink('https://rawcdn.githack.com/socib/Leaflet.TimeDimension/master/dist/leaflet.timedimension.min.js'), # noqa
name='leaflet.timedimension.min.js')
figure.header.add_child(
JavascriptLink(
'https://rawcdn.githack.com/python-visualization/folium/master/folium/templates/pa7_hm.min.js'), # noqa
name='heatmap.min.js')
figure.header.add_child(
JavascriptLink('https://rawcdn.githack.com/pa7/heatmap.js/develop/plugins/leaflet-heatmap/leaflet-heatmap.js'), # noqa
name='leaflet-heatmap.js')
figure.header.add_child(
CssLink('http://apps.socib.es/Leaflet.TimeDimension/dist/leaflet.timedimension.control.min.css'), # noqa
name='leaflet.timedimension.control.min.css')
figure.header.add_child(
Element(
"""
<script>
var TDHeatmap = L.TimeDimension.Layer.extend({
initialize: function(data, options) {
var heatmapCfg = {
radius: 15,
maxOpacity: 1.,
scaleRadius: false,
useLocalExtrema: false,
latField: 'lat',
lngField: 'lng',
valueField: 'count',
defaultWeight : 1,
};
heatmapCfg = $.extend({}, heatmapCfg, options.heatmapOptions || {});
var layer = new HeatmapOverlay(heatmapCfg);
L.TimeDimension.Layer.prototype.initialize.call(this, layer, options);
this._currentLoadedTime = 0;
this._currentTimeData = {
data: []
};
this.data= data;
this.defaultWeight = heatmapCfg.defaultWeight || 1;
},
onAdd: function(map) {
L.TimeDimension.Layer.prototype.onAdd.call(this, map);
map.addLayer(this._baseLayer);
if (this._timeDimension) {
this._getDataForTime(this._timeDimension.getCurrentTime());
}
},
_onNewTimeLoading: function(ev) {
this._getDataForTime(ev.time);
return;
},
isReady: function(time) {
return (this._currentLoadedTime == time);
},
_update: function() {
this._baseLayer.setData(this._currentTimeData);
return true;
},
_getDataForTime: function(time) {
delete this._currentTimeData.data;
this._currentTimeData.data = [];
var data = this.data[time-1];
for (var i = 0; i < data.length; i++) {
this._currentTimeData.data.push({
lat: data[i][0],
lng: data[i][1],
count: data[i].length>2 ? data[i][2] : this.defaultWeight
});
}
this._currentLoadedTime = time;
if (this._timeDimension && time == this._timeDimension.getCurrentTime() && !this._timeDimension.isLoading()) {
this._update();
}
this.fire('timeload', {
time: time
});
}
});
L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
initialize: function(index, options) {
var playerOptions = {
buffer: 1,
minBufferReady: -1
};
options.playerOptions = $.extend({}, playerOptions, options.playerOptions || {});
L.Control.TimeDimension.prototype.initialize.call(this, options);
this.index = index;
},
_getDisplayDateFormat: function(date){
return this.index[date.getTime()-1];
}
});
</script>
""", # noqa
template_name='timeControlScript'
)
)