Python:如何更新bokeh中的数据选择?

ema*_*max 6 python bokeh

我是新来的bokeh

这就是我在做什么。从osmnx我那里获得海地学校和医院的数据。

没有编写所有代码,我到达以下代码

data1=dict(
    x=list(schools['x'].values),
    y=list(schools['y'].values)
)

data2=dict(
    x=list(hospitals['x'].values),
    y=list(hospitals['y'].values)
)

building = 'Schools'

buildings = {
    'Schools': {
    'title': 'Schools',
    'data': data1,
    'color': 'black'
    },

    'Hospitals': {
    'title': 'Hospitals',
    'data': data2,
    'color': 'red'
    }
}

building_select = Select(value=building, title='Building', options=sorted(buildings.keys()))
Run Code Online (Sandbox Code Playgroud)

我想通过选择它来更改学校和医院之间的可视化。我定义了更改要获取的数据和颜色的函数。

def returnInfo(building):
    dataPoints = buildings[building]['data']
    color = buildings[building]['color']
    return dataPoints, color

dataPoints, color = returnInfo(building)
Run Code Online (Sandbox Code Playgroud)

我定义功能 make_plot

def make_plot(dataPoints, title, color):

    TOOLS = "pan, wheel_zoom, reset,save"

    p = figure(plot_width=800,
           tools=TOOLS,
           x_axis_location=None, 
           y_axis_location=None)

# Add points on top (as black points)
    buildings = p.circle('x', 'y', size=4, source=data1, color=color)


    hover_buildings = HoverTool(renderers = [buildings], point_policy="follow_mouse", tooltips = [("(Long, Lat)", "($x, $y)")])

    p.add_tools(hover_buildings)

    return p
Run Code Online (Sandbox Code Playgroud)

plot = make_plot(数据点,“ +建筑物[building] ['title']的数据,颜色)

然后我更新

def update_plot(attrname, old, new):
    building = building_select.value
    p.title.text = "Data for " + buildings[building]['title']
    src = buildings[building]['data']
    dataPoints, color = returnInfo(building)
    dataPoints.update

building_select.on_change('value', update_plot)

controls = column(building_select)
curdoc().add_root(row(plot, controls))
Run Code Online (Sandbox Code Playgroud)

但它不起作用:即,即使有光标,我也无法将点从学校更改为医院。更新部分中的错误在哪里?

Ton*_*ony 6

作为第一个解决方案,我建议使用legend.click_plolicy = 'hide'切换建筑物在地图上的可见性(Bokeh v1.1.0)

from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, show
from bokeh.tile_providers import CARTODBPOSITRON_RETINA
import osmnx as ox

amenities = ['hospital', 'school']
for i, amenity in enumerate(amenities):
    buildings = ox.pois_from_address("Port-au-Prince, Haiti", amenities = [amenity], distance = 3500)[['geometry', 'name', 'element_type']]
    for item in ['way', 'relation']:
        buildings.loc[buildings.element_type == item, 'geometry'] = buildings[buildings.element_type == item]['geometry'].map(lambda x: x.centroid)
        buildings.name.fillna('Hospital' if i == 0 else 'School', inplace = True)
        amenities[i] = buildings.to_crs(epsg = 3857)

p = figure(title = "Port-au-Prince, Haiti", tools = "pan,wheel_zoom,hover,reset", x_range = (-8057000, -8048500), y_range = (2098000, 2106000), 
           tooltips = [('Name', '@name'), ("(Long, Lat)", "($x, $y)")], x_axis_location = None, y_axis_location = None, active_scroll = 'wheel_zoom')
p.add_tile(CARTODBPOSITRON_RETINA)
p.grid.grid_line_color = None

for i, b in enumerate(amenities):
    source = ColumnDataSource(data = dict(x = b.geometry.x, y = b.geometry.y, name = b.name.values))
    p.circle('x', 'y', color = 'red' if i == 0 else 'blue', source = source, legend = 'Hospital' if i == 0 else 'School')

p.legend.click_policy = 'hide' 

show(p)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

如果您想要Select小部件,那么这里是另一种选择(Bokeh v1.1.0):

from bokeh.models import ColumnDataSource, Column, Select, CustomJS
from bokeh.plotting import figure, show
from bokeh.tile_providers import CARTODBPOSITRON_RETINA
import osmnx as ox

amenities = ['hospital', 'school']
for i, amenity in enumerate(amenities):
    buildings = ox.pois_from_address("Port-au-Prince, Haiti", amenities = [amenity], distance = 3500)[['geometry', 'name', 'element_type']]
    for item in ['way', 'relation']:
        buildings.loc[buildings.element_type == item, 'geometry'] = buildings[buildings.element_type == item]['geometry'].map(lambda x: x.centroid)
        buildings.name.fillna('Hospital' if i == 0 else 'School', inplace = True)
        buildings = buildings.to_crs(epsg = 3857)      
    amenities[i] = dict(x = list(buildings.geometry.x), y = list(buildings.geometry.y), name = list(buildings.name.values), color = (['red'] if i == 0 else ['blue']) * len(buildings.name.values))

source = ColumnDataSource(amenities[0])
p = figure(title = "Hospitals", tools = "pan,wheel_zoom,hover,reset", x_range = (-8057000, -8048500), y_range = (2098000, 2106000), 
           tooltips = [('Name', '@name'), ("(Long, Lat)", "($x, $y)")], x_axis_location = None, y_axis_location = None, active_scroll = 'wheel_zoom')
p.add_tile(CARTODBPOSITRON_RETINA)
p.circle(x = 'x', y = 'y', color = 'color', source = source)
p.grid.grid_line_color = None

code = '''  source.data = (cb_obj.value == 'Hospitals' ? data[0] : data[1]); p.title.text =  cb_obj.value; '''
select = Select(options = ['Hospitals', 'Schools'], callback = CustomJS(args=dict(p = p, source = source, data = amenities), code = code))

show(Column(p, select))
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

让我知道您是否需要对此代码的任何解释。


Web*_*Dev 0

以下是使您的代码正常工作所需的更改:

在您的make_plot方法中,由于您想在选择更改时更新绘图的标题,因此将

p = figure(plot_width=800,
           tools=TOOLS,
           x_axis_location=None, 
           y_axis_location=None)
Run Code Online (Sandbox Code Playgroud)

p = figure(plot_width=800,
                tools=TOOLS,
                title=title,
                x_axis_location=None, 
                y_axis_location=None)
Run Code Online (Sandbox Code Playgroud)

另外,由于您想要更新建筑物的数据和颜色,因此请buildings在方法中返回too,以便完整的方法现在如下所示:

def make_plot(dataPoints, title, color):

            TOOLS = "pan, wheel_zoom, reset,save"

            p = figure(plot_width=800,
                tools=TOOLS,
                title=title,
                x_axis_location=None, 
                y_axis_location=None)

        # Add points on top (as black points)
            buildings = p.circle('x', 'y', size=4, source=data1, color=color)


            hover_buildings = HoverTool(renderers = [buildings], point_policy="follow_mouse", tooltips = [("(Long, Lat)", "($x, $y)")])

            p.add_tools(hover_buildings)

            return p, buildings
Run Code Online (Sandbox Code Playgroud)

接下来,而不是调用

plot = make_plot(dataPoints, "Data for " + buildings[building]['title'], color)
Run Code Online (Sandbox Code Playgroud)

您还需要将返回的建筑物也保存在变量中,以便可以直接更新。所以现在你的电话看起来像

plot, b = make_plot(dataPoints, "Data for " + buildings[building]['title'], color)
Run Code Online (Sandbox Code Playgroud)

最后,更改你的update_plot方法,使其看起来像这样:

def update_plot(attrname, old, new):
            building = building_select.value
            plot.title.text = "Data for " + buildings[building]['title']
            src = buildings[building]['data']
            dataPoints, color = returnInfo(building)
            b.data_source.data = dataPoints
            b.glyph.fill_color = color
Run Code Online (Sandbox Code Playgroud)

通过这些更改,它将按预期工作。请参阅所附结果。使用的样本数据是:

data1=dict(
        x=[1,2,3],
        y=[2,1,3]
    )

data2=dict(
        x=[1,2,3],
        y=[1,3,2]
    )
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述