Dynami c стайлинг линий в листве - PullRequest
3 голосов
/ 18 марта 2020

Я пытался разобраться в плагине 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')

Для меня первое свидание не имеет никакого смысла, но, видимо, оно необходимо, потому что в противном случае браузер ничего не будет рисовать.

Итак:

а) Как изменить стиль, не перерисовывая линии? б) что значит время? Как я могу указать согласованную временную последовательность?

1 Ответ

4 голосов
/ 05 апреля 2020

Сначала я постараюсь ответить на ваши вопросы индивидуально, и в итоге я предлагаю полное решение того, что я буду делать. по существу:

  1. измените переменную TimestampedGeo Json _template, чтобы изменить функцию style_, и она позволит сделать стиль dinami c
  2. , чтобы убедиться, что у вас есть один временной шаг на координаты в TimestampedGeo Json data
  3. Чтобы избежать путаницы, постарайтесь не перекрывать функции или иметь функции, у которых отсутствуют данные за определенный промежуток времени
  4. Я считаю, что в вашем сценарии у вас есть только одна функция, но вы меняете цвета в различные временные шаги

Ответы на ваши вопросы:

a) Как изменить стиль без перерисовки линий?

Не знаю думаю, что это возможно из самого folium, необходимо передать style_function в TimestampedGeo Json, который на данный момент даже не является параметром класса init. Кажется, это трудно сделать, потому что вам нужно было бы перевести python style_function в javascript style_function.

Был бы простой обходной путь. Внутри определения класса класса TimestampedGeo Json она использует переменную _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;
                    },

следующим образом: l oop через массив цветов

                    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) Что означает время? Как указать согласованную временную последовательность?

TimestampedGeo Json использует библиотеку Leaflet.TimeDimension, поэтому TimestampedGeo Json соответствует L.TimeDimension.Layer.Geo JSON .

из этой документации вы получаете

"ordinTimes, times или linestringTimestamps: массив времен, который может быть связан с геометрией (строки даты или мс). В случае для LineString у него должно быть столько же элементов, сколько и координат в LineString."

, поэтому, по сути, для обеспечения согласованности просто убедитесь, что 1. для каждого объекта размер времен совпадает с координатами и 2. используйте допустимые строки даты или формат мс. 3. если ваши даты увеличиваются на постоянную, установите период равным этому значению

, складывая все вместе. Я в основном изменил ваш предыдущий пример: 1) добавил переменную _template с новой функцией style_function и измените TimestampedGeo Json шаблон по умолчанию

2) немного изменили координаты двух объектов, чтобы показать, что два установленные вами функции перекрывались, а некоторые временные шаги и некоторые временные шаги определяли только первую функцию, а позже определяли только вторую функцию, чтобы запутывать то, что происходит на каждом временном шаге.

3) добавили список цвета до l oop для каждой функции

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')
...