JPA*_*888 6 python callback plotly choropleth plotly-dash
我希望包含一个带有回调函数的下拉栏,允许用户在较小的区域内显示特定的点。最初,我想使用所有点几何数据作为默认值。然后,我的目标是包含一个下拉栏和回调函数,该函数从该主 df 返回较小的子集。这是通过合并特定多边形区域内的点数据来完成的。
使用下面的方法,默认 df 被标记为gdf_all。这包含一个大区域的点数据。较小的多边形文件是gdf_poly. 其中包括非洲和欧洲大陆。它们在函数中使用,仅在点数据在多边形形状内相交时返回点数据。
我已经对下面的输出进行了硬编码。1) 使用gdf_all2) 使用非洲大陆的子集。
理想情况下,下拉栏将用于输入要在图中可视化的所需点数据。
import geopandas as gpd
import plotly.express as px
import dash
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
# point data
gdf_all = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))
# 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 = 'left').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)
# function to return selected df for plotting
def update_dataset(df):
if df == 'gdf_Africa':
gdf = gdf_Africa
elif df == 'gdf_Europe':
gdf = gdf_Europe
else:
gdf = gdf_all
return gdf
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
),
])
# output 1
df = gdf_all
# output 2
#df = gdf_Africa
scatter = px.scatter_mapbox(data_frame = df,
lat = 'LAT',
lon = 'LON',
zoom = 2,
mapbox_style = 'carto-positron',
)
count = df['name'].value_counts()
bar = px.bar(x = count.index,
y = count.values,
color = count.index,
)
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(nav_bar), width=2),
dbc.Col([
dbc.Row([
dbc.Col(dcc.Graph(figure = scatter))
]),
dbc.Row([
dbc.Col(dcc.Graph(figure = bar))
]),
], width=5),
dbc.Col([
], width=5),
])
], fluid=True)
if __name__ == '__main__':
app.run_server(debug=True, port = 8051)
Run Code Online (Sandbox Code Playgroud)
输出1:
输出2:
我认为主要任务是转换update_dataset为回调函数,该函数将下拉选择作为输入,并输出新更新的散点图框和条形图。为此,您需要为这两个数字提供一个id参数。dcc.Graph然后在回调中,您可以根据下拉选择重新创建散点图框和条形图。
另外,我不确定您的用例,但为了本示例的目的,我修改了您的merge_withinboundary函数以执行inner join而不是左连接(使用您提供的示例数据,如果您执行左连接,您将总是以 if 这是\xe2\x80\x93gdf_all的第一个参数结束,因为和都完全包含在) 中。然而,我将把这个决定留给你 \xe2\x80\x93 也许左连接就是你想要的实际数据集。merge_withinboundaryAfr_gdf_areaEur_gdf_areagdf_all
出于演示目的,我还设置zoom = 0为默认值,因此当用户gdf_all从下拉列表中选择时,所有点都是可见的。
import geopandas as gpd\nimport plotly.express as px\nimport dash\nfrom dash import dcc, html, Input, Output\nimport dash_bootstrap_components as dbc\n\n# point data\ngdf_all = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))\n\n# polygon data\ngdf_poly = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))\ngdf_poly = gdf_poly.drop(\'name\', axis = 1)\n\ngdf_all[\'LON\'] = gdf_all[\'geometry\'].x\ngdf_all[\'LAT\'] = gdf_all[\'geometry\'].y\n\n# subset African continent\nAfr_gdf_area = gdf_poly[gdf_poly[\'continent\'] == \'Africa\'].reset_index(drop = True)\n\n# subset European continent\nEur_gdf_area = gdf_poly[gdf_poly[\'continent\'] == \'Europe\'].reset_index(drop = True)\n\n# function to merge point data within selected polygon area\ndef merge_withinboundary(gdf1, gdf2):\n\n # spatial join data within larger boundary\n gdf_out = gpd.sjoin(gdf1, gdf2, predicate = \'within\', how = \'inner\').reset_index(drop = True)\n\n return gdf_out\n\ngdf_Africa = merge_withinboundary(gdf_all, Afr_gdf_area)\ngdf_Europe = merge_withinboundary(gdf_all, Eur_gdf_area)\n\n\nexternal_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]\n\napp = dash.Dash(__name__, external_stylesheets = external_stylesheets)\n\n# function to return selected df for plotting\n@app.callback(Output(\'scatter-mapbox\', \'figure\'),\n Output(\'bar\', \'figure\'),\n Input(\'data\', \'value\'),\n prevent_initial_call=True)\n# function to return df using smaller areas\ndef update_dataset(dropdown_selection):\n if dropdown_selection == \'gdf_Africa\':\n gdf = gdf_Africa\n zoom = 2\n\n elif dropdown_selection == \'gdf_Europe\':\n gdf = gdf_Europe\n zoom = 2\n\n else:\n gdf = gdf_all\n zoom = 0\n\n scatter_subset = px.scatter_mapbox(data_frame = gdf, \n lat = \'LAT\', \n lon = \'LON\',\n zoom = zoom,\n mapbox_style = \'carto-positron\', \n )\n count = gdf[\'name\'].value_counts()\n\n bar_subset = px.bar(x = count.index, \n y = count.values, \n color = count.index, \n ) \n return scatter_subset, bar_subset\n\n\nnav_bar = html.Div([\n html.P("area-dropdown:"),\n dcc.Dropdown(\n id=\'data\', \n value=\'data\', \n options=[{\'value\': \'gdf_all\', \'label\': \'gdf_all\'},\n {\'value\': \'gdf_Africa\', \'label\': \'gdf_Africa\'},\n {\'value\': \'gdf_Europe\', \'label\': \'gdf_Europe\'}\n ],\n clearable=False\n ),\n])\n\n# output 1\ndf = gdf_all\n\n# output 2\n#df = gdf_Africa\n\nscatter = px.scatter_mapbox(data_frame = df, \n lat = \'LAT\', \n lon = \'LON\',\n zoom = 0,\n mapbox_style = \'carto-positron\', \n )\n\n\ncount = df[\'name\'].value_counts()\n\nbar = px.bar(x = count.index, \n y = count.values, \n color = count.index, \n )\n\napp.layout = dbc.Container([\n dbc.Row([\n dbc.Col(html.Div(nav_bar), width=2),\n dbc.Col([\n dbc.Row([\n dbc.Col(dcc.Graph(figure = scatter, id = \'scatter-mapbox\'))\n ]),\n dbc.Row([\n dbc.Col(dcc.Graph(figure = bar, id = \'bar\'))\n ]),\n ], width=5),\n dbc.Col([\n ], width=5),\n ])\n], fluid=True)\n\n\nif __name__ == \'__main__\':\n app.run_server(debug=True, port = 8051)\nRun Code Online (Sandbox Code Playgroud)\n\n
| 归档时间: |
|
| 查看次数: |
519 次 |
| 最近记录: |