我想通过隐藏属性来filter和style,就像在docs网站上一样,但无法弄清楚。
现在,我被困在这里:
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 marker 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){console.log(context); return context.props.hideout.dd_defaults.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=dict(dd_defaults=dd_defaults, test="test"), id="geojson", zoomToBounds=True)
], 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 be done with a normal callback, but clientside is more performant).
app.clientside_callback(
"""function(value, hideout){
hideout.dd_defaults = value
console.log(hideout);
return hideout
;}
""",
Output("geojson", "hideout"), Input("dd", "value"), Input("geojson", "hideout"))
if __name__ == '__main__':
app.run_server()
我认为当我传回整个隐藏组件时它应该起作用,但事实并非如此。这是错误还是我做错了什么?问题似乎是当我将字典传递给隐藏组件时。
好吧,我修好了一次!我需要这样退货:
app.clientside_callback(
"""
function(value, hideout) {
console.log(hideout);
return {
dd_defaults: value
}
;}
""",
Output("geojson", "hideout"), Input("dd", "value"), Input("geojson", "hideout"))
好的,有完整的工作示例:
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 import Dash
from dash_extensions.javascript import arrow_function, assign
from dash.dependencies import Output, Input
def get_info(feature=None):
header = [html.H4("US Population Density")]
if not feature:
return header + [html.P("Hoover over a state")]
return header + [html.B(feature["properties"]["name"]), html.Br(),
"{:.3f} people / mi".format(feature["properties"]["density"]), html.Sup("2")]
classes = [0, 10, 20, 50, 100, 200, 500, 1000]
colorscale = ['#FFEDA0', '#FED976', '#FEB24C', '#FD8D3C', '#FC4E2A', '#E31A1C', '#BD0026', '#800026']
style = dict(weight=2, opacity=1, color='white', dashArray='3', fillOpacity=0.7)
# Create colorbar.
ctg = ["{}+".format(cls, classes[i + 1]) for i, cls in enumerate(classes[:-1])] + ["{}+".format(classes[-1])]
colorbar = dlx.categorical_colorbar(categories=ctg, colorscale=colorscale, width=300, height=30, position="bottomleft")
# Geojson rendering logic, must be JavaScript as it is executed in clientside.
style_handle = assign("""function(feature, context){
const {classes, colorscale, style, colorProp} = context.props.hideout; // get props from hideout
const value = feature.properties[colorProp]; // get value the determines the color
for (let i = 0; i < classes.length; ++i) {
if (value > classes[i]) {
style.fillColor = colorscale[i]; // set the fill color according to the class
}
}
return style;
}""")
filter_handle = assign("function(feature, context){console.log(context);return context.props.hideout.name.includes(feature.properties.name);}")
dd_options = [{"value": "Alabama", "label": "Alabama"}, {"value": "Arkansas", "label": "Arkansas"}, {"value": "Florida", "label": "Florida"}]
dd_defaults = ["Alabama", "Arkansas", "Florida"]
# Create geojson.
geojson = dl.GeoJSON(url="/assets/us-states.json", # url to geojson file
options=dict(style=style_handle,filter=filter_handle), # how to style each polygon
zoomToBounds=True, # when true, zooms to bounds when data changes (e.g. on load)
zoomToBoundsOnClick=True, # when true, zooms to bounds of feature (e.g. polygon) on click
hoverStyle=arrow_function(dict(weight=5, color='#666', dashArray='')), # style applied on hover
hideout=dict(colorscale=colorscale, classes=classes, style=style, colorProp="density", name=dd_defaults),
id="geojson")
# Create info control.
info = html.Div(children=get_info(), id="info", className="info",
style={"position": "absolute", "top": "10px", "right": "10px", "z-index": "1000"})
# Create app.
app = Dash(prevent_initial_callbacks=True)
app.layout = html.Div([
dl.Map([dl.TileLayer(), geojson, colorbar, info], style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"}, id="map"
),
html.Div([
dcc.Dropdown(id="dd", value=dd_defaults, options=dd_options, clearable=False, multi=True)
])
])
@app.callback(Output("info", "children"), [Input("geojson", "hover_feature")])
def info_hover(feature):
return get_info(feature)
app.clientside_callback("""
function(x, y){
return {
classes: y.classes,
name: x,
colorProp: y.colorProp,
colorscale: y.colorscale,
style: y.style
};}
""",
Output("geojson", "hideout"), [Input("dd", "value"), Input("geojson", "hideout")]),
if __name__ == '__main__':
app.run_server()
我正在努力解决同样的问题,正如之前的答案所建议的那样,返回新创建的字典是有效的。
但是,由于我只想更新藏身处的一部分,因此我需要一种动态执行此操作的方法。更新字典并随后复制它,如下对我有用:
window.dash_clientside = Object.assign({}, window.dash_clientside, {
clientside: {
update_filter: function (new_value, current_hideout) {
current_hideout['certain_filter'] = new_value
return Object.fromEntries(Object.entries(current_hideout).map(([key, value]) => [key, value])) // return a copy of the current_hideout object, otherwise it does not work
}
}
});