Jinja2 template with CustomJS only renders first component on load

Bokeh 0.13 with python 3.6 (anaconda) 64bit on Win10.

I tried using the example from bokeh/examples/embed/embed_multiple.py to embed bokeh components into a static html page and it works.

However, when I add CustomJS interactions to the components, only the first one correctly renders in the browser.

The other components are still there but somehow aren’t rendered correctly.

renderproblem.png

The example code is:

import io

from jinja2 import Template

from bokeh.embed import components

from bokeh.resources import INLINE

from bokeh.util.browser import view

from bokeh.layouts import column

from bokeh.models import CustomJS

from bokeh.models.widgets import Toggle

from bokeh.core.properties import Int

from bokeh.util.compiler import CoffeeScript

class TechToggle(Toggle):

implementation = CoffeeScript("""

import {Toggle, ToggleView} from “models/widgets/toggle”

import * as p from “core/properties”

export class TechToggleView extends ToggleView

render: () ->

super()

export class TechToggle extends Toggle

type = “TechToggle”

default_view = TechToggleView

@define {

techid: [ p.Int, 0 ]

}

“”")

techid = Int(default=0)

buttonstates = [0,0]

toggle0 = TechToggle(techid=0)

toggle1 = TechToggle(techid=1)

#toggles = [toggle0,toggle1]

toggles = {0:toggle0, 1:toggle1}

togglecallback0 = CustomJS(args=dict(toggles=toggles), code="""

console.log(cb_obj.active)

console.log(toggles)

console.log(cb_obj)

if (cb_obj.active == true) {

toggles[1].disabled=true;

} else {

toggles[1].disabled=false;

}

“”")

toggle0.callback = togglecallback0

togglecallback1 = CustomJS(args=dict(toggles=toggles), code="""

console.log(cb_obj.active)

console.log(toggles)

console.log(cb_obj)

if (cb_obj.active == true) {

toggles[0].disabled=true;

} else {

toggles[0].disabled=false;

}

“”")

toggle1.callback = togglecallback1

layout = column(toggle0, toggle1)

plots = {‘Red’: toggle0, ‘Blue’: toggle1}

script, div = components(plots)

template = Template(’’’

Bokeh Scatter Plots

{{ resources }}

{{ script }}

.embed-wrapper { width: 50%; height: 400px; margin: auto; }

{% for key in div.keys() %}

{{ div[key] }}

{% endfor %}

‘’’)

resources = INLINE.render()

filename = ‘embed_multiple.html’

html = template.render(resources=resources,

script=script,

div=div)

with io.open(filename, mode=‘w’, encoding=‘utf-8’) as f:

f.write(html)

view(filename)

I’ll try and see if the other templating examples can make this work.

What seems to trigger this is the inclusion of the components as args in CustomJS.

Thanks

Hi,

I'm not sure to what extent passing in a dict as a value for one of the args is actually supported. It's definitely not what I had in mind, which was only ever:

  args=dict(a=model_a, b=model_b, ...)

i.e. a mapping of names to individual models. However, I see that your code functions when passing the list instead of a dict, and I think another dev may have specifically made that case supportable, so my recommendation is simply to do that, and not try to pass a dict as a value for an arg.

Thanks,

Bryan

···

On Aug 10, 2018, at 13:05, [email protected] wrote:

Bokeh 0.13 with python 3.6 (anaconda) 64bit on Win10.

I tried using the example from bokeh/examples/embed/embed_multiple.py to embed bokeh components into a static html page and it works.

However, when I add CustomJS interactions to the components, only the first one correctly renders in the browser.
The other components are still there but somehow aren't rendered correctly.

<renderproblem.png>

The example code is:

import io
from jinja2 import Template

from bokeh.embed import components
from bokeh.resources import INLINE
from bokeh.util.browser import view

from bokeh.layouts import column
from bokeh.models import CustomJS
from bokeh.models.widgets import Toggle
from bokeh.core.properties import Int
from bokeh.util.compiler import CoffeeScript

class TechToggle(Toggle):

    __implementation__ = CoffeeScript("""
import {Toggle, ToggleView} from "models/widgets/toggle"
import * as p from "core/properties"
export class TechToggleView extends ToggleView
  render: () ->
    super()

export class TechToggle extends Toggle
  type = "TechToggle"
  default_view = TechToggleView
  @define {
    techid: [ p.Int, 0 ]
  }
""")
    techid = Int(default=0)

buttonstates = [0,0]

toggle0 = TechToggle(techid=0)
toggle1 = TechToggle(techid=1)
#toggles = [toggle0,toggle1]
toggles = {0:toggle0, 1:toggle1}
togglecallback0 = CustomJS(args=dict(toggles=toggles), code="""
       console.log(cb_obj.active)
       console.log(toggles)
       console.log(cb_obj)
       if (cb_obj.active == true) {
           toggles[1].disabled=true;
       } else {
           toggles[1].disabled=false;
       }
    """)
toggle0.callback = togglecallback0
togglecallback1 = CustomJS(args=dict(toggles=toggles), code="""
       console.log(cb_obj.active)
       console.log(toggles)
       console.log(cb_obj)
       if (cb_obj.active == true) {
           toggles[0].disabled=true;
       } else {
           toggles[0].disabled=false;
       }
    """)
toggle1.callback = togglecallback1
layout = column(toggle0, toggle1)
plots = {'Red': toggle0, 'Blue': toggle1}

script, div = components(plots)

template = Template('''<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Bokeh Scatter Plots</title>
        {{ resources }}
        {{ script }}
        <style>
            .embed-wrapper {
                width: 50%;
                height: 400px;
                margin: auto;
            }
        </style>
    </head>
    <body>
        {% for key in div.keys() %}
            <div class="embed-wrapper">
            {{ div[key] }}
            </div>
        {% endfor %}
    </body>
</html>
''')

resources = INLINE.render()

filename = 'embed_multiple.html'

html = template.render(resources=resources,
                       script=script,
                       div=div)

with io.open(filename, mode='w', encoding='utf-8') as f:
    f.write(html)

view(filename)

I'll try and see if the other templating examples can make this work.
What seems to trigger this is the inclusion of the components as args in CustomJS.

Thanks

--
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/e289a04e-c418-44c5-8fd0-74eaaf4ffeea%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
<renderproblem.png>

Thanks for the quick reply!

Passing a list is actually what I tried first as you can see by the commented out line.

I’ve tried:

args=[model_a, model_b ]
and I get a:

ValueError: expected an element of Dict(String, AnyRef), got [TechToggle(id=‘e0fa2e1f-b76a-4243-ae3a-fd9e19b90dbf’, …), TechToggle(id=‘318f4e07-5ae1-4a37-98d6-22409f77ac1f’, …)]

which is why I ended up using:

args=dict(models=dict(a=model_a, b=model_b)) to make the JS selection easier, because the plan is to have a large array of buttons eventually.

however even when I try:

args=dict(a=toggle0,b=toggle1)

it still only renders the first toggle.

How do I pass a list instead of a dict?

I’ve already tried the following signature too:

args=dict(a=[toggle0,toggle1])

and it also only renders the first toggle.

Thanks for the help

···

On Friday, August 10, 2018 at 4:17:02 PM UTC-4, Bryan Van de ven wrote:

Hi,

I’m not sure to what extent passing in a dict as a value for one of the args is actually supported. It’s definitely not what I had in mind, which was only ever:

    args=dict(a=model_a, b=model_b, ...)

i.e. a mapping of names to individual models. However, I see that your code functions when passing the list instead of a dict, and I think another dev may have specifically made that case supportable, so my recommendation is simply to do that, and not try to pass a dict as a value for an arg.

Thanks,

Bryan

On Aug 10, 2018, at 13:05, [email protected] wrote:

Bokeh 0.13 with python 3.6 (anaconda) 64bit on Win10.

I tried using the example from bokeh/examples/embed/embed_multiple.py to embed bokeh components into a static html page and it works.

However, when I add CustomJS interactions to the components, only the first one correctly renders in the browser.

The other components are still there but somehow aren’t rendered correctly.

<renderproblem.png>

The example code is:

import io

from jinja2 import Template

from bokeh.embed import components

from bokeh.resources import INLINE

from bokeh.util.browser import view

from bokeh.layouts import column

from bokeh.models import CustomJS

from bokeh.models.widgets import Toggle

from bokeh.core.properties import Int

from bokeh.util.compiler import CoffeeScript

class TechToggle(Toggle):

__implementation__ = CoffeeScript("""

import {Toggle, ToggleView} from “models/widgets/toggle”

import * as p from “core/properties”

export class TechToggleView extends ToggleView

render: () ->
super()

export class TechToggle extends Toggle
type = “TechToggle”

default_view = TechToggleView

@define {

techid:   [ p.Int, 0 ]

}

“”")

techid = Int(default=0)

buttonstates = [0,0]

toggle0 = TechToggle(techid=0)

toggle1 = TechToggle(techid=1)

#toggles = [toggle0,toggle1]

toggles = {0:toggle0, 1:toggle1}

togglecallback0 = CustomJS(args=dict(toggles=toggles), code="""

   console.log(cb_obj.active)  
   console.log(toggles)
   console.log(cb_obj)
   if (cb_obj.active == true) {
       toggles[1].disabled=true;
   } else {
       toggles[1].disabled=false;
   }
""")

toggle0.callback = togglecallback0

togglecallback1 = CustomJS(args=dict(toggles=toggles), code="""

   console.log(cb_obj.active)  
   console.log(toggles)
   console.log(cb_obj)
   if (cb_obj.active == true) {
       toggles[0].disabled=true;
   } else {
       toggles[0].disabled=false;
   }
""")

toggle1.callback = togglecallback1

layout = column(toggle0, toggle1)

plots = {‘Red’: toggle0, ‘Blue’: toggle1}

script, div = components(plots)

template = Template(’’’

<head>
    <meta charset="utf-8">
    <title>Bokeh Scatter Plots</title>
    {{ resources }}
    {{ script }}
    <style>
        .embed-wrapper {
            width: 50%;
            height: 400px;
            margin: auto;
        }
    </style>
</head>
<body>
    {% for key in div.keys() %}
        <div class="embed-wrapper">
        {{ div[key] }}
        </div>
    {% endfor %}
</body>

‘’’)

resources = INLINE.render()

filename = ‘embed_multiple.html’

html = template.render(resources=resources,

                   script=script,
                   div=div)

with io.open(filename, mode=‘w’, encoding=‘utf-8’) as f:

f.write(html)

view(filename)

I’ll try and see if the other templating examples can make this work.

What seems to trigger this is the inclusion of the components as args in CustomJS.

Thanks


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/e289a04e-c418-44c5-8fd0-74eaaf4ffeea%40continuum.io.

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

<renderproblem.png>

Hi,

Well, when I did

  args=dict(a=[toggle0,toggle1])

I saw both buttons, which is why I suggested that approach. However, at this point, if that is not working for you, it's probably just time to submit a GitHub issue with as much information as possible. Unfortunately I don't have any workaround to suggest other than to map names to individual toggles in the args dict.

Thanks,

Bryan

···

On Aug 10, 2018, at 13:52, [email protected] wrote:

Thanks for the quick reply!

Passing a list is actually what I tried first as you can see by the commented out line.
I've tried:
args=[model_a, model_b ]
and I get a:
ValueError: expected an element of Dict(String, AnyRef), got [TechToggle(id='e0fa2e1f-b76a-4243-ae3a-fd9e19b90dbf', ...), TechToggle(id='318f4e07-5ae1-4a37-98d6-22409f77ac1f', ...)]

which is why I ended up using:
args=dict(models=dict(a=model_a, b=model_b)) to make the JS selection easier, because the plan is to have a large array of buttons eventually.

however even when I try:

args=dict(a=toggle0,b=toggle1)

it still only renders the first toggle.
How do I pass a list instead of a dict?
I've already tried the following signature too:

args=dict(a=[toggle0,toggle1])

and it also only renders the first toggle.

Thanks for the help

On Friday, August 10, 2018 at 4:17:02 PM UTC-4, Bryan Van de ven wrote:
Hi,

I'm not sure to what extent passing in a dict as a value for one of the args is actually supported. It's definitely not what I had in mind, which was only ever:

        args=dict(a=model_a, b=model_b, ...)

i.e. a mapping of names to individual models. However, I see that your code functions when passing the list instead of a dict, and I think another dev may have specifically made that case supportable, so my recommendation is simply to do that, and not try to pass a dict as a value for an arg.

Thanks,

Bryan

> On Aug 10, 2018, at 13:05, [email protected] wrote:
>
> Bokeh 0.13 with python 3.6 (anaconda) 64bit on Win10.
>
> I tried using the example from bokeh/examples/embed/embed_multiple.py to embed bokeh components into a static html page and it works.
>
> However, when I add CustomJS interactions to the components, only the first one correctly renders in the browser.
> The other components are still there but somehow aren't rendered correctly.
>
> <renderproblem.png>
>
>
> The example code is:
>
> import io
> from jinja2 import Template
>
> from bokeh.embed import components
> from bokeh.resources import INLINE
> from bokeh.util.browser import view
>
> from bokeh.layouts import column
> from bokeh.models import CustomJS
> from bokeh.models.widgets import Toggle
> from bokeh.core.properties import Int
> from bokeh.util.compiler import CoffeeScript
>
> class TechToggle(Toggle):
>
> __implementation__ = CoffeeScript("""
> import {Toggle, ToggleView} from "models/widgets/toggle"
> import * as p from "core/properties"
> export class TechToggleView extends ToggleView
> render: () ->
> super()
>
> export class TechToggle extends Toggle
> type = "TechToggle"
> default_view = TechToggleView
> @define {
> techid: [ p.Int, 0 ]
> }
> """)
> techid = Int(default=0)
>
> buttonstates = [0,0]
>
>
> toggle0 = TechToggle(techid=0)
> toggle1 = TechToggle(techid=1)
> #toggles = [toggle0,toggle1]
> toggles = {0:toggle0, 1:toggle1}
> togglecallback0 = CustomJS(args=dict(toggles=toggles), code="""
> console.log(cb_obj.active)
> console.log(toggles)
> console.log(cb_obj)
> if (cb_obj.active == true) {
> toggles[1].disabled=true;
> } else {
> toggles[1].disabled=false;
> }
> """)
> toggle0.callback = togglecallback0
> togglecallback1 = CustomJS(args=dict(toggles=toggles), code="""
> console.log(cb_obj.active)
> console.log(toggles)
> console.log(cb_obj)
> if (cb_obj.active == true) {
> toggles[0].disabled=true;
> } else {
> toggles[0].disabled=false;
> }
> """)
> toggle1.callback = togglecallback1
> layout = column(toggle0, toggle1)
> plots = {'Red': toggle0, 'Blue': toggle1}
>
> script, div = components(plots)
>
> template = Template('''<!DOCTYPE html>
> <html lang="en">
> <head>
> <meta charset="utf-8">
> <title>Bokeh Scatter Plots</title>
> {{ resources }}
> {{ script }}
> <style>
> .embed-wrapper {
> width: 50%;
> height: 400px;
> margin: auto;
> }
> </style>
> </head>
> <body>
> {% for key in div.keys() %}
> <div class="embed-wrapper">
> {{ div[key] }}
> </div>
> {% endfor %}
> </body>
> </html>
> ''')
>
> resources = INLINE.render()
>
> filename = 'embed_multiple.html'
>
> html = template.render(resources=resources,
> script=script,
> div=div)
>
> with io.open(filename, mode='w', encoding='utf-8') as f:
> f.write(html)
>
> view(filename)
>
>
> I'll try and see if the other templating examples can make this work.
> What seems to trigger this is the inclusion of the components as args in CustomJS.
>
> Thanks
>
> --
> 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/e289a04e-c418-44c5-8fd0-74eaaf4ffeea%40continuum.io.
> For more options, visit https://groups.google.com/a/continuum.io/d/optout.
> <renderproblem.png>

--
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/30eee0c1-f685-43c4-82a5-c979e3296fa1%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Strange that that worked for you. I tried again and no dice.
I’m wondering if that is a configuration issue on my side then.

I’ve also tried rendering with file_html() and it works correctly if the models go through the models input.

However as soon as I attempt to render them through additional jinja variables in the template_variables dict, it again only renders the first button.
I’ll submit an issue.

Thanks

···

On Friday, August 10, 2018 at 5:24:14 PM UTC-4, Bryan Van de ven wrote:

Hi,

Well, when I did

    args=dict(a=[toggle0,toggle1])

I saw both buttons, which is why I suggested that approach. However, at this point, if that is not working for you, it’s probably just time to submit a GitHub issue with as much information as possible. Unfortunately I don’t have any workaround to suggest other than to map names to individual toggles in the args dict.

Thanks,

Bryan

On Aug 10, 2018, at 13:52, [email protected] wrote:

Thanks for the quick reply!

Passing a list is actually what I tried first as you can see by the commented out line.

I’ve tried:

args=[model_a, model_b ]

and I get a:

ValueError: expected an element of Dict(String, AnyRef), got [TechToggle(id=‘e0fa2e1f-b76a-4243-ae3a-fd9e19b90dbf’, …), TechToggle(id=‘318f4e07-5ae1-4a37-98d6-22409f77ac1f’, …)]

which is why I ended up using:

args=dict(models=dict(a=model_a, b=model_b)) to make the JS selection easier, because the plan is to have a large array of buttons eventually.

however even when I try:

args=dict(a=toggle0,b=toggle1)

it still only renders the first toggle.

How do I pass a list instead of a dict?

I’ve already tried the following signature too:

args=dict(a=[toggle0,toggle1])

and it also only renders the first toggle.

Thanks for the help

On Friday, August 10, 2018 at 4:17:02 PM UTC-4, Bryan Van de ven wrote:

Hi,

I’m not sure to what extent passing in a dict as a value for one of the args is actually supported. It’s definitely not what I had in mind, which was only ever:

    args=dict(a=model_a, b=model_b, ...)

i.e. a mapping of names to individual models. However, I see that your code functions when passing the list instead of a dict, and I think another dev may have specifically made that case supportable, so my recommendation is simply to do that, and not try to pass a dict as a value for an arg.

Thanks,

Bryan

On Aug 10, 2018, at 13:05, [email protected] wrote:

Bokeh 0.13 with python 3.6 (anaconda) 64bit on Win10.

I tried using the example from bokeh/examples/embed/embed_multiple.py to embed bokeh components into a static html page and it works.

However, when I add CustomJS interactions to the components, only the first one correctly renders in the browser.
The other components are still there but somehow aren’t rendered correctly.

<renderproblem.png>

The example code is:

import io
from jinja2 import Template

from bokeh.embed import components
from bokeh.resources import INLINE
from bokeh.util.browser import view

from bokeh.layouts import column
from bokeh.models import CustomJS
from bokeh.models.widgets import Toggle
from bokeh.core.properties import Int
from bokeh.util.compiler import CoffeeScript

class TechToggle(Toggle):

__implementation__ = CoffeeScript("""

import {Toggle, ToggleView} from “models/widgets/toggle”
import * as p from “core/properties”
export class TechToggleView extends ToggleView
render: () ->
super()

export class TechToggle extends Toggle
type = “TechToggle”
default_view = TechToggleView
@define {
techid: [ p.Int, 0 ]
}
“”")
techid = Int(default=0)

buttonstates = [0,0]

toggle0 = TechToggle(techid=0)
toggle1 = TechToggle(techid=1)
#toggles = [toggle0,toggle1]
toggles = {0:toggle0, 1:toggle1}
togglecallback0 = CustomJS(args=dict(toggles=toggles), code="""
console.log(cb_obj.active)
console.log(toggles)
console.log(cb_obj)
if (cb_obj.active == true) {
toggles[1].disabled=true;
} else {
toggles[1].disabled=false;
}
“”")
toggle0.callback = togglecallback0
togglecallback1 = CustomJS(args=dict(toggles=toggles), code="""
console.log(cb_obj.active)
console.log(toggles)
console.log(cb_obj)
if (cb_obj.active == true) {
toggles[0].disabled=true;
} else {
toggles[0].disabled=false;
}
“”")
toggle1.callback = togglecallback1
layout = column(toggle0, toggle1)
plots = {‘Red’: toggle0, ‘Blue’: toggle1}

script, div = components(plots)

template = Template(’’’

Bokeh Scatter Plots {{ resources }} {{ script }} .embed-wrapper { width: 50%; height: 400px; margin: auto; } {% for key in div.keys() %}
{{ div[key] }}
{% endfor %} ''')

resources = INLINE.render()

filename = ‘embed_multiple.html’

html = template.render(resources=resources,
script=script,
div=div)

with io.open(filename, mode=‘w’, encoding=‘utf-8’) as f:
f.write(html)

view(filename)

I’ll try and see if the other templating examples can make this work.
What seems to trigger this is the inclusion of the components as args in CustomJS.

Thanks


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/e289a04e-c418-44c5-8fd0-74eaaf4ffeea%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
<renderproblem.png>


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/30eee0c1-f685-43c4-82a5-c979e3296fa1%40continuum.io.

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