我正在使用Dash Leaflet地图组件dash-leaflet进行交互式地图可视化。
我的目标是根据破折号组件(例如dcc.Slider)的值来过滤大型GeoJSON组件(dl.GeoJSON)。
我目前的方法如下:
import random
import dash
import dash_html_components as html
import dash_leaflet as dl
import dash_leaflet.express as dlx
import dash_core_components as dcc
from dash.dependencies import Input, Output
# Create some markers.
points = [dict(lat=55.5 + random.random(), lon=9.5 + random.random(), value=random.random()*100) for i in range(100)]
data = dlx.dicts_to_geojson(points)
app = dash.Dash()
app.layout = html.Div([
dl.Map([
dl.TileLayer(),
dl.GeoJSON(id="data-id", data=data)
], center=(56, 10), zoom=8, style={'height': '50vh'}),
html.Div([
html.H5('Filtering'),
dcc.Slider(id='my-slider', min=0, max=100, step=1, value=100),
html.Div(id='slider-output-container')
], style={'width': '30%'}),
])
@app.callback(
Output('slider-output-container', 'children'),
Output('data-id', 'data'),
[Input('my-slider', 'value')])
def update_output(value):
points_new = [p for p in points if p['value'] <= value]
data_new = dlx.dicts_to_geojson(points_new)
return 'You have selected value "{}"'.format(value), data_new
if __name__ == '__main__':
app.run_server()在此示例中,使用破折号组件“my- GeoJSON”的值筛选数据组件" data -id“的数据对象,方法是根据输入值筛选点列表并返回使用dlx.dicts_to_geojson函数创建的新geoJSON对象:
points_new = [p for p in points if p['value'] <= value]
data_new = dlx.dicts_to_geojson(points_new)这是过滤geoJSON对象的正确方式吗?
我可以想象,有更好的方法可以使用GeoJSON组件的options-feature和javascript函数在客户端定义这样的过滤器函数,但我不知道如何定义。
我很感谢我能得到的任何建议/代码示例。
发布于 2021-01-12 04:25:35
虽然可以在Python中过滤数据,但根据数据大小的不同,可能会引入大量的网络开销(每次过滤器更改时,数据都会从服务器传输到客户端)。如果你在客户端进行过滤,你只需要传输一次数据,即性能差异可能是巨大的。
客户端过滤可以通过根据the documentation添加具有过滤功能的JavaScript资产(即,放置在assets文件夹中的.js文件)来实现,
window.myNamespace = Object.assign({}, window.myNamespace, {
mySubNamespace: {
filter_features: function(feature, context) {
// code should return true if feature is included, otherwise false
const value = context.props.hideout['value']
...
}
}
});要应用过滤,请将filter函数的函数句柄传递给GeoJSON组件,
import dash_leaflet as dl
from dash_extensions.javascript import Namespace
...
ns = Namespace("myNamespace ", "mySubNamespace")
dl.GeoJSON(id="geojson", options=dict(filter=ns("filter_features"), ...)最后,通过使过滤器依赖于hideout属性(如上面的示例代码所示),您可以通过回调更新此属性来实现交互性。
@app.callback(Output("geojson", "hideout"), ...)
def update(...):
...
return {"value": value}编辑:根据评论中的请求,这里是一个小型的自包含示例,演示了仅使用客户端逻辑的交互式geojson过滤。
import dash_html_components as html
import dash_leaflet as dl
import dash_core_components as dcc
import dash_leaflet.express as dlx
from dash import Dash
from dash.dependencies import Output, Input
from dash_extensions.javascript import assign
# A few cities in Denmark.
cities = [dict(name="Aalborg", lat=57.0268172, lon=9.837735),
dict(name="Aarhus", lat=56.1780842, lon=10.1119354),
dict(name="Copenhagen", lat=55.6712474, lon=12.5237848)]
# Create drop down options.
dd_options = [dict(value=c["name"], label=c["name"]) for c in cities]
dd_defaults = [o["value"] for o in dd_options]
# Generate geojson with a maker for each city and name as tooltip.
geojson = dlx.dicts_to_geojson([{**c, **dict(tooltip=c['name'])} for c in cities])
# Create javascript function that filters on feature name.
geojson_filter = assign("function(feature, context){return context.props.hideout.includes(feature.properties.name);}")
# Create example app.
app = Dash()
app.layout = html.Div([
dl.Map(children=[
dl.TileLayer(),
dl.GeoJSON(data=geojson, options=dict(filter=geojson_filter), hideout=dd_defaults, id="geojson")
], style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"}, id="map"),
dcc.Dropdown(id="dd", value=dd_defaults, options=dd_options, clearable=False, multi=True)
])
# Link drop down to geojson hideout prop (could also be done with a normal callback).
app.clientside_callback("function(x){return x;}", Output("geojson", "hideout"), Input("dd", "value"))
if __name__ == '__main__':
app.run_server()请注意,它需要dash-extensions==0.0.55。
https://stackoverflow.com/questions/65668208
复制相似问题