【问题标题】:Python bokeh slider not refreshing plotPython散景滑块不刷新情节
【发布时间】:2019-02-11 10:54:36
【问题描述】:

我正在创建一个带有滑块的散景图,以相应地刷新图。发布的代码有两个问题。 1. 绘图不按滑块刷新。请帮助提供解决此问题的方法。 2.使用bokeh serve --show fn.ipynb时,curdoc()不显示plot

我正在尝试可视化this CSV 文件。

import pandas as pd
import numpy as np
from bokeh.models import ColumnDataSource, CategoricalColorMapper, HoverTool, Slider
from bokeh.plotting import figure, curdoc
from bokeh.palettes import viridis
from bokeh.layouts import row, widgetbox

#Importing and processing data file 
crop = pd.read_csv('crop_production.csv') 

#Cleaning Data 
crop.fillna(np.NaN) 
crop['Season'] = crop.Season.str.strip() 

#Removing Whitespace #Filtering the dataset by Season 
crop_season = crop[crop.Season == 'Whole Year'] 
crop_dt = crop_season.groupby(['State_Name', 'District_Name', 'Crop_Year']).mean().round(1)

#Creating Column Data Source
source = ColumnDataSource({
        'x'        : crop_dt[crop_dt.index.get_level_values('Year')==2001].loc[(['ABC']), :].Area,
        'y'        : crop_dt[crop_dt.index.get_level_values('Year')==2001].loc[(['ABC']), :].Production,
        'state'    : crop_dt[crop_dt.index.get_level_values('Year')==2001].loc[(['ABC']), :].index.get_level_values('State_Name'),
        'district' : crop_dt[crop_dt.index.get_level_values('Year')==2001].loc[(['ABC']), :].index.get_level_values('District_Name')
})


#Creating color palette for plot
district_list = crop_dt.loc[(['Tamil Nadu']), :].index.get_level_values('District_Name').unique().tolist()
call_colors = viridis(len(district_list))
color_mapper = CategoricalColorMapper(factors=district_list, palette=call_colors)


# Creating the figure
#xmin, xmax = min(data.Crop_Year), max(data.Crop_Year)
#ymin, ymax = min(data.Production), max(data.Production)
p = figure(
    title = 'Crop Area vs Production',
    x_axis_label = 'Area',
    y_axis_label = 'Production',
    plot_height=900, 
    plot_width=1200,
    tools = [HoverTool(tooltips='@district')]
          )
p.circle(x='x', y='y', source=source, size=12, alpha=0.7, 
         color=dict(field='district', transform=color_mapper),
         legend='district')
p.legend.location = 'top_right'


def update_plot(attr, old, new):
    yr = slider.value
    new_data = {
        'x'        : crop_dt[crop_dt.index.get_level_values('Year')==yr].loc[(['ABC']), :].Area,
        'y'        : crop_dt[crop_dt.index.get_level_values('Year')==yr].loc[(['ABC']), :].Production,
        'state'    : crop_dt[crop_dt.index.get_level_values('Year')==yr].loc[(['ABC']), :].index.get_level_values('State_Name'),
        'district' : crop_dt[crop_dt.index.get_level_values('Year')==yr].loc[(['ABC']), :].index.get_level_values('District_Name')
    }
    source.data = new_data

#Creating Slider for Year
start_yr = min(crop_dt.index.get_level_values('Crop_Year'))
end_yr = max(crop_dt.index.get_level_values('Crop_Year'))
slider = Slider(start=start_yr, end=end_yr, step=1, value=start_yr, title='Year')
slider.on_change('value',update_plot)

layout = row(widgetbox(slider), p)
curdoc().add_root(layout)
show(layout)

还尝试了使用 CustomJS 的不同选项,如下所示,但仍然没有运气。

callback = CustomJS(args=dict(source=source), code="""
    var data = source.data;
    var yr = slider.value;
    var x = data['x']
    var y = data['y']
    'x'        = crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['ABC']), :].Area;
    'y'        = crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['ABC']), :].Production;
    p.circle(x='x', y='y', source=source, size=12, alpha=0.7, 
         color=dict(field='district', transform=color_mapper),
         legend='district');
    }
    source.change.emit();
""")



#Creating Slider for Year
start_yr = min(crop_dt.index.get_level_values('Crop_Year'))
end_yr = max(crop_dt.index.get_level_values('Crop_Year'))
yr_slider = Slider(start=start_yr, end=end_yr, step=1, value=start_yr, title='Year', callback=callback)
callback.args["slider"] = yr_slider

【问题讨论】:

  • 能否在您的帖子中添加一些示例数据,以便我们调试您的代码?
  • 我的意思是crop_production.csv文件;)
  • @Jasper 添加数据和代码的初始部分:
  • #导入和处理数据文件crop = pd.read_csv('crop_production.csv') #清理数据crop.fillna(np.NaN)crop['Season'] = crop.Season.str. strip() #Removing Whitespace #按季节过滤数据crop_season = crop[crop.Season == 'Whole Year'] crop_dt = crop_season.groupby(['State_Name', 'District_Name', 'Crop_Year']).mean() .round(1)

标签: python data-visualization bokeh data-science


【解决方案1】:

在尝试执行您的代码时遇到了很多问题,我已经更改了一些内容,所以如果做错了,请随时纠正我。

错误是由ColumnDataSource 的创建引起的,我不得不将级别值更改为 Crop_Year 而不是 Year。 loc 'ABC' 也导致了一个错误,所以我也删除了它(我必须添加 source = ColumnDataSource({,你可能忘记复制了)

我还添加了一个下拉菜单,因此可以只显示一个地区的数据。

另外,我不太确定是否可以通过向 --serve 提供 .ipynb 文件来启动散景服务器。但是不要把我钉在那个上面,我从不使用笔记本。我已经用 .py 文件对此进行了测试。

#!/usr/bin/python3
import pandas as pd
import numpy as np
from bokeh.models import ColumnDataSource, CategoricalColorMapper, HoverTool
from bokeh.plotting import figure, curdoc
from bokeh.palettes import viridis
from bokeh.layouts import row, widgetbox
from bokeh.models.widgets import Select, Slider

#Importing and processing data file 
crop = pd.read_csv('crop_production.csv') 

#Cleaning Data 
crop.fillna(np.NaN) 
crop['Season'] = crop.Season.str.strip() 

#Removing Whitespace #Filtering the dataset by Season 
crop_season = crop[crop.Season == 'Whole Year'] 
crop_dt = crop_season.groupby(['State_Name', 'District_Name', 'Crop_Year']).mean().round(1)

crop_dt_year = crop_dt[crop_dt.index.get_level_values('Crop_Year')==2001]
crop_dt_year_state = crop_dt_year[crop_dt_year.index.get_level_values('State_Name')=='Tamil Nadu']

#Creating Column Data Source
source = ColumnDataSource({
    'x': crop_dt_year_state.Area.tolist(), 
    'y': crop_dt_year_state.Production.tolist(), 
    'state': crop_dt_year_state.index.get_level_values('State_Name').tolist(), 
    'district': crop_dt_year_state.index.get_level_values('District_Name').tolist()
})

#Creating color palette for plot
district_list = crop_dt.loc[(['Tamil Nadu']), :].index.get_level_values('District_Name').unique().tolist()
call_colors = viridis(len(district_list))
color_mapper = CategoricalColorMapper(factors=district_list, palette=call_colors)

# Creating the figure
p = figure(
    title = 'Crop Area vs Production',
    x_axis_label = 'Area',
    y_axis_label = 'Production',
    plot_height=900, 
    plot_width=1200,
    tools = [HoverTool(tooltips='@district')]
          )
glyphs = p.circle(x='x', y='y', source=source, size=12, alpha=0.7, 
         color=dict(field='district', transform=color_mapper),
         legend='district')
p.legend.location = 'top_right'

def update_plot(attr, old, new):
    #Update glyph locations
    yr = slider.value
    state  = select.value
    crop_dt_year = crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr]
    crop_dt_year_state = crop_dt_year[crop_dt_year.index.get_level_values('State_Name')==state]
    new_data = {
        'x': crop_dt_year_state.Area.tolist(), 
        'y': crop_dt_year_state.Production.tolist(), 
        'state': crop_dt_year_state.index.get_level_values('State_Name').tolist(), 
        'district': crop_dt_year_state.index.get_level_values('District_Name').tolist()
    }
    source.data = new_data
    #Update colors
    district_list = crop_dt.loc[([state]), :].index.get_level_values('District_Name').unique().tolist()
    call_colors = viridis(len(district_list))
    color_mapper = CategoricalColorMapper(factors=district_list, palette=call_colors)
    glyphs.glyph.fill_color = dict(field='district', transform=color_mapper)
    glyphs.glyph.line_color = dict(field='district', transform=color_mapper)

#Creating Slider for Year
start_yr = min(crop_dt.index.get_level_values('Crop_Year'))
end_yr = max(crop_dt.index.get_level_values('Crop_Year'))
slider = Slider(start=start_yr, end=end_yr, step=1, value=start_yr, title='Year')
slider.on_change('value',update_plot)

#Creating drop down for state
options = list(set(crop_dt.index.get_level_values('State_Name').tolist()))
options.sort()
select = Select(title="State:", value="Tamil Nadu", options=options)
select.on_change('value', update_plot)

layout = row(widgetbox(slider, select), p)
curdoc().add_root(layout)

【讨论】:

  • Dint 期待为您提供如此多的支持。我现在要开始工作了。但你已经做了一切。非常感谢 Jasper 的工作。
  • 很高兴为您服务!如果可以的话,请使用左侧的复选标记接受答案。
【解决方案2】:

@Jasper 非常感谢。这可行,但它不适用于 .loc[(['Tamil Nadu']), :]。这样做的原因是通过添加散景下拉列表或单选按钮对象来过滤数据,并根据过滤器刷新绘图。以下代码仅在删除 .loc[(['Tamil Nadu']), :] 时才有效。请问有没有其他方法可以解决这个问题?

def update_plot(attr, old, new):
    yr = slider.value
    new_data = {
        'x'        : crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['Tamil Nadu']), :].Area.tolist(),
        'y'        : crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['Tamil Nadu']), :].Production.tolist(),
        'state'    : crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['Tamil Nadu']), :].index.get_level_values('State_Name').tolist(),
        'district' : crop_dt[crop_dt.index.get_level_values('Crop_Year')==yr].loc[(['Tamil Nadu']), :].index.get_level_values('District_Name').tolist()
    }
    source.data = new_data

【讨论】:

  • 我已经编辑了我的答案,以包括一个按州过滤的下拉菜单。它还没有更新颜色,但我今天没有时间修复它。
  • 现在应该修复一切。
猜你喜欢
  • 2021-10-20
  • 1970-01-01
  • 1970-01-01
  • 2021-02-02
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多