【问题标题】:Return x, y coordinates from Bokeh graph从散景图中返回 x, y 坐标
【发布时间】:2018-03-27 00:58:55
【问题描述】:

我正在尝试调整来自Get selected data contained within box select tool in Bokeh的答案

但得到:

NameError: name 'inds' is not defined 

选择点后。

有人知道怎么回事吗?

我正在使用的代码:

    import pandas as pd
    import numpy as np
    import matplotlib as mpl
    from bokeh.transform import factor_cmap, linear_cmap
    from bokeh.palettes import Spectral6
    from bokeh.plotting import figure, output_file, show
    from bokeh.models import CustomJS, ColumnDataSource
    from bokeh.io import output_notebook

    import bokeh.plotting as bpl
    import bokeh.models as bmo
    from bokeh.models.tools import *

    output_notebook()

    algorithm = 'Loc'
    metric = 'LengthOfStayDaysNBR'
    coordinate_df = pd.DataFrame({'x-{}'.format(str(algorithm)[:3]):np.random.rand(500)\
                                  ,'y-{}'.format(str(algorithm)[:3]):np.random.rand(500)\
                                 ,metric:np.random.rand(500)})


    TOOLS="pan,wheel_zoom,reset,hover,poly_select,lasso_select"


    p = figure(title = '{}'.format(str(algorithm)[:3]),tools=TOOLS)


    source = bpl.ColumnDataSource(coordinate_df)

    if metric == 'LengthOfStayDaysNBR':
        color_mapper = linear_cmap(metric,palette=Spectral6,low=coordinate_df[metric].min(),high=coordinate_df[metric].max())
    else:
        color_mapper = factor_cmap(metric,palette=Spectral6,factors=coordinate_df[metric].unique())



    p1 = figure(width=250, height = 250, title = '{}'.format(str(algorithm)[:3]),tools=TOOLS)

    p1.scatter('x-{}'.format(str(algorithm)[:3]),'y-{}'.format(str(algorithm)[:3]),fill_color= color_mapper, source = source)


    source.callback = CustomJS(args=dict(source=source), code="""
            var inds = cb_obj.get('selected')['1d'].indices;
            var d1 = cb_obj.get('data');
            console.log(d1)
            var kernel = IPython.notebook.kernel;
            IPython.notebook.kernel.execute("inds = " + inds);
            """
    )

    show(p1)


    # Run this after selecting
    for x,y in  zip([source.data['x-{}'.format(str(algorithm)[:3])][i] for i in inds],
        [source.data['y-{}'.format(str(algorithm)[:3])][i] for i in inds]):
        print(x,y)

提供一些背景知识:我正在尝试从包含许多特征的较大数据框中获取 x/y 坐标,选择散点图的子组,然后绘制(在条形图中)最大(20 个左右)平均值子队列的指定 x/y 坐标的特征。例如,假设您有 50 个特征(列)和 20 个数据点的子群组。我希望将剩余的 48 个要素的平均值绘制成条形图,条形图的高度代表要素的平均值。知道怎么做吗? – user123328 10 小时前
此外:如果能够将实际的索引/xy 坐标返回到某个对象中,那就太好了,即数据框、np.array、列表或其他任何东西——10 小时前的 user123328

编辑:

我得到它(有点)使用以下内容:

    def app(doc):

        x = df_algs['x-{}'.format(str(algorithm)[:3])]
        y = df_algs['y-{}'.format(str(algorithm)[:3])]
        # create the scatter plot


        if metric == 'LengthOfStayDaysNBR':
            color_mapper = linear_cmap(metric,palette=Spectral6,low=df_algs[metric].min(),high=df_algs[metric].max())
        else:
            color_mapper = factor_cmap(metric,palette=Spectral6,factors=df_algs[metric].unique())


        source = ColumnDataSource(dict(
            x = x
        ,   y = y
        ,   metric_ = df_algs[metric]))
        # create the scatter plot
        p = figure(tools=TOOLS, plot_width=600, plot_height=600, min_border=10, min_border_left=50,
                   toolbar_location="above", x_axis_location=None, y_axis_location=None,
                   title="Linked Histograms")
        p.select(BoxSelectTool).select_every_mousemove = False
        p.select(LassoSelectTool).select_every_mousemove = False

        r = p.scatter('x', 'y', source=source, fill_color = color_mapper, alpha=0.6)
    # 
        # create the horizontal histogram
        hhist, hedges = np.histogram(x, bins=20)
        hzeros = np.zeros(len(hedges)-1)
        hmax = max(hhist)*1.1

        LINE_ARGS = dict(color="#3A5785", line_color=None)

        ph = figure(toolbar_location=None, plot_width=p.plot_width, plot_height=200, x_range=p.x_range,
                    y_range=(-hmax, hmax), min_border=10, min_border_left=50, y_axis_location="right")
        ph.xgrid.grid_line_color = None
        ph.yaxis.major_label_orientation = np.pi/4
        ph.background_fill_color = "#fafafa"

        ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hhist, color="white", line_color="#3A5785")
        hh1 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.5, **LINE_ARGS)
        hh2 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.1, **LINE_ARGS)

        # create the vertical histogram
        vhist, vedges = np.histogram(y, bins=20)
        vzeros = np.zeros(len(vedges)-1)
        vmax = max(vhist)*1.1

        pv = figure(toolbar_location=None, plot_width=200, plot_height=p.plot_height, x_range=(-vmax, vmax),
                    y_range=p.y_range, min_border=10, y_axis_location="right")
        pv.ygrid.grid_line_color = None
        pv.xaxis.major_label_orientation = np.pi/4
        pv.background_fill_color = "#fafafa"

        pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vhist, color="white", line_color="#3A5785")
        vh1 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.5, **LINE_ARGS)
        vh2 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.1, **LINE_ARGS)

        layout = column(row(p, pv), row(ph, Spacer(width=200, height=200)))

        doc.add_root(layout)
        doc.title = "Selection Histogram"

        def update(attr, old, new):
            inds = np.array(new['1d']['indices'])
            if len(inds) == 0 or len(inds) == len(x):
                hhist1, hhist2 = hzeros, hzeros
                vhist1, vhist2 = vzeros, vzeros
            else:
                neg_inds = np.ones_like(x, dtype=np.bool)
                neg_inds[inds] = False
                hhist1, _ = np.histogram(x[inds], bins=hedges)
                vhist1, _ = np.histogram(y[inds], bins=vedges)
                hhist2, _ = np.histogram(x[neg_inds], bins=hedges)
                vhist2, _ = np.histogram(y[neg_inds], bins=vedges)

            hh1.data_source.data["top"]   =  hhist1
            hh2.data_source.data["top"]   = -hhist2
            vh1.data_source.data["right"] =  vhist1
            vh2.data_source.data["right"] = -vhist2

            df = df_algs.loc[df_algs.index.isin(inds)]
            df.drop(expected_metrics+metrics+['AgeNBR'],axis=1).mean().sort_values(ascending=False)[:25].plot(kind='Bar')
            plt.show()


        r.data_source.on_change('selected', update)

但是

        if metric == 'LengthOfStayDaysNBR':
            color_mapper = linear_cmap(metric,palette=Spectral6,low=df_algs[metric].min(),high=df_algs[metric].max())
        else:
            color_mapper = factor_cmap(metric,palette=Spectral6,factors=df_algs[metric].unique())

似乎破坏了代码。尝试对散点图进行颜色编码时,我得到“字形引用不存在的列名:{}”。

【问题讨论】:

    标签: python callback bokeh lasso-regression


    【解决方案1】:

    我不会依赖调用kernel.execute 的CustomJS 回调来执行此操作。我认为这是一种非常脆弱的做事方式,当以任意顺序重新执行单元格时,很容易造成混淆或不合理。此外,为了将来考虑,我不确定它是否会与下一代 JupyterLab 一起使用,因为 kernel.execute 可能不可用。

    相反,我会嵌入一个真正的Bokeh Server Application。 Bokeh 服务器的创建是为了通过定义和维护的协议在 Bokeh 的 JavaScript 和 Python 部分之间高效且稳健地同步数据,并提供基于任何一方的更改执行回调。

    这是嵌入在笔记本中的应用程序的截屏 gif,该应用程序根据中心图中的选择更新一对直方图。代码单元在 gif 下方给出。


    单元格 1

    import numpy as np
    from bokeh.io import output_notebook, show
    from bokeh.layouts import row, column
    from bokeh.models import BoxSelectTool, LassoSelectTool, Spacer
    from bokeh.plotting import figure, curdoc
    
    output_notebook()
    

    细胞 2

    x1 = np.random.normal(loc=5.0, size=400) * 100
    y1 = np.random.normal(loc=10.0, size=400) * 10
    
    x2 = np.random.normal(loc=5.0, size=800) * 50
    y2 = np.random.normal(loc=5.0, size=800) * 10
    
    x3 = np.random.normal(loc=55.0, size=200) * 10
    y3 = np.random.normal(loc=4.0, size=200) * 10
    
    x = np.concatenate((x1, x2, x3))
    y = np.concatenate((y1, y2, y3))
    
    TOOLS="pan,wheel_zoom,box_select,lasso_select,reset"
    

    细胞 3

    def app(doc):
        # create the scatter plot
        p = figure(tools=TOOLS, plot_width=600, plot_height=600, min_border=10, min_border_left=50,
                   toolbar_location="above", x_axis_location=None, y_axis_location=None,
                   title="Linked Histograms")
        p.background_fill_color = "#fafafa"
        p.select(BoxSelectTool).select_every_mousemove = False
        p.select(LassoSelectTool).select_every_mousemove = False
    
        r = p.scatter(x, y, size=3, color="#3A5785", alpha=0.6)
    
        # create the horizontal histogram
        hhist, hedges = np.histogram(x, bins=20)
        hzeros = np.zeros(len(hedges)-1)
        hmax = max(hhist)*1.1
    
        LINE_ARGS = dict(color="#3A5785", line_color=None)
    
        ph = figure(toolbar_location=None, plot_width=p.plot_width, plot_height=200, x_range=p.x_range,
                    y_range=(-hmax, hmax), min_border=10, min_border_left=50, y_axis_location="right")
        ph.xgrid.grid_line_color = None
        ph.yaxis.major_label_orientation = np.pi/4
        ph.background_fill_color = "#fafafa"
    
        ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hhist, color="white", line_color="#3A5785")
        hh1 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.5, **LINE_ARGS)
        hh2 = ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hzeros, alpha=0.1, **LINE_ARGS)
    
        # create the vertical histogram
        vhist, vedges = np.histogram(y, bins=20)
        vzeros = np.zeros(len(vedges)-1)
        vmax = max(vhist)*1.1
    
        pv = figure(toolbar_location=None, plot_width=200, plot_height=p.plot_height, x_range=(-vmax, vmax),
                    y_range=p.y_range, min_border=10, y_axis_location="right")
        pv.ygrid.grid_line_color = None
        pv.xaxis.major_label_orientation = np.pi/4
        pv.background_fill_color = "#fafafa"
    
        pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vhist, color="white", line_color="#3A5785")
        vh1 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.5, **LINE_ARGS)
        vh2 = pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vzeros, alpha=0.1, **LINE_ARGS)
    
        layout = column(row(p, pv), row(ph, Spacer(width=200, height=200)))
    
        doc.add_root(layout)
        doc.title = "Selection Histogram"
    
        def update(attr, old, new):
            inds = np.array(new['1d']['indices'])
            if len(inds) == 0 or len(inds) == len(x):
                hhist1, hhist2 = hzeros, hzeros
                vhist1, vhist2 = vzeros, vzeros
            else:
                neg_inds = np.ones_like(x, dtype=np.bool)
                neg_inds[inds] = False
                hhist1, _ = np.histogram(x[inds], bins=hedges)
                vhist1, _ = np.histogram(y[inds], bins=vedges)
                hhist2, _ = np.histogram(x[neg_inds], bins=hedges)
                vhist2, _ = np.histogram(y[neg_inds], bins=vedges)
    
            hh1.data_source.data["top"]   =  hhist1
            hh2.data_source.data["top"]   = -hhist2
            vh1.data_source.data["right"] =  vhist1
            vh2.data_source.data["right"] = -vhist2
    
        r.data_source.on_change('selected', update)
    

    细胞 4

    # set notebook_url appropriately
    show(app, notebook_url="http://localhost:8889")
    

    【讨论】:

    • 这看起来很有希望。提供一些背景知识:我正在尝试从包含许多特征的较大数据框中获取 x/y 坐标,选择散点图的子组,然后绘制(在条形图中)最大(20 个左右)特征的平均值对于子队列的指定 x/y 坐标。例如,假设您有 50 个特征(列)和 20 个数据点的子群组。我希望将剩余的 48 个要素的平均值绘制成条形图,条形图的高度代表要素的平均值。知道怎么做吗?
    • 此外:如果能够将实际的索引/xy 坐标返回到某个对象,即数据框、np.array、列表或其他任何东西中,那就太好了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 2022-01-24
    • 2014-09-13
    • 2015-09-28
    • 2019-08-11
    • 1970-01-01
    • 2013-06-27
    相关资源
    最近更新 更多