1

I am adding a Dash-Leaflet map to a callback and want to know how to setup up the app layout. Below are the modules and datasets used.

import dash
import plotly.express as px
from dash import Dash, dcc, html, Input, Output, State, dash_table
from dash.exceptions import PreventUpdate
import plotly.graph_objs as go
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from jupyter_dash import JupyterDash
import dash_bootstrap_components as dbc

import dash_leaflet as dl
import dash_leaflet.express as dlx
import geopandas as gpd
import json


df = df[["Analysis","LGA", "SMA","AVLU", "Address","Locality", "AREA(HA)","Sale Date"]]
gdf1 = gdf[["ANALYSISID","geometry"]]
sales =gdf1.merge(dfb, left_on='ANALYSISID', right_on='Analysis')


app = dash.Dash(__name__, external_stylesheets=[dbc.themes.FLATLY])
app.layout = html.Div([

####app layout code for 4 dropdowns, a radio button, a table, 2 graphs, and 2 statistical ouputs.####

Below is a snippet of the app layout code I have been writing but have not been successful in connecting to a callback and returning a figure.

############################################################################### map layout

    dbc.Row(
        [
            dbc.Col(
                    dl.Map([
                    dl.TileLayer(),  # <-- default basemap
                    geojson,                      
                    id="map", style={'width': '100%', 'height': '80vh', 'margin': "auto", "display": "block"},
                ])
         
            ),
            
        ],
)


@app.callback(
    Output('graph-container1', 'children'),    
    Output('graph-container', 'children'),
    Output('table-container', 'data'),
    Output('my_output', 'children'),
    Output('my_output1', 'children'),
    Output('map', 'children'),
    Input('factor2', 'value'),
    Input('factor1', 'value'),
    Input('radio_items', 'value'),   
    Input('SMA-dpdn', 'value'), 
    Input('LGA-dpdn', 'value'),

prevent_initial_call=True

1 Answers1

1
  • have not used dash-leaflet before. Simply it works the same as any type of dash component when returned from a callback
  • have sourced / generated some data so your initial data frame code works
  • have created a very rudimentary layout that is layout indicated by parameters you provided to @app.callback()
  • in line with first point, changed callback to pass list of inputs and list of outputs
  • coded a callback method, parameters being the inputs. return is a tuple of all the outputs

full working example

import pandas as pd
import geopandas as gpd
import numpy as np
import dash
import plotly.express as px
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_leaflet as dl
from jupyter_dash import JupyterDash

# set up some data that is missing from question
gdf = (
    gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
    .rename(columns={"iso_a3": "ANALYSISID"})
    .sample(30)
)
df = pd.DataFrame(
    {
        c: gdf["ANALYSISID"] if c == "Analysis" else np.random.uniform(1, 30, len(gdf))
        for c in ["Analysis", "LGA", "SMA", "AVLU", "Address", "Locality", "AREA(HA)", "Sale Date"]  # fmt: skip
    }
)
dfb = df
df = df[["Analysis", "LGA", "SMA", "AVLU", "Address", "Locality", "AREA(HA)", "Sale Date"]]  # fmt: skip
gdf1 = gdf[["ANALYSISID", "geometry"]]
sales = gdf1.merge(dfb, left_on="ANALYSISID", right_on="Analysis")

app = JupyterDash(__name__)

# setup a layout missing from question, partial definition of callback
app.layout = html.Div(
    [html.Div(id=id) for id in ["my_output", "my_output1"]]
    + [dcc.Input(id=id, type="number") for id in ["factor2", "factor1"]]
    + [
        dcc.RadioItems(
            df["Analysis"].tolist(),
            df["Analysis"].tolist()[0],
            inline=True,
            id="radio_items",
        )
    ]
    + [dcc.Dropdown(["A", "B", "C"], "A", id=id) for id in ["SMA-dpdn", "LGA-dpdn"]]
    + [html.Div(id=id) for id in ["graph-container1", "graph-container", "map"]]
    + [
        dash_table.DataTable(
            id="table-container",
            columns=[
                {"name": i, "id": i} for i in df.drop(columns=["Analysis"]).columns
            ],
        )
    ]
)

# many output and inputs so define them as iterators
@app.callback(
    [
        Output("graph-container1", "children"),
        Output("graph-container", "children"),
        Output("table-container", "data"),
        Output("my_output", "children"),
        Output("my_output1", "children"),
        Output("map", "children"),
    ],
    [
        Input("factor2", "value"),
        Input("factor1", "value"),
        Input("radio_items", "value"),
        Input("SMA-dpdn", "value"),
        Input("LGA-dpdn", "value"),
    ],
)
# call back that takes all parameters and returns all outputs
def big_cb(factor2, factor1, radio_items, sma_dpdn, lga_dpdn):
    # make graphs, table and map dependent on radio button selection
    df_ = df.loc[df["Analysis"].eq(radio_items)].drop(columns=["Analysis"])
    gdf_ = gdf1.loc[gdf1["ANALYSISID"].eq(radio_items)]
    return (
        dcc.Graph(figure=px.scatter(df_)),
        dcc.Graph(figure=px.bar(df_)),
        df_.to_dict("records"),
        factor2,
        radio_items,
        # dash-leaflet the question.  create using geojson from geopandas dataframe
        # centering is just for convenience
        dl.Map(
            [dl.TileLayer(), dl.GeoJSON(data=gdf_.__geo_interface__)],
            center=gdf_.unary_union.centroid.coords[0][::-1],
            style={"width": "1000px", "height": "500px"},
        ),
    )


if __name__ == "__main__":
    #     app.run_server(debug=True)
    app.run_server(mode="inline", debug=True, port=8051)
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30