-1

I use the following function to setup a bokeh server programmatically.

def setup_bokeh_server(data):
'''
Sets up Bokeh Application instances on server.
'''

    def run_server(url_func_map):
        server = Server(url_func_map,
                    allow_websocket_origin=['localhost:8888',
                                            'localhost:5006'])
        server.start()
        server.io_loop.start()

    url_func_map = {}
    for name, app in data['bokeh_apps'].items():
        url_func_map['/'+name] = app

    p = multiprocessing.Process(target=run_server, args=(url_func_map,))
    p.start()
    p.join()

Before I setup the server I create Bokeh applications and add them to data['bokeh_apps'].

def setup_plot_data(data):
'''
Creates Bokeh Application to be rendered by server.
'''

    def plot_maker(doc, x=[], y=[], name=''):

        source = ColumnDataSource(data={'x':x, 'y':y})

        fig = figure(title=name)
        fig.line(x='x', y='y', source=source)

        doc.add_root(fig)
        return doc

    args_dict = {'1':{'x':[1,2,3,4],'y':[4,3,2,1],'name':'plot_1'},
                 '2':{'x':[1,2,3,4],'y':[4,3,2,1],'name':'plot_2'}}
    for args_num, args in args_dict.items():
        render_foo = lambda doc: plot_maker(doc, **args)
        handler = FunctionHandler(render_foo)
        app = Application(handler)
        data['bokeh_apps'][args['name']] = app

Using this approach results in the same plot being rendered on both bokeh server URL:s (the last Application to be added to data['bokeh_apps'] is rendered on both URL:s). However, when I skip the for loop and add the apps one at a time:

render_foo = lambda doc: plot_maker([1,2,3,4], [1,2,3,4], 'plot_1', doc)
handler = FunctionHandler(render_foo)
app = Application(handler)
data['bokeh_apps']['plot_1'] = app

render_foo = lambda doc: plot_maker([1,2,3,4], [4,3,2,1], 'plot_2', doc)
handler = FunctionHandler(render_foo)
app = Application(handler)
data['bokeh_apps']['plot_2'] = app

Everything is hunky-dory, I get individual plots on both URL:s. I'm curious why this happens and want to find out if I can avoid having to create all Applications and add them individually?

1 Answers1

-1

It doesn't have to do anything with Bokeh - you just experienced Python closures at work.

Consider running this small snippet, but first try to guess what it will print:

def f(idx):
    print(idx)


fs = []
for i in range(3):
    fs.append(lambda: f(i))

for fn in fs:
    fn()

More details can be found in this SO question.

Eugene Pakhomov
  • 9,309
  • 3
  • 27
  • 53