【问题标题】:Dynamic styling of lines in foliumfolium中线条的动态样式
【发布时间】:2020-06-29 16:27:57
【问题描述】:

我一直在尝试理解来自 folium 的 TimestampedGeoJson 插件。

我想绘制随时间改变颜色的线条。目前,我所做的就是在每次需要更改颜色时完全重新绘制一条线,这会带来巨大的开销。

另一个问题是如何在特征中指定时间。目前,我有这个例子:

import folium
from folium.plugins import TimestampedGeoJson

m = folium.Map(
    location=[42.80491692, -4.62577249],
    zoom_start=10
)

data = [
{
    'coordinates': [
        [-4.018876661, 43.11843382],
        [-4.856537491, 42.82202193],
    ],
    'dates': [
        '2017-06-02T00:00:00',
        '2017-06-02T00:10:00'
    ],
    'color': 'red'
},
{
    'coordinates': [
        [-4.018876661, 43.11843382],
        [-4.856537491, 42.82202193],
    ],
    'dates': [
        '2017-06-02T00:00:00',
        '2017-06-02T00:20:00'
    ],
    'color': 'blue'
},
]

features = [
    {
        'type': 'Feature',
        'geometry': {
            'type': 'LineString',
            'coordinates': d['coordinates'],
        },
        'properties': {
            'times': d['dates'],
            'style': {
                'color': d['color'],
                'weight': d['weight'] if 'weight' in d else 5
            }
        }
    }
    for d in data
]

TimestampedGeoJson({
    'type': 'FeatureCollection',
    'features': features,
}, period='PT1M', add_last_point=True).add_to(m)

m.save('dynamic4.html')

对我来说,第一次约会没有任何意义,但显然它是必需的,否则浏览器将不会绘制任何东西。

所以:

a) 如何在不重绘线条的情况下更改样式? b) 时间是什么意思?如何指定一致的时间顺序?

【问题讨论】:

    标签: python leaflet folium


    【解决方案1】:

    我将首先尝试单独解决您的问题,然后我将给出我最终将要做什么的完整解决方案。本质上:

    1. 更改 TimestampedGeoJson _template 变量以更改 style_function 并使其能够使样式动态化
    2. 确保 TimestampedGeoJson 数据中的每个坐标都有一个时间步长
    3. 为避免混淆,请尽量不要重叠特征或在特定时间步长内使特征缺失数据
    4. 我相信在您的场景中,您只有一个功能,但会在不同的时间步长改变颜色

    解决您的问题:

    a) 如何在不重绘线条的情况下更改样式?

    我认为 folium 本身不可能,因此有必要将 style_function 传递给 TimestampedGeoJson,目前它甚至不是类 init 的参数。这似乎很难做到,因为您需要将 python style_function 转换为 javascript style_function。

    会有一个简单的解决方法。在 class definition of TimestampedGeoJson 内部,它使用 _template 变量作为 javascript 代码的字符串模板,因此您可以根据需要调整此模板,但使用 javascript。

    class TimestampedGeoJson(MacroElement):
             .... hidding lines to save space
        _template = Template("""
            {% macro script(this, kwargs) %}
                     .... hidding lines to save space
                        style: function (feature) {
                            return feature.properties.style;
                        },
                        onEachFeature: function(feature, layer) {
                            if (feature.properties.popup) {
                            layer.bindPopup(feature.properties.popup);
                            }
                        }
                    })
            {% endmacro %}
            """)  # noqa
         ..... hidding lines to save space
    

    因此,要在每个时间步更改线条颜色,您可以更改模板的这一部分:

    style: function (feature) {
                            return feature.properties.style;
                        },
    

    通过这个:循环遍历颜色数组

                        style: function(feature) {
                            lastIdx=feature.properties.colors.length-1
                            currIdx=feature.properties.colors.indexOf(feature.properties.color);
                            if(currIdx==lastIdx){
                                feature.properties.color = feature.properties.colors[0]  
                            }
                            else{
                                feature.properties.color =feature.properties.colors[currIdx+1] 
                            }
                            return {color: feature.properties.color}
                        },
    
    

    更改它,以便您在每个时间步更新 properties.style 中的颜色。

    b) 时间是什么意思?如何指定一致的时间顺序?

    TimestampedGeoJson 使用的是Leaflet.TimeDimension 库,所以TimestampedGeoJson 对应L.TimeDimension.Layer.GeoJSON

    从你得到的文档中

    "coordTimes、times 或 linestringTimestamps:可与几何图形关联的时间数组(日期字符串或毫秒)。对于 LineString,它必须具有与 LineString 中的坐标一样多的项目。强>”

    所以本质上要保持一致,只要确保 1. 对于每个特征,时间大小与坐标相同,并且 2. 使用有效的日期字符串或毫秒格式 3. 如果您的日期增加了一个常数,请将您的期间设置为该值

    综上所述,我主要在您之前的示例中进行了更改: 1) 使用新的 style_function 添加了一个 _template 变量并更改 TimestampedGeoJson 默认模板

    2) 稍微更改了两个特征坐标,以显示您设置的两个特征是重叠的,并且在某些时间步长上,在某些时间步长上只定义了第一个特征,后来只定义了第二个特征,所以发生了什么令人困惑在每个时间步。

    3) 为每个功能添加了一个循环颜色列表

    from jinja2 import Template
    _template = Template("""
        {% macro script(this, kwargs) %}
            L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
                _getDisplayDateFormat: function(date){
                    var newdate = new moment(date);
                    console.log(newdate)
                    return newdate.format("{{this.date_options}}");
                }
            });
            {{this._parent.get_name()}}.timeDimension = L.timeDimension(
                {
                    period: {{ this.period|tojson }},
                }
            );
            var timeDimensionControl = new L.Control.TimeDimensionCustom(
                {{ this.options|tojson }}
            );
            {{this._parent.get_name()}}.addControl(this.timeDimensionControl);
            var geoJsonLayer = L.geoJson({{this.data}}, {
                    pointToLayer: function (feature, latLng) {
                        if (feature.properties.icon == 'marker') {
                            if(feature.properties.iconstyle){
                                return new L.Marker(latLng, {
                                    icon: L.icon(feature.properties.iconstyle)});
                            }
                            //else
                            return new L.Marker(latLng);
                        }
                        if (feature.properties.icon == 'circle') {
                            if (feature.properties.iconstyle) {
                                return new L.circleMarker(latLng, feature.properties.iconstyle)
                                };
                            //else
                            return new L.circleMarker(latLng);
                        }
                        //else
                        return new L.Marker(latLng);
                    },
                    style: function(feature) {
                        lastIdx=feature.properties.colors.length-1
                        currIdx=feature.properties.colors.indexOf(feature.properties.color);
                        if(currIdx==lastIdx){
                            feature.properties.color = feature.properties.colors[currIdx+1] 
                        }
                        else{
                            feature.properties.color =feature.properties.colors[currIdx+1] 
                        }
                        return {color: feature.properties.color}
                    },
                    onEachFeature: function(feature, layer) {
                        if (feature.properties.popup) {
                        layer.bindPopup(feature.properties.popup);
                        }
                    }
                })
            var {{this.get_name()}} = L.timeDimension.layer.geoJson(
                geoJsonLayer,
                {
                    updateTimeDimension: true,
                    addlastPoint: {{ this.add_last_point|tojson }},
                    duration: {{ this.duration }},
                }
            ).addTo({{this._parent.get_name()}});
        {% endmacro %}
        """)
    import folium
    from folium.plugins import TimestampedGeoJson
    
    m = folium.Map(
        location=[42.80491692, -4.62577249],
        zoom_start=9
    )
    
    data = [
    {
        'coordinates': [
            [-4.018876661, 43.11843382],
            [-4.856537491, 42.82202193],
        ],
        'dates': [
            '2017-06-02T00:00:00',
            '2017-06-02T00:10:00'
        ],
        'color': 'brown',
        'colors':["black","orange","pink"],
    },
    {
        'coordinates': [
            [-4.058876661, 43.11843382],
            [-4.936537491, 42.82202193],
        ],
        'dates': [
            '2017-06-02T00:00:00',
            '2017-06-02T00:10:00'
        ],
        'color': 'blue',
        'colors':["red","yellow","green"],
    },
    ]
    
    features = [
        {
            'type': 'Feature',
            'geometry': {
                'type': 'LineString',
                'coordinates': d['coordinates'],
            },
            'properties': {
                'times': d['dates'],
                'color': d["color"],
                'colors':d["colors"]
            }
        }
        for d in data
    ]
    
    t=TimestampedGeoJson({
        'type': 'FeatureCollection',
        'features': features,
    }, period='PT10H', add_last_point=True)
    t._template=_template
    t.add_to(m)
    
    m.save('original.html')
    

    【讨论】:

      猜你喜欢
      • 2011-07-07
      • 2013-05-07
      • 2020-07-17
      • 1970-01-01
      • 1970-01-01
      • 2020-08-14
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      相关资源
      最近更新 更多