dash-leaflet 通过 hideout [geojson] 进行过滤和样式设置

问题描述 投票:0回答:3

我想通过隐藏属性来filterstyle,就像在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()

我认为当我传回整个隐藏组件时它应该起作用,但事实并非如此。这是错误还是我做错了什么?问题似乎是当我将字典传递给隐藏组件时。

python leaflet geojson plotly-dash
3个回答
0
投票

好吧,我修好了一次!我需要这样退货:

app.clientside_callback(
    """
    function(value, hideout) {
        console.log(hideout);
        return {
            dd_defaults: value
            }
    ;}
    """,
        Output("geojson", "hideout"), Input("dd", "value"), Input("geojson", "hideout"))

0
投票

好的,有完整的工作示例:

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()

0
投票

我正在努力解决同样的问题,正如之前的答案所建议的那样,返回新创建的字典是有效的。

但是,由于我只想更新藏身处的一部分,因此我需要一种动态执行此操作的方法。更新字典并随后复制它,如下对我有用:

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
        }
    }
});

© www.soinside.com 2019 - 2024. All rights reserved.