如何使用 Panel 更新现有图?
How to update existing plot with Panel?
我有一个与 Bokeh
配合使用的仪表板应用程序。我正在尝试将其更改为使用 Panel
和 Geoviews
。我正在使用面板回调 API,因为这看起来最像我现有的 Bokeh 代码。我是 运行 Panel 服务器的常规 Python 脚本。
当我的回调为小部件选择创建新图时,Panel 会显示一个附加图而不是更新现有图。使用“servable”会在现有浏览器中显示额外的绘图 window,使用“show”会显示额外的 window。如何更新现有地块?
这是一些测试代码。 (完整的应用程序显示带有地理数据的等值线图,并且有更多带有读取不同数据的代码的小部件,但这段代码说明了问题。)
import census_read_data as crd
import census_read_geopandas as crg
import pandas as pd
import geopandas as gpd
import geoviews as gv
from bokeh.plotting import show
from bokeh.models import PrintfTickFormatter
import panel as pn
import hvplot.pandas
# Get Census Merged Ward and Local Authority Data
# Replaced by test DataFrame
geography = pd.DataFrame(data=[
['E36007378', 'Chiswick Riverside', 'E09000018', 'Hounslow'],
['E36007379', 'Cranford', 'E09000018', 'Hounslow'],
['E36007202', 'Ealing Broadway', 'E09000009', 'Ealing'],
['E36007203', 'Ealing Common', 'E09000009', 'Ealing'],
['E36007204', 'East Acton', 'E09000009', 'Ealing'],
['E09000018', 'Hounslow', 'E09000018', 'Hounslow'],
['E09000009', 'Ealing', 'E09000009', 'Ealing']
], columns=["GeographyCode", "Name", "LAD11CD", "LAD11NM"])
# Get London Ward GeoPandas DataFrame
# Replaced by test DataFrame
london_wards_data_gdf = pd.DataFrame(data=[
['E36007378', 'E09000018', 378],
['E36007379', 'E09000018', 379],
['E36007202', 'E09000009', 202],
['E36007203', 'E09000009', 203],
['E36007204', 'E09000009', 204]
], columns=["cmwd11cd", "lad11cd", "data"])
# Get LAD GeoPandas DataFrame
# Replaced by test DataFrame
london_lads_data_gdf = pd.DataFrame(data=[
['E09000018', 757],
['E09000009', 609]
], columns=["lad11cd", "data"])
locationcol = "GeographyCode"
namecol = "Name"
datacol = 'data'
# Panel
pn.extension('bokeh')
gv.extension('bokeh')
lad_max_value = london_lads_data_gdf[datacol].max()
ward_max_value = london_wards_data_gdf[datacol].max()
title = datacol + " by Local Authority"
local_authorities = geography['LAD11CD'].unique()
granularities = ['Local Authorities', 'Wards']
# Create Widgets
granularity_widget = pn.widgets.RadioButtonGroup(options=granularities)
local_authority_widget = pn.widgets.Select(name='Wards for Local Authority',
options=['All'] +
[geography[geography[locationcol] == lad][namecol].iat[0]
for lad in local_authorities],
value='All')
widgets = pn.Column(granularity_widget, local_authority_widget)
layout = widgets
def update_graph(event):
# Callback recreates map when granularity or local_authority are changed
global layout
granularity = granularity_widget.value
local_authority_name = local_authority_widget.value
print(f'granularity={granularity}')
if granularity == 'Local Authorities':
gdf = london_lads_data_gdf
max_value = lad_max_value
title = datacol + " by Local Authority"
else:
max_value = ward_max_value
if local_authority_name == 'All':
gdf = london_wards_data_gdf
title = datacol + " by Ward"
else:
local_authority_id = geography[geography['Name'] ==
local_authority_name].iloc[0]['GeographyCode']
gdf = london_wards_data_gdf[london_wards_data_gdf['lad11cd'].str.match(
local_authority_id)]
title = datacol + " by Ward for " + local_authority_name
# Replace gv.Polygons with hvplot.bar for test purposes
map = gdf.hvplot.bar(y=datacol, height=500)
layout = pn.Column(widgets, map)
# With servable, a new plot is added to the browser window each time the widgets are changed
# layout.servable()
# With servable, a new browser window is shown each time the widgets are changed
layout.show()
granularity_widget.param.watch(update_graph, 'value')
local_authority_widget.param.watch(update_graph, 'value')
update_graph(None)
# panel serve panel_test_script.py --show
我最终使用参数而不是回调实现了我的解决方案,效果很好。但是,我最终看到了 ,它向我展示了我最初问题的解决方案。
回调不应 show()
新布局(使用新地图),而应仅更新现有布局,用新地图替换现有地图。当我写这篇文章时,它似乎很明显!
此代码片段显示了解决方案:
...
widgets = pn.Column(granularity_widget, local_authority_widget)
empty_map = pn.pane.Markdown('### Map placeholder...')
layout = pn.Column(widgets, empty_map)
def update_graph(event):
...
# Replace gv.Polygons with hvplot.bar for test purposes
map = gdf.hvplot.bar(y=datacol, height=500)
# Update existing layout with new map
layout[1] = map
granularity_widget.param.watch(update_graph, 'value')
local_authority_widget.param.watch(update_graph, 'value')
# Invoke callback to show map for initial widget values
update_graph(None)
layout.show()
我有一个与 Bokeh
配合使用的仪表板应用程序。我正在尝试将其更改为使用 Panel
和 Geoviews
。我正在使用面板回调 API,因为这看起来最像我现有的 Bokeh 代码。我是 运行 Panel 服务器的常规 Python 脚本。
当我的回调为小部件选择创建新图时,Panel 会显示一个附加图而不是更新现有图。使用“servable”会在现有浏览器中显示额外的绘图 window,使用“show”会显示额外的 window。如何更新现有地块?
这是一些测试代码。 (完整的应用程序显示带有地理数据的等值线图,并且有更多带有读取不同数据的代码的小部件,但这段代码说明了问题。)
import census_read_data as crd
import census_read_geopandas as crg
import pandas as pd
import geopandas as gpd
import geoviews as gv
from bokeh.plotting import show
from bokeh.models import PrintfTickFormatter
import panel as pn
import hvplot.pandas
# Get Census Merged Ward and Local Authority Data
# Replaced by test DataFrame
geography = pd.DataFrame(data=[
['E36007378', 'Chiswick Riverside', 'E09000018', 'Hounslow'],
['E36007379', 'Cranford', 'E09000018', 'Hounslow'],
['E36007202', 'Ealing Broadway', 'E09000009', 'Ealing'],
['E36007203', 'Ealing Common', 'E09000009', 'Ealing'],
['E36007204', 'East Acton', 'E09000009', 'Ealing'],
['E09000018', 'Hounslow', 'E09000018', 'Hounslow'],
['E09000009', 'Ealing', 'E09000009', 'Ealing']
], columns=["GeographyCode", "Name", "LAD11CD", "LAD11NM"])
# Get London Ward GeoPandas DataFrame
# Replaced by test DataFrame
london_wards_data_gdf = pd.DataFrame(data=[
['E36007378', 'E09000018', 378],
['E36007379', 'E09000018', 379],
['E36007202', 'E09000009', 202],
['E36007203', 'E09000009', 203],
['E36007204', 'E09000009', 204]
], columns=["cmwd11cd", "lad11cd", "data"])
# Get LAD GeoPandas DataFrame
# Replaced by test DataFrame
london_lads_data_gdf = pd.DataFrame(data=[
['E09000018', 757],
['E09000009', 609]
], columns=["lad11cd", "data"])
locationcol = "GeographyCode"
namecol = "Name"
datacol = 'data'
# Panel
pn.extension('bokeh')
gv.extension('bokeh')
lad_max_value = london_lads_data_gdf[datacol].max()
ward_max_value = london_wards_data_gdf[datacol].max()
title = datacol + " by Local Authority"
local_authorities = geography['LAD11CD'].unique()
granularities = ['Local Authorities', 'Wards']
# Create Widgets
granularity_widget = pn.widgets.RadioButtonGroup(options=granularities)
local_authority_widget = pn.widgets.Select(name='Wards for Local Authority',
options=['All'] +
[geography[geography[locationcol] == lad][namecol].iat[0]
for lad in local_authorities],
value='All')
widgets = pn.Column(granularity_widget, local_authority_widget)
layout = widgets
def update_graph(event):
# Callback recreates map when granularity or local_authority are changed
global layout
granularity = granularity_widget.value
local_authority_name = local_authority_widget.value
print(f'granularity={granularity}')
if granularity == 'Local Authorities':
gdf = london_lads_data_gdf
max_value = lad_max_value
title = datacol + " by Local Authority"
else:
max_value = ward_max_value
if local_authority_name == 'All':
gdf = london_wards_data_gdf
title = datacol + " by Ward"
else:
local_authority_id = geography[geography['Name'] ==
local_authority_name].iloc[0]['GeographyCode']
gdf = london_wards_data_gdf[london_wards_data_gdf['lad11cd'].str.match(
local_authority_id)]
title = datacol + " by Ward for " + local_authority_name
# Replace gv.Polygons with hvplot.bar for test purposes
map = gdf.hvplot.bar(y=datacol, height=500)
layout = pn.Column(widgets, map)
# With servable, a new plot is added to the browser window each time the widgets are changed
# layout.servable()
# With servable, a new browser window is shown each time the widgets are changed
layout.show()
granularity_widget.param.watch(update_graph, 'value')
local_authority_widget.param.watch(update_graph, 'value')
update_graph(None)
# panel serve panel_test_script.py --show
我最终使用参数而不是回调实现了我的解决方案,效果很好。但是,我最终看到了
回调不应 show()
新布局(使用新地图),而应仅更新现有布局,用新地图替换现有地图。当我写这篇文章时,它似乎很明显!
此代码片段显示了解决方案:
...
widgets = pn.Column(granularity_widget, local_authority_widget)
empty_map = pn.pane.Markdown('### Map placeholder...')
layout = pn.Column(widgets, empty_map)
def update_graph(event):
...
# Replace gv.Polygons with hvplot.bar for test purposes
map = gdf.hvplot.bar(y=datacol, height=500)
# Update existing layout with new map
layout[1] = map
granularity_widget.param.watch(update_graph, 'value')
local_authority_widget.param.watch(update_graph, 'value')
# Invoke callback to show map for initial widget values
update_graph(None)
layout.show()