sim*_*rke 5 python geojson plotly-dash
我正在使用 Dash Leaflet 地图组件dash-leaflet 进行交互式地图可视化。
dl.GeoJSON我的目标是通过破折号组件的值(例如)过滤大型 GeoJSON 组件( ) dcc.Slider。
我目前的方法如下:
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()
Run Code Online (Sandbox Code Playgroud)
在此示例中,GeoJSON 组件“data-id”的数据对象通过根据输入值过滤点列表并返回使用破折号组件“my-slider”的值进行过滤,并返回使用dlx.dicts_to_geojson功能:
points_new = [p for p in points if p['value'] <= value]
data_new = dlx.dicts_to_geojson(points_new)
Run Code Online (Sandbox Code Playgroud)
这是过滤 geoJSON 对象的正确方法吗?
我可以想象,存在更好的方法来使用optionsGeoJSON 组件的 -feature 和 javascript 函数在客户端定义这样的过滤器函数,但我不知道如何。
我很感激我能得到的任何建议/代码示例。
虽然可以在 Python 中过滤数据,但根据数据大小,它可能会引入大量的网络开销(每次过滤器更改时,数据都会从服务器传输到客户端)。如果您在客户端进行过滤,则只需传输数据一次,即性能差异可能会很大。
客户端过滤可以通过添加带有过滤功能的 JavaScript 资产(即放置在资产文件夹中的 .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']
...
}
}
});
Run Code Online (Sandbox Code Playgroud)
要应用过滤,请将过滤函数的函数句柄传递给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"), ...)
Run Code Online (Sandbox Code Playgroud)
最后,通过使过滤器依赖于hideoutprop(如上面的示例代码所示),您可以通过回调更新此 prop 来实现交互性,
@app.callback(Output("geojson", "hideout"), ...)
def update(...):
...
return {"value": value}
Run Code Online (Sandbox Code Playgroud)
编辑:根据评论中的请求,这里是一个小型独立示例,演示仅使用客户端逻辑的交互式 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()
Run Code Online (Sandbox Code Playgroud)
请注意,它需要dash-extensions==0.0.55.