过滤数据的多个回调 - dash Plotly

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

我希望包含多个回调或将它们组合起来以过滤数据。这些函数将用于可视化图形。

第一个回调返回指定区域内的点数据。它被分配给一个名为

area-dropdown
的下拉栏。下拉栏和回调函数从主 df 返回较小的子集。这是通过合并特定多边形区域内的点数据来实现的。

散点图和条形图的附加回调函数。他们过滤

Code
Cat
.

中的唯一值

目前,我在

Code
Cat
中过滤唯一值的回调函数已经运行。这在 2nd 批代码中有概述。如果我将此部分注释掉并使用 1st 批代码,则区域下拉回调功能正常。

我的目标是找到一种将这两种功能结合在一起的方法。

import geopandas as gpd
import plotly.express as px
import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objs as go
import plotly.figure_factory as ff
import geopandas as gpd
from itertools import cycle

# point data
gdf_all = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))

i = iter(['A', 'B', 'C', 'D'])
gdf_all['Cat'] = gdf_all.index.map(dict(zip(gdf_all.index, cycle(i))))

j = iter(['10-20', '20-30', '30-40', '40-50', '60-70'])
gdf_all['Code'] = gdf_all.index.map(dict(zip(gdf_all.index, cycle(j))))

# polygon data
gdf_poly = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
gdf_poly = gdf_poly.drop('name', axis = 1)

gdf_all['LON'] = gdf_all['geometry'].x
gdf_all['LAT'] = gdf_all['geometry'].y

# subset African continent
Afr_gdf_area = gdf_poly[gdf_poly['continent'] == 'Africa'].reset_index(drop = True)

# subset European continent
Eur_gdf_area = gdf_poly[gdf_poly['continent'] == 'Europe'].reset_index(drop = True)

# function to merge point data within selected polygon area
def merge_withinboundary(gdf1, gdf2):

    # spatial join data within larger boundary
    gdf_out = gpd.sjoin(gdf1, gdf2, predicate = 'within', how = 'inner').reset_index(drop = True)

    return gdf_out

gdf_Africa = merge_withinboundary(gdf_all, Afr_gdf_area)
gdf_Europe = merge_withinboundary(gdf_all, Eur_gdf_area)



external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]

app = dash.Dash(__name__, external_stylesheets = external_stylesheets)

nav_bar =  html.Div([
     html.P("area-dropdown:"),
     dcc.Dropdown(
       id = 'data', 
       value = 'data', 
       options = [{'value': 'gdf_all', 'label': 'gdf_all'},
             {'value': 'gdf_Africa', 'label': 'gdf_Africa'},
             {'value': 'gdf_Europe', 'label': 'gdf_Europe'}
             ],
       clearable=False
  ),

    html.Label('Code', style = {'paddingTop': '1rem'}),
    dcc.Checklist(
            id = 'Code',
            options = [
                 {'label': '10-20', 'value': '10-20'},
                 {'label': '20-30', 'value': '20-30'},
                 {'label': '30-40', 'value': '30-40'},
                 {'label': '40-50', 'value': '40-50'},
                 {'label': '60-70', 'value': '60-70'},                        
                 ],
            value = ['10-20', '20-30', '30-40', '40-50', '60-70'],
            style = {'display': 'inline', 'margin-right': '50px'}
        ),

    html.Label('Cat', style = {'paddingTop': '1rem'}),
    dcc.Checklist(
            id = 'Cat',
            options = [
                 {'label': 'A', 'value': 'A'},
                 {'label': 'B', 'value': 'B'},
                 {'label': 'C', 'value': 'C'},
                 {'label': 'D', 'value': 'D'},                     
                 ],
            value = ['A', 'B', 'C', 'D'],
            style = {'display': 'inline', 'margin-right': '50px'}
        ),

    html.Label('Spatial Map', style = {'paddingTop': '1rem'}),
    dcc.RadioItems(['Scatter','Hexbin'],'Scatter', 
                       id = 'maps', 
                       #labelStyle= {"margin":"1rem"}, 
                       style = {'display': 'inline', 'margin-right': '50px'}
                       ),

 ], className = "vstack gap-2 h-50")


app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.Div(nav_bar), className = 'bg-light', width=2),
        dbc.Col([
            dbc.Row([
                dbc.Col(dcc.Graph(id = 'spatial-chart'))
            ]),
            dbc.Row([
                dbc.Col(dcc.Graph(id = 'bar-chart'))
            ]),
        ], width = 5),
        dbc.Col([
        ], width = 5),
    ])
], fluid = True)


df = gdf_all

#================  1st   =======================
# function to return selected df for plotting
#@app.callback(Output('spatial-chart', 'figure'),
#              Output('bar-chart', 'figure'),
#              Input('data', 'value'),
#              prevent_initial_call=True)

# function to return df using smaller areas
#def update_dataset(dropdown_selection):

#    if dropdown_selection == 'gdf_Africa':
#        gdf = gdf_Africa
#        zoom = 2

#    elif dropdown_selection == 'gdf_Europe':
#        gdf = gdf_Europe
#        zoom = 2

#    else:
#        gdf = gdf_all
#        zoom = 0

#    scatter_subset = px.scatter_mapbox(data_frame = gdf, 
#        lat = 'LAT', 
#        lon = 'LON',
#        zoom = zoom,
#        mapbox_style = 'carto-positron', 
#       )
#    count = gdf['name'].value_counts()

#    bar_subset = px.bar(x = count.index, 
#                y = count.values, 
#               color = count.index, 
#                ) 

#    return scatter_subset, bar_subset
#=============================================


#================  2nd   =======================
# function to filter unique Cat/Code for bar chart
@app.callback(
    [Output('bar-chart', 'figure'),
    ],
    [Input('Cat','value'), 
     Input('Code','value'),
     ]
     )     

def date_chart(cat, code):

    dff = df[df['Cat'].isin(cat)]
    dff = dff[dff['Code'].isin(code)]
    count = dff['Cat'].value_counts()

    data = px.bar(x = count.index, 
                 y = count.values,
                 color = count.index, 
                 )

    fig = [go.Figure(data = data)]

    return fig

# function to filter unique Cat/Code for scatter
@app.callback(
    [Output('spatial-chart', 'figure'),
     ],
    [Input('Cat','value'), 
     Input('Code','value'),
     Input("maps", "value"),
     ])     

def scatter_chart(cat, code, maps):

    if maps == 'Scatter':
    
        dff = df[df['Cat'].isin(cat)]
        dff = dff[dff['Code'].isin(code)]

        data = px.scatter_mapbox(data_frame = dff, 
                                   lat = 'LAT', 
                                   lon = 'LON',
                                   color = 'Cat',
                                   opacity = 0.5,
                                   zoom = 1,
                                   mapbox_style = 'carto-positron', 
                                   hover_name = 'Cat',
                                   ) 

        fig = [go.Figure(data = data)]


    elif maps == 'Hexbin':

        dff = df[df['Cat'].isin(cat)]
        dff = dff[dff['Code'].isin(code)]

        data = ff.create_hexbin_mapbox(data_frame = dff, 
                                      lat = "LAT", 
                                      lon = "LON",
                                      nx_hexagon = 100,
                                      min_count = 1,
         )
    

        fig = [go.Figure(data = data)]

    return fig
#=============================================


if __name__ == '__main__':
    app.run_server(debug=True, port = 8051)
python callback plotly plotly-dash
1个回答
0
投票

我将你的回调函数

update_dataset
date_chart
scatter_chart
合并到一个回调中。此函数处理下拉选择、清单和单选项组件,并输出更新的散点图框和条形图。

import geopandas as gpd
import plotly.express as px
import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objs as go
import plotly.figure_factory as ff
import geopandas as gpd
from itertools import cycle

# point data
gdf_all = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))

i = iter(['A', 'B', 'C', 'D'])
gdf_all['Cat'] = gdf_all.index.map(dict(zip(gdf_all.index, cycle(i))))

j = iter(['10-20', '20-30', '30-40', '40-50', '60-70'])
gdf_all['Code'] = gdf_all.index.map(dict(zip(gdf_all.index, cycle(j))))

# polygon data
gdf_poly = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
gdf_poly = gdf_poly.drop('name', axis = 1)

gdf_all['LON'] = gdf_all['geometry'].x
gdf_all['LAT'] = gdf_all['geometry'].y

# subset African continent
Afr_gdf_area = gdf_poly[gdf_poly['continent'] == 'Africa'].reset_index(drop = True)

# subset European continent
Eur_gdf_area = gdf_poly[gdf_poly['continent'] == 'Europe'].reset_index(drop = True)

# function to merge point data within selected polygon area
def merge_withinboundary(gdf1, gdf2):

    # spatial join data within larger boundary
    gdf_out = gpd.sjoin(gdf1, gdf2, predicate = 'within', how = 'inner').reset_index(drop = True)

    return gdf_out

gdf_Africa = merge_withinboundary(gdf_all, Afr_gdf_area)
gdf_Europe = merge_withinboundary(gdf_all, Eur_gdf_area)



external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]

app = dash.Dash(__name__, external_stylesheets = external_stylesheets)

nav_bar =  html.Div([
     html.P("area-dropdown:"),
     dcc.Dropdown(
       id = 'data', 
       value = 'data', 
       options = [{'value': 'gdf_all', 'label': 'gdf_all'},
             {'value': 'gdf_Africa', 'label': 'gdf_Africa'},
             {'value': 'gdf_Europe', 'label': 'gdf_Europe'}
             ],
       clearable=False
  ),

    html.Label('Code', style = {'paddingTop': '1rem'}),
    dcc.Checklist(
            id = 'Code',
            options = [
                 {'label': '10-20', 'value': '10-20'},
                 {'label': '20-30', 'value': '20-30'},
                 {'label': '30-40', 'value': '30-40'},
                 {'label': '40-50', 'value': '40-50'},
                 {'label': '60-70', 'value': '60-70'},                        
                 ],
            value = ['10-20', '20-30', '30-40', '40-50', '60-70'],
            style = {'display': 'inline', 'margin-right': '50px'}
        ),

    html.Label('Cat', style = {'paddingTop': '1rem'}),
    dcc.Checklist(
            id = 'Cat',
            options = [
                 {'label': 'A', 'value': 'A'},
                 {'label': 'B', 'value': 'B'},
                 {'label': 'C', 'value': 'C'},
                 {'label': 'D', 'value': 'D'},                     
                 ],
            value = ['A', 'B', 'C', 'D'],
            style = {'display': 'inline', 'margin-right': '50px'}
        ),

    html.Label('Spatial Map', style = {'paddingTop': '1rem'}),
    dcc.RadioItems(['Scatter','Hexbin'],'Scatter', 
                       id = 'maps', 
                       #labelStyle= {"margin":"1rem"}, 
                       style = {'display': 'inline', 'margin-right': '50px'}
                       ),

 ], className = "vstack gap-2 h-50")


app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.Div(nav_bar), className = 'bg-light', width=2),
        dbc.Col([
            dbc.Row([
                dbc.Col(dcc.Graph(id = 'spatial-chart'))
            ]),
            dbc.Row([
                dbc.Col(dcc.Graph(id = 'bar-chart'))
            ]),
        ], width = 5),
        dbc.Col([
        ], width = 5),
    ])
], fluid = True)

df = gdf_all

@app.callback(
    [Output('bar-chart', 'figure'),
     Output('spatial-chart', 'figure'),
    ],
    [Input('data', 'value'),
     Input('Cat', 'value'), 
     Input('Code','value'),
     Input('maps', 'value'),
     ]
     )     

def update_charts(dropdown_selection, cat, code, maps):

    ## dropdown defines df before the other inputs subset it further
    if dropdown_selection == 'gdf_Africa':
        df = gdf_Africa
        zoom = 2

    elif dropdown_selection == 'gdf_Europe':
        df = gdf_Europe
        zoom = 2

    else:
        df = gdf_all
        zoom = 0

    dff = df[df['Cat'].isin(cat)]
    dff = dff[dff['Code'].isin(code)]
    count = dff['Cat'].value_counts()

    data = px.bar(x = count.index, 
                 y = count.values,
                 color = count.index, 
                 )

    fig_bar = go.Figure(data = data)

    if maps == 'Scatter':
    
        dff = df[df['Cat'].isin(cat)]
        dff = dff[dff['Code'].isin(code)]

        data = px.scatter_mapbox(data_frame = dff, 
                                   lat = 'LAT', 
                                   lon = 'LON',
                                   color = 'Cat',
                                   opacity = 0.5,
                                   zoom = 1,
                                   mapbox_style = 'carto-positron', 
                                   hover_name = 'Cat',
                                   ) 

        fig_mapbox = go.Figure(data = data)


    elif maps == 'Hexbin':

        dff = df[df['Cat'].isin(cat)]
        dff = dff[dff['Code'].isin(code)]

        data = ff.create_hexbin_mapbox(data_frame = dff, 
                                      lat = "LAT", 
                                      lon = "LON",
                                      nx_hexagon = 100,
                                      min_count = 1,
         )
    
        fig_mapbox = go.Figure(data = data)
    
    return fig_bar, fig_mapbox

if __name__ == '__main__':
    app.run_server(debug=True, port = 8051)

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