Select widget conflicting with CDN and Select components

I have developed a COVID19 Dashboard and have integrated Google Analytics to the dashboard as it is deployed on http://covid19analysis.live .

I have used components() to append them in index.html file under Templates. It is functioning perfectly with Tabs but when I add Select widget to the existing tab, the dashboard opens on bokeh serve but the Select options aren’t updating the plot. When I remove the below components, the Select widget values are updating the plot as expected:

script, div = components(tabs, CDN)

curdoc().template_variables["script"] = script
curdoc().template_variables["div"] = div  

I have to update {{script | safe }} and {{div|safe}} in index.html so, Google Analytics is functional.

Is there any way, I can fix this?

PS - I am new to Python and a newly become fan of Bokeh.

Thank you.

@akashagl92 The Bokeh server keeps only keeps objects in sync that are directly or indirectly added via curdoc().add_root(...). The components API is intended for standalone (i.e. not Bokeh server) content, and is not really intended to be used in a Bokeh server app. Using it circumvents all the machinery that keeps the Python and JavaScript sides in sync. If you want to place widgets that are actually “hooked up” in a template, you should follow how things are done in this example:

Thank you @Bryan. I have gone through the demo repo shared by you but apparently it looks little complex for my set of preliminary skills, I suppose. Would you, therefore, suggest me an alternative I can use to integrate Google Analytics on my dashboard along with some meta tags for SEO purpose and traffic tracking?

It will really help me solve this challenge at the moment and completely omit using components API altogether.

@akashagl92 I think we need to clarify some things because not everything about the situation as described makes sense to me. You mention things “open on bokeh serve” so I assumed this is a question about Bokeh server applications. You mention wanting to add SEO scripts, which you could do with a template in a Bokeh server application. But the things you are adding with components above are not the SEO scripts, they are Bokeh objects, which seems to contradict that assumption. Also looking at the linked page, it does not appear to be Bokeh server app page. So first let’s clear up: Are you running a Bokeh server application, or not?

@Bryan, sorry if I hadn’t been clear enough. The complete dashboard is made using Bokeh library on Python. My folder structure is:
covid19-india>main.py
covid19-india>templates
covid19-india>templates>index.html

For more understanding, please find my github repo that I am running on AWS using bokeh serve --keep-alive 7000 for it to be kept alive until the nohup process is terminated.

Google Analytics script and meta tags are added in index.html along with {{variable_names}} that are defined from components of scripts and div.

I hope the current explanation helps further. With my hands on Python and then Bokeh, it seems like I have been introduced to an amazing platform with so much to do to showcase realtime dashboards and therefore, I am on a learning spree to develop a comprehensive COVID19 dashboard for India.

GitHub repo to the COVID19analysis.live Dashboard

Ok, great so this is a Bokeh server application. In that case, I think:

  • all the Bokeh objects should go in Bokeh layouts and be added via curdoc().add_roots(...) and nothing with components
  • any SEO code should be written directly in the index.html template

Here is a simpler app + template example than the “dash” one that might be more helpful:

In general I would that that using components in a Bokeh server app is always a mistake. components is explicitly for embedding when there is not a Bokeh server.

@Bryan, This helped. After going through various other resources, I was able to add a Jinja2 Template in index.html. When I run the bokeh serve with log-level = debug on the folder “covid19-analysis-live” containing main.py file and templates folder, I don’t get any error on the terminal but the I get a white blank screen.

Upon ViewPageSource, I can see the meta info and Google Analytics tag as well. The GA real time is receiving a traffic hit successfully, but somehow the below code isn’t embedding the tabs.

{% block contents %}
     <div class="bokeh-tabs"> {{ embed(roots.tabs) } }</div>
{% endblock %} 

Please find the complete code below:

#main.py (ending lines)

tabs = Tabs(tabs=[tab12, tab1, tab2, tab3,  tab4, tab5, tab6,  tab7, tab8, tab9, tab10, tab11], name='tabs')

curdoc().add_root(tabs)
#index.html


{% extends base %}

<!--<!DOCTYPE html> -->
<html lang="en">
{% block head %}
<head>
    {% block inner_head %}
     {% block postamble %}
            <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
     {% endblock %}
    <meta charset="utf-8">
        <title>{% block title %}COVID19 Analysis India{% endblock %}</title>
        <meta name="HandheldFriendly" content="True">
	    <meta name="MobileOptimized" content="320">
	    <meta name="viewport" content="width=device-width, initial-scale=0.28"/>
        <link rel="canonical" href="http://covid19analysis.live" />


        <!-- Google Tag Manager -->

        <script>
            (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','GTM-P5XXXXX);
        </script>


        <script type="text/javascript" src="static/js/bokeh.min.js?v=57d29d5936e494351385d736f792154c"></script>
        <script type="text/javascript" src="static/js/bokeh-widgets.min.js?v=fdb1f42cceaade9062de57963cac654c"></script>
        <script type="text/javascript" src="static/js/bokeh-tables.min.js?v=0a7f930d4b0805283dfba427bb3d0dae"></script>
        <script type="text/javascript" src="static/js/bokeh-gl.min.js?v=c376f0736800259be44cb1aed39a6cc3"></script>
        <script type="text/javascript">

        </script>
        <link rel="shortcut icon" type="image/png" href="/covid19-india/favicon.ico"/>
        <meta name="description" content="It is a Bokeh Application made exclusively for COVID19 analysis for India and all the states with the available open source data of The Ministry of Health and Family Affair."/>
        <meta property="og:description" content="Dashboard made exclusively for COVID19 analysis for India and it's states with available open source data of The Ministry of Health and Family Affair. " />
        <meta property="og:url" content="http://www.covid19analysis.live" />
        <meta property="og:site_name" content="COVID19 Analysis India" />
        <meta name="twitter:card" content="summary" />
        <meta name="twitter:description" content="Dashboard made exclusively for COVID19 analysis for India and it's states with available open source data of The Ministry of Health and Family Affair." />
        <meta name="twitter:title" content="Analyse and Compare COVID19 spread between Indian states" />
        <meta name="twitter:site" content="@akash2692" />

    {% endblock %}

</head>
{% endblock %}
{% block body %}
<body>
     <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PXXXX"
            height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    {% block contents %}
     <div class="bokeh-tabs">{{ embed(roots.tabs) }}</div>
    {% endblock %}
</body>
{% endblock %}
</html>

Upon running the complete folder, I am getting a blank white screen on the browser with no console error.

What’s reported in the browser JavaScript console?

My bad. By console error, I meant debug log in the terminal didn’t show any exception/errors. However, i am sharing a console tab (from Inspect) screenshot as there seems to be an error. Thank you for the help!

Uncaught SyntaxError: Invalid or unexpected token

Unfortunately I can’t really ay anything else without running and reproducing things myself. I did try to do that with the repo above but when I run I get a numpy error when a session tries to load:

numpy.linalg.LinAlgError: SVD did not converge in Linear Least Squares

which, if it is also happening for you, is certainly a reason for nothing to show up. But it’s not clear whether that is happening for you or not.

Tho actually looking close I guess the code in the repo still uses components. I can only say that I am happy to help look at this directly, but only with a minimal, complete reproducer. Right now there is nearly ~1000 lines of code most of which are probably not relevant to the issue at all. You should pare things down enormously, to reproduce the problem with a extreme bare minimum of code. You may even find that starting from something much, much smaller, and incrementally adding to it solves the problem on its own.

In general, people run in to trouble when they “dive in” with a large amount of code, instead of starting with a tiny working toy example and building up. E.g. maybe take the working gapminder example and start making small tweaks/changes to nudge it towards what you actually want. Then if it stops working along the way at some point, you actually know what change caused a problem. That’s the kind of fine-grained information that is needed to diagnose most any software issue.

Well, the code independently is running perfectly with all the given widgets such as Select and Tabs. If I were to run only .py file, the code would run successfully with all the interactions using Bokeh Serve.

I am facing problem only when I add index.html into the templates folder and run the complete folder containing main.py and templates. :thinking:

Right, that is my point, really. It’s something new. I am suggesting you tackle the problem of learning the new things like how to work with templates, independently and purposefully, as a task unto itself. I.e. by starting with simpler, smaller usage first, before jumping in to adding directly things to your full app. Start off by making small changes to something that you know works like the gapminder example, and see exactly what steps you run in to problems with. That is a much more efficient way to approach this than trying to work backwards from what might be going wrong in the middle of a thousand lines of code.

Hello Bryan,

Thanks for being patient with me. I understand what you are suggesting.

Although, one last thing, hopefully, I caught some js exceptions while loading the page localhost:5006 upon running bokeh serve. I have attached the same in the image if that leads you anywhere from your experience.

Nevertheless, I am still going to work my way around by working on small snippets of codes to understand it better.

However, if you find any lead, I would appreciate you guiding me with it.

Thanks

@akashagl92 those messages are not coming from Bokeh, I’m afraid.

Hello @Bryan, I was able to achieve index.html with embed(roots.tabs) and GA snippet after debugging the jinja2 template of index.html file and it’s well functional and deployed in production url now. In fact I added a pre-loader too to the html page.

The issue was with the {% body block %}. It was causing the screen to be blank for some error I still couldn’t really understand. But otherwise, it is functional.

Although, despite adding a title to the page, I am still getting a default “Bokeh Application” title. Any ideas on this?

Following is the complete code for the reference of others if anyone faces a similar challenge:

{% extends base %}

<!--<!DOCTYPE html> -->
<html lang="en">
{% block head %}
<head>

     {% block preamble %}
        <style type="text/css">
            .se-pre-con{
                        width:100%;
                        height:100%;
                        position:fixed;
                        z-index:9999;
                        background:no-repeat center center rgba(0,0,0,0)
                        }
            .se-pre-con img{
                        position: relative;
                        left: 50%;
                        top: 50%;
                        }

        </style>

        <meta charset="utf-8">
       {% block title %} <title>{{"COVID19 Analysis India"}}</title> {% endblock %}
        <meta name="HandheldFriendly" content="True">
	    <meta name="MobileOptimized" content="320">
	    <meta name="viewport" content="width=device-width, initial-scale=0.28"/>
        <link rel="canonical" href="http://covid19analysis.live" />

     {% endblock %}

        <!-- Google Tag Manager -->

        <script>
            (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','GTM-XXXXXX');
        </script>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.js"></script>

    	<script> $(window).load(function() {
		// Animate loader off screen
		$(".se-pre-con").fadeOut("slow");;
       	}); </script>

        <script type="text/javascript" src="static/js/bokeh.min.js?v=57d29d5936e494351385d736f792154c"></script>
        <script type="text/javascript" src="static/js/bokeh-widgets.min.js?v=fdb1f42cceaade9062de57963cac654c"></script>
        <script type="text/javascript" src="static/js/bokeh-tables.min.js?v=0a7f930d4b0805283dfba427bb3d0dae"></script>
        <script type="text/javascript" src="static/js/bokeh-gl.min.js?v=c376f0736800259be44cb1aed39a6cc3"></script>
        <script type="text/javascript">

        </script>
        <link rel="shortcut icon" type="image/png" href="/staging/favicon.ico"/>
        <meta name="description" content="It is a Bokeh Application made exclusively for COVID19 analysis for India and all the states with the available open source data of The Ministry of Health and Family Affair."/>
        <meta property="og:description" content="Dashboard made exclusively for COVID19 analysis for India and it's states with available open source data of The Ministry of Health and Family Affair. " />
        <meta property="og:url" content="http://www.covid19analysis.live" />
        <meta property="og:site_name" content="COVID19 Analysis India" />
        <meta name="twitter:card" content="summary" />
        <meta name="twitter:description" content="Dashboard made exclusively for COVID19 analysis for India and it's states with available open source data of The Ministry of Health and Family Affair." />
        <meta name="twitter:title" content="Analyse and Compare COVID19 spread between Indian states" />
        <meta name="twitter:site" content="@akash2692" />


</head>
{% endblock %}

<body>
    {% block contents %}
        <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXX"
            height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <div class = 'se-pre-con'><img src="/staging/static/Preloader_6.gif"/></div>
     <div class="bokeh-tabs">{{ embed(roots.tabs)}}</div>
     {% endblock %}
</body>
</html>

Thank you for the help though!

@akashagl92 I am glad things got sorted! Normally to set the title i would set curdoc().title.

1 Like

Thank you! This worked :slight_smile: