I'm hoping to include multiple callbacks or combine them to filter data. These functions will be used to visualise graphs.
The first callback returns point data if it's within a designated region. It is assigned to a dropdown bar called area-dropdown:
. The dropdown bar and callback function returns smaller subsets from the main df. This is accomplished by merging the point data within a specific polygon area.
The additional callback functions are for a scatter chart and bar chart. They filter unique values in Code
and Cat
.
At present, I've got the callback functions that filter unique values in Code
and Cat
operational. This is outlined in the 2nd batch of code. If I comment this section out and use the 1st batch of code, the area dropdown callback is functional.
I'm aiming to find a method that combines both these functions together.
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)
from Multiple callbacks to filter data - dash Plotly
No comments:
Post a Comment