Getting Sliders to work with autoload_server on a Bokeh/Dango system

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):

document = Document()

document.add_root(plot)

document.title = suffix

with closing(push_session(document)) as session:

Get the script to pass into the template

script = autoload_server(None, session_id=session.id)

return script

and the slider is in the argument passed via plot as follows:

def update(attrname, old, new):

source.data = compute(sTime.value, params)

sTime = Slider(title=“Time (h)”, value=0, start=0, end=max(data[‘times’]), step=max(data[‘times’]) / 25)

sTime.on_change(‘value’, update)

update(None, None, None)

plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

Hi,

I’ve the exact same use case with a Flask app.

After a quick test and reading the docs, to use on_change event handlers you have to run your Python code with bokeh serve .

You can’t just send everything using autoload_server.

As I see it, you have 2 ways to do it:

  1. Put all your bokeh code in foo.py and run bokeh serve foo.py

In your django app, you just call autoload_server to embed the entire document.

def get_bokeh_script():

return autoload_server(model=None, app_path='/foo')

``

  1. If you want to keep the bokeh code in your django app, you have to use a CustomJS callback.

As I see it, the solution 1 makes it easier to add interaction to your plot.

The drawback is that anyone can access /foo on the bokeh server directly.

In my case, I have some user authentication in my Flask app I’d like to use.

I might get around by only allowing localhost to access the bokeh server.

Or I might go for solution 2. I haven’t decided yet.

Benjamin

···

Le vendredi 10 juin 2016 12:23:22 UTC, [email protected] a écrit :

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):

document = Document()

document.add_root(plot)

document.title = suffix

with closing(push_session(document)) as session:

Get the script to pass into the template

script = autoload_server(None, session_id=session.id)

return script

and the slider is in the argument passed via plot as follows:

def update(attrname, old, new):

source.data = compute(sTime.value, params)

sTime = Slider(title=“Time (h)”, value=0, start=0, end=max(data[‘times’]), step=max(data[‘times’]) / 25)

sTime.on_change(‘value’, update)

update(None, None, None)

plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

Right, just to add some comments from a different perspective, in case they are helpfiul:

If you want to run *actual python code* in response to widgets (sliders, buttons) or events like plot selections or range changes, then there has to be a python process somewhere for the code to run! The Bokeh server exists specifically to be that place where python code can run, in response to document UI events.

Now, it certainly possible to use CustomJS callbacks + AJAX calls + custom endpoints on a Flask/DJango server to do the same, but there you'd be taking on all the synchronization work that the Bokeh Server was designed to make easy.

One thing to note, is that in the upcoming 0.12 release (and recent dev builds) there is an option for a custom HTML template for a Bokeh app. So if you have a Single Page App that is "bokeh-centric" one option in some scenarios could be to just server everything from the Bokeh server.

Regarding the auth, because we are not experts, and because different people want to integrate with lots of different things, we decided to start simple and follow what I will call the "redis model". Which is to say, for "real" deployments, you'd want to put the Bokeh server on an internal network, and configure it only to communicate with the public-facing site via the internal network. These scenarios and some sample Nginx and Apache configs are in the user's guide. There is some interest and various proposals to incorporate some simple pluggable auth into the server. That could be fantastic, but this is an area where the community will have to lead.

Thanks,

Bryan

···

On Jun 17, 2016, at 7:15 AM, [email protected] wrote:

Hi,

I've the exact same use case with a Flask app.
After a quick test and reading the docs, to use on_change event handlers you have to run your Python code with bokeh serve <app>.
You can't just send everything using autoload_server.

As I see it, you have 2 ways to do it:

1. Put all your bokeh code in foo.py and run bokeh serve foo.py
In your django app, you just call autoload_server to embed the entire document.

def get_bokeh_script():

    return autoload_server(model=None, app_path='/foo')

2. If you want to keep the bokeh code in your django app, you have to use a CustomJS callback.

As I see it, the solution 1 makes it easier to add interaction to your plot.
The drawback is that anyone can access /foo on the bokeh server directly.
In my case, I have some user authentication in my Flask app I'd like to use.
I might get around by only allowing localhost to access the bokeh server.
Or I might go for solution 2. I haven't decided yet.

Benjamin

Le vendredi 10 juin 2016 12:23:22 UTC, [email protected] a écrit :
Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):
    document = Document()
    document.add_root(plot)
    document.title = suffix

    with closing(push_session(document)) as session:
        # Get the script to pass into the template
        script = autoload_server(None, session_id=session.id)

    return script

and the slider is in the argument passed via plot as follows:
   
    def update(attrname, old, new):
        source.data = compute(sTime.value, params)
   
   sTime = Slider(title="Time (h)", value=0, start=0, end=max(data['times']), step=max(data['times']) / 25)
   sTime.on_change('value', update)

    update(None, None, None)

    plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/a8626b76-f536-42b1-b441-d1b9031504b3%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

As described in the User's Guide, the "bokeh.client" way of doing things is really only suited for local exploration. It has a number of inherent drawbacks compared to the "bokeh serve app.py" approach. The number one thing is that using sessions, you have to end with a blocking call to "session.loop_until_closed" to service the events of the session. That is pretty much a non-starter in a web framework. Perhaps you could run that blocking code in a thread (I've never tried) or certainly you could spawn a new python process for every connection, but that seems pretty messy and fragile too.

If you just need a "bokeh-centric" single page app, in 0.12 you will be able to just serve that directly from the Bokeh server itself by supplying a custom template. If you do need to "embed" in a larger application on Flask/Django then there's alot of information, example setup and config in the User's Guide, and a full "deployable" repository for the demoplots site available on GitHub. (or just using iframes from the bokeh server would be another idea, but not always appropriate)

Thanks,

Bryan

···

On Jun 10, 2016, at 1:26 AM, [email protected] wrote:

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):
    document = Document()
    document.add_root(plot)
    document.title = suffix

    with closing(push_session(document)) as session:
        # Get the script to pass into the template
        script = autoload_server(None, session_id=session.id)

    return script

and the slider is in the argument passed via plot as follows:
   
    def update(attrname, old, new):
        source.data = compute(sTime.value, params)
   
   sTime = Slider(title="Time (h)", value=0, start=0, end=max(data['times']), step=max(data['times']) / 25)
   sTime.on_change('value', update)

    update(None, None, None)

    plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/49201d7d-1480-4f32-aeb7-b0eb01f79474%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Hi,

2. If you want to keep the bokeh code in your django app, you have to use a CustomJS callback.

As I see it, the solution 1 makes it easier to add interaction to your plot.
The drawback is that anyone can access /foo on the bokeh server directly.
In my case, I have some user authentication in my Flask app I'd like to use.
I might get around by only allowing localhost to access the bokeh server.
Or I might go for solution 2. I haven't decided yet.

There is a feature --session-ids=external-signed specifically designed
to handle this scenario. What this does is that while anyone can
connect to `bokeh serve`, it won't create a session (and thus won't
serve your apps or create documents) unless the person connecting has
a pre-signed session ID. Start both Django and `bokeh serve` with the
same BOKEH_SECRET_KEY env variable. In your django app use
bokeh.util.session_id.generate_session_id() to make a session ID, and
autoload_server(session_id=generated_id). Then the autoloaded session
should work, BUT someone connecting to bokeh server directly will get
nothing.
Be careful to generate a new session ID for every browser tab that
connects, if a bunch of users share one session ID it will be weird
and broken.

Havoc

···

On Fri, Jun 17, 2016 at 8:15 AM, <[email protected]> wrote:

Nice feature. It does fit my use case.

I will probably give that a try.

Thanks!

Benjamin

···

Le vendredi 17 juin 2016 17:18:11 UTC+2, Havoc Pennington a écrit :

There is a feature --session-ids=external-signed specifically designed

to handle this scenario. What this does is that while anyone can

connect to bokeh serve, it won’t create a session (and thus won’t

serve your apps or create documents) unless the person connecting has

a pre-signed session ID. Start both Django and bokeh serve with the

same BOKEH_SECRET_KEY env variable. In your django app use

bokeh.util.session_id.generate_session_id() to make a session ID, and

autoload_server(session_id=generated_id). Then the autoloaded session

should work, BUT someone connecting to bokeh server directly will get

nothing.

Be careful to generate a new session ID for every browser tab that

connects, if a bunch of users share one session ID it will be weird

and broken.

Regarding auth. I made a demo

  that integrates bokeh and django including integrating the auth

specifically to show off this more complex kind of integration

  along the way I make a bunch of mistakes and learned a bunch of

stuff about things like --session-ids=external-signed and I wrote
it up here:

Best,

BIrd

···

https://github.com/bokeh/bokeh-demos/tree/master/happinesshttps://github.com/bokeh/bokeh-demos/blob/master/happiness/Building%20happiness.ipynb
On 6/17/16 5:15 AM, wrote:

[email protected]

    As I see it, the solution 1 makes it easier to add

interaction to your plot.

    The drawback is that anyone can access /foo on the bokeh

server directly.

    In my case, I have some user authentication in my Flask app

I’d like to use.

    I might get around by only allowing localhost to access the

bokeh server.

Or I might go for solution 2. I haven’t decided yet.


Sarah Bird
Developer, Bokeh

    [
      ![Continuum Analytics](http://docs.continuum.io/_static/img/ContinuumWordmark.png)
    ](http://continuum.io)

Yes, I looked at the demo. It was very interesting as well to read what your learned.

Thanks for sharing!

My use case is less complex. I basically just want to allow only some users to access a view with Bokeh plots (based on roles).

Nothing to share between users. So –session-ids=external-signed is perfect.

But I need some sliders. So it’s probably easier to run most of the Bokeh code on the server as suggested by Bryan.

Benjamin

PS: It’s your PyCon2015 talk that made me discover Bokeh and want to try it. Very nice talk :slight_smile:

···

Le samedi 18 juin 2016 04:07:58 UTC+2, Sarah Bird a écrit :

  Regarding auth. I made a demo

https://github.com/bokeh/bokeh-demos/tree/master/happiness

  that integrates bokeh and django including integrating the auth

specifically to show off this more complex kind of integration

  along the way I make a bunch of mistakes and learned a bunch of

stuff about things like --session-ids=external-signed and I wrote
it up here:
https://github.com/bokeh/bokeh-demos/blob/master/happiness/Building%20happiness.ipynb

Best,

BIrd

Hi,

Did you figure out how to get this working? I’m at the same spot with a drop down. I followed Sarah’s Happiness app except I’m using function views instead of CBVs. So, my code is very similar to yours for the callbacks and get_bokeh_script. The plot gets embedded in my page (Django), but on changing the dropdown, the update function does not get fired.

Thanks,

Charles

···

On Friday, June 10, 2016 at 7:23:22 AM UTC-5, [email protected] wrote:

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):

document = Document()

document.add_root(plot)

document.title = suffix

with closing(push_session(document)) as session:

Get the script to pass into the template

script = autoload_server(None, session_id=session.id)

return script

and the slider is in the argument passed via plot as follows:

def update(attrname, old, new):

source.data = compute(sTime.value, params)

sTime = Slider(title=“Time (h)”, value=0, start=0, end=max(data[‘times’]), step=max(data[‘times’]) / 25)

sTime.on_change(‘value’, update)

update(None, None, None)

plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

I should prolly elaborate:

I am not interacting with the model. I am doing some calculations with scikit-learn (at least for this part of the webapp) in the view and plotting results. It looks like Sarah is updating the session on a Happiness model save method call. I think I might need to use a function similar to update_bokeh_sessions to change the source. But the problem still lies with getting django and bokeh talking to each other to know that select.on_change() happened.

···

On Friday, November 4, 2016 at 9:26:57 AM UTC-5, [email protected] wrote:

Hi,

Did you figure out how to get this working? I’m at the same spot with a drop down. I followed Sarah’s Happiness app except I’m using function views instead of CBVs. So, my code is very similar to yours for the callbacks and get_bokeh_script. The plot gets embedded in my page (Django), but on changing the dropdown, the update function does not get fired.

Thanks,

Charles

On Friday, June 10, 2016 at 7:23:22 AM UTC-5, [email protected] wrote:

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):

document = Document()

document.add_root(plot)

document.title = suffix

with closing(push_session(document)) as session:

Get the script to pass into the template

script = autoload_server(None, session_id=session.id)

return script

and the slider is in the argument passed via plot as follows:

def update(attrname, old, new):

source.data = compute(sTime.value, params)

sTime = Slider(title=“Time (h)”, value=0, start=0, end=max(data[‘times’]), step=max(data[‘times’]) / 25)

sTime.on_change(‘value’, update)

update(None, None, None)

plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

If you not running the app *in* a bokeh server (i.e. you are not running "bokeh serve myapp.py", etc.) then the other client process that connects to the server with bokeh.client and push_session (which sounds like what you are trying to do inside Django) *must* run the blocking call session.loop_until_closed(). This is what actually keeps the original process running and servicing the callbacks.

Of course, blocking inside a Django reponse is probably not reasonable; this is why running a "native server app" has inherent advantages over using bokeh.client. I think some folks have had success with these options:

* executing the plotting and session.loop_until_closed in a new thread in django
* effectively running "bokeh serve myapp" programmatically from within django (see other message chains on the ML)
* running "bokeh serve myapp" separately outside django

Thanks,

Bryan

···

On Nov 4, 2016, at 10:26 AM, [email protected] wrote:

I should prolly elaborate:

I am not interacting with the model. I am doing some calculations with scikit-learn (at least for this part of the webapp) in the view and plotting results. It looks like Sarah is updating the session on a Happiness model save method call. I think I might need to use a function similar to update_bokeh_sessions to change the source. But the problem still lies with getting django and bokeh talking to each other to know that select.on_change() happened.

On Friday, November 4, 2016 at 9:26:57 AM UTC-5, [email protected] wrote:
Hi,

Did you figure out how to get this working? I'm at the same spot with a drop down. I followed Sarah's Happiness app except I'm using function views instead of CBVs. So, my code is very similar to yours for the callbacks and get_bokeh_script. The plot gets embedded in my page (Django), but on changing the dropdown, the update function does not get fired.

Thanks,
Charles

On Friday, June 10, 2016 at 7:23:22 AM UTC-5, [email protected] wrote:
Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):
    document = Document()
    document.add_root(plot)
    document.title = suffix

    with closing(push_session(document)) as session:
        # Get the script to pass into the template
        script = autoload_server(None, session_id=session.id)

    return script

and the slider is in the argument passed via plot as follows:
   
    def update(attrname, old, new):
        source.data = compute(sTime.value, params)
   
   sTime = Slider(title="Time (h)", value=0, start=0, end=max(data['times']), step=max(data['times']) / 25)
   sTime.on_change('value', update)

    update(None, None, None)

    plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/57089018-ab72-4ded-aefb-68b002719336%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Thanks for the quick reply. I’m new to web programming and django and bokeh. I’ll try to use session.loop_until_closed() in a new thread. I can get the other two options to work. But I wanna keep it contained in the app and also have the sessions closed out when the window is closed or navigated away from. Thanks again, Bokeh is awesome!

···

On Friday, November 4, 2016 at 11:37:09 AM UTC-5, Bryan Van de ven wrote:

If you not running the app in a bokeh server (i.e. you are not running “bokeh serve myapp.py”, etc.) then the other client process that connects to the server with bokeh.client and push_session (which sounds like what you are trying to do inside Django) must run the blocking call session.loop_until_closed(). This is what actually keeps the original process running and servicing the callbacks.

Of course, blocking inside a Django reponse is probably not reasonable; this is why running a “native server app” has inherent advantages over using bokeh.client. I think some folks have had success with these options:

  • executing the plotting and session.loop_until_closed in a new thread in django

  • effectively running “bokeh serve myapp” programmatically from within django (see other message chains on the ML)

  • running “bokeh serve myapp” separately outside django

Thanks,

Bryan

On Nov 4, 2016, at 10:26 AM, [email protected] wrote:

I should prolly elaborate:

I am not interacting with the model. I am doing some calculations with scikit-learn (at least for this part of the webapp) in the view and plotting results. It looks like Sarah is updating the session on a Happiness model save method call. I think I might need to use a function similar to update_bokeh_sessions to change the source. But the problem still lies with getting django and bokeh talking to each other to know that select.on_change() happened.

On Friday, November 4, 2016 at 9:26:57 AM UTC-5, [email protected] wrote:

Hi,

Did you figure out how to get this working? I’m at the same spot with a drop down. I followed Sarah’s Happiness app except I’m using function views instead of CBVs. So, my code is very similar to yours for the callbacks and get_bokeh_script. The plot gets embedded in my page (Django), but on changing the dropdown, the update function does not get fired.

Thanks,

Charles

On Friday, June 10, 2016 at 7:23:22 AM UTC-5, [email protected] wrote:

Hi everyone,

I have a use case where I would like an interactive plot controlled by a slider embedded in a Django webserver (using autoload_server). However, the slider is not responding, most likely due to a lack of polling of the client. What is the proper way to poll for responses when using autoload_server? Where would you add session.loop_until_closed()? When I add it, the loop blocks everything.

The slider has working callbacks set up and it works when served on the bokeh server. This is the function i use to communicate with the server:

def get_bokeh_script(plot, suffix):

document = Document()
document.add_root(plot)
document.title = suffix
with closing(push_session(document)) as session:
    # Get the script to pass into the template
    script = autoload_server(None, session_id=[session.id](http://session.id))
return script

and the slider is in the argument passed via plot as follows:

def update(attrname, old, new):
    source.data = compute(sTime.value, params)

sTime = Slider(title=“Time (h)”, value=0, start=0, end=max(data[‘times’]), step=max(data[‘times’]) / 25)

sTime.on_change(‘value’, update)

update(None, None, None)
plot= VBoxForm(release, time_plot, sTime)

where release and time_plot are Figure objects.

Thanks,

Hok Hei


You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.

To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

To post to this group, send email to [email protected].

To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/57089018-ab72-4ded-aefb-68b002719336%40continuum.io.

For more options, visit https://groups.google.com/a/continuum.io/d/optout.