我使用 python Folium 和 GeoJSON 制作了一个动画时间轴地图。
地图使用线条显示一些人从 A 点旅行到 B 点。这些线条随着时间的推移而显示,并通过将线条和点添加为 GeoJSON 中的特征而制作动画时间线。
虽然这些旅行线路和点随着时间的推移出现在地图上,但我还需要显示一些文本(可能是文本框或一些标题或标签),其中的文本随着时间的推移而变化,例如
*"Events of 2017: blablabla", "Events of 2018: blablabla"*
等。
这些文本框、标签或更改的标题 (??) 将随着时间的推移而出现,而其余元素则沿着时间线出现。即使弹出窗口保持打开状态且可见,无需单击制作者,我也可以接受。
我查看了其他 stackoverflow 问题,但它们只解决了 GeoJSON 弹出窗口,我知道如何创建这些弹出窗口,但它们不是我需要的,除非有一种方法可以让弹出窗口永久显示而无需单击它。
尝试:
DivIcon
在地图上添加一个文本框作为 点标记,以显示 HTML 文本而不是图标,这效果很好,只是它只是一个不会随时间变化的文本,所以它是静态且不更新文本。from folium.features import DivIcon
folium.Marker([47.717414, -20.897951], icon=DivIcon(html=('<textarea style= "font-family:Helvetica, Avenir, Helvetica neue, Sans-serif;font-size:12pt;color:Black; outline:2px black; background-color:transparent;"> Sometext.</textarea>'))).add_to(m)
我尝试在 DivIcon 图标中添加多点标记及其文本,但这只会造成难以辨认的文本重叠。我可以让标记出现在地图的非重叠位置,但这无论如何都会一次显示所有文本,而我需要它们随着时间的推移逐渐出现。
我尝试将文本显示为 GeoJSOn 点功能之一的 popup,但我实现的只是将文本放在地图中某个点的弹出窗口或工具提示中,所以我实际上无法除非我每次“怀疑”可能存在新文本时停止时间线并手动单击或将鼠标悬停在该图标上,否则都会看到它。我没有找到一种方法可以让弹出窗口保持打开状态而无需单击它。
我尝试询问 Chat GPT 和 Google Bard,他们都提出了涉及不存在的代码或不存在的库的解决方案。
有没有办法让某种永久可见的文本随着时间的推移而显示和变化?也许根本不使用 GeoJSON,但是使用一些可以与地图的 HTML 配合使用的 JavaScript 东西?我不是这方面的专家。
这是我用来制作地图的代码中的示例代码:
import folium
from folium import plugins
from folium.plugins import TimestampedGeoJson
#Create map
m = folium.Map(location=[latitude, longitude], zoom_start=4)
# Create points
points=[
{
"times": ["2017-06-02T00:10:00", "2017-06-02T00:40:00"],
"popup": "<h1>Some text 1</h1>",
"coordinates": [10.000654, 53.550341], # Longitude first
},
# more points
]
lines = [
{
"coordinates": [
[28.9662187, 41.0091982], # Longitude first
[10.000654, 53.550341],
],
"times": ["2017-06-02T00:00:00", "2017-06-02T00:10:00"],
},
# more lines
]
# Create "features" list to be filled for GeoJSON
features=[]
# Fill features with points
for point in points:
features.append(
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": point["coordinates"],
},
"properties": {
"times": point["times"],
"popup": point["popup"],
},
}
)
# Fill features with lines
for line in lines:
features.append(
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": line["coordinates"],
},
"properties": {
"times": line["dates"],
"popup": "Some Line Text",
},
}
)
# Create GeoJSON layer and add to map
timestamped_geojson = plugins.TimestampedGeoJson(
{
"type": "FeatureCollection",
"features": features,
},
period="PT1M",
add_last_point=True,
)
timestamped_geojson.add_to(m)
我的英语不太好所以抱歉。
当我在 Pyqt 6 上编写软件时,我遇到了完全相同的问题。我想到的唯一更真实的拐杖是稍微更改 TimestampedGeoJson 中的 _template ,以便将当前日期打印到 javascript 控制台,然后拦截来自控制台的消息。
首先,我创建了一个继承自 TimestampedGeoJson 的 Customtimestamp 类:
class CustomTimestamped(TimestampedGeoJson):
_template = Template(
"""
{% macro script(this, kwargs) %}
L.Control.TimeDimensionCustom = L.Control.TimeDimension.extend({
_getDisplayDateFormat: function(date){
var newdate = new moment(date);
console.log(newdate.format("{{this.date_options}}"))
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) {
return feature.properties.style;
},
onEachFeature: function(feature, layer) {
if (feature.properties.popup) {
layer.bindPopup(feature.properties.popup);
}
if (feature.properties.tooltip) {
layer.bindTooltip(feature.properties.tooltip);
}
}
})
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 %}
"""
)
def __init__(
self,
data,
transition_time=200,
loop=True,
auto_play=True,
add_last_point=True,
period="P1D",
min_speed=0.1,
max_speed=10,
loop_button=False,
date_options="YYYY-MM-DD HH:mm:ss",
time_slider_drag_update=False,
duration=None,
speed_slider=True,
):
super().__init__(data,
transition_time=transition_time,
loop=loop,
auto_play=auto_play,
add_last_point=add_last_point,
period=period,
min_speed=min_speed,
max_speed=max_speed,
loop_button=loop_button,
date_options=date_options,
time_slider_drag_update=time_slider_drag_update,
duration=duration,
speed_slider=speed_slider,
)
在这个课程中,在_template中,我改变了
console.log(newdate.format(this.date_options)
开
console.log(new date.format("{{this.date_options}}"))
现在 TimestampedGeoJson 在动画期间显示的日期格式将被打印到 javascript 控制台
接下来在从
QWebEngineView
继承的基类中,我重新定义了javaScriptConsoleMessage
类的函数QWebEnginePage
,如下所示:
page = QWebEnginePage(self)
page.javaScriptConsoleMessage = lambda _1, message, _2, _3: self.change_params(message)
self.setPage(page)
现在,每次出现动画时刻时,都会调用
self.change_params
函数。它接受来自 javascript 控制台的消息作为参数
在此功能中您可以做您需要的事情。