Multiple Bokeh plots in Flask

Hi,
I want to deploy multiple Bokeh scatter plots using a Flask app. A Flask app will receive a .csv file and after applying my ML functions, it produces two tsne scatter plots.

Although my app can display them individually when I used the following code to display them together on a same page (something like Row Layout Creating layouts — Bokeh 2.4.2 Documentation) I am receiving this error: "jinja2.exceptions.UndefinedError: 'div' is undefined"

On my app.py and inside my @app.route(’/’, methods=[‘POST’]), I have the following code:

    p_true = figure(title="Data with True Labels",plot_width=300, plot_height=300,)
        true_df = pd.DataFrame(data=tsne_value, columns=["v1", "v2"])
        colormap = {1: 'red', 0: 'green'}
        true_df['label'] = gold_label

        true_df["color"] = true_df['label'].map(lambda x: colormap[x])

        p_true.scatter(true_df['v1'], true_df['v2'], color=true_df['color'], fill_alpha=0.8, size=5)

        p = figure(title="PRAD Predicted results",plot_width=300, plot_height=300)

        tsne_df = pd.DataFrame(data=tsne_value, columns=["v1", "v2"])
        tsne_df["p"] = [1 if x > 0.115 else 0 for x in y_p]
        colormap = {1: 'red', 0: 'green'}
        print(y_prad)

        tsne_df['color'] = tsne_df['p'].map(lambda x: colormap[x])
        print(tsne_df['color'].values)
        p.scatter(tsne_df['v1'], tsne_df['v2'], color=tsne_df['color'], fill_alpha=0.8, size=7)
       plots = {"true":p_true, "pred":p}
       script, div = components(plots)
       return render_template("home.html", the_div=div, the_script=script)

and in my home.html I have:

<!doctype html>

Python Flask File Upload Example

Select a file to upload

{% with messages = get_flashed_messages() %} {% if messages %}

    {% for message in messages %}
  • {{ message }}
  • {% endfor %}
{% endif %} {% endwith %}

 <head>
        <meta charset="utf-8">
        <title>Bokeh Scatter Plots</title>
        
        <style> div{float: left;} </style>
        <link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.9.0.min.css" type="text/css" />
        <script type="text/javascript" src="http://cdn.bokeh.org/bokeh/release/bokeh-0.9.0.min.js"></script>
        {{ script }}
    </head>
    <body>
    {% for key in div.keys() %}
        {{ div[key] }}
    {% endfor %}
    </body>

</html>

I have checked the code multiple times but could not find the issue. Any thoughts on this error? Am I missing something?

Thanks!

Your Jinja template has a div parameter, but you are not passing any value for div when you call render_template. (You are passing “the_div” but the template does not expect anything called that.)

@Bryan, Thanks! But still have the same issue even I have modified my code based on your comment.

my code now is:

     plots = {"true":p_true, "prad":p_prad }
     script, div = components((p_true,p_prad))
    return render_template("home.html", div= div, script=script) 

and my HTML:

        <!doctype html>
            <head>
        <link
    href="http://cdn.pydata.org/bokeh/release/bokeh-0.12.5.min.css"
    rel="stylesheet" type="text/css">
<link
    href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.5.min.css"
    rel="stylesheet" type="text/css">
<link
    href="https://cdn.pydata.org/bokeh/release/bokeh-0.12.14.min.css"
    rel="stylesheet" type="text/css">
<link
    href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.14.min.css"
    rel="stylesheet" type="text/css">
<link
    href="https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.14.min.css"
    rel="stylesheet" type="text/css">

<script src="https://cdn.pydata.org/bokeh/release/bokeh-0.12.14.min.js"></script>
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.14.min.js"></script>
<script src="https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.14.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-0.12.5.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.5.min.js"></script>
        <link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-0.12.1.min.css" type="text/css" />

<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-0.12.1.min.js"></script>
<script type="text/javascript"> Bokeh.set_log_level("info"); </script>

      </head>
        <title>Python Flask File Upload Example</title>
       <h2>Select a file to upload</h2>
      <p>
	{% with messages = get_flashed_messages() %}
	  {% if messages %}
		<ul class=flashes>
		{% for message in messages %}
		  <li>{{ message }}</li>
		{% endfor %}
		</ul>
	  {% endif %}
	{% endwith %}
</p>
<form method="post" action="/" enctype="multipart/form-data">
    <dl>
		<p>
			<input type="file" name="file" autocomplete="off" required>
		</p>
    </dl>
    <p>
		<input type="submit" value="Submit">
	</p>
</form>

 <body>
        <link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-0.12.1.min.css" type="text/css" />

<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-0.12.1.min.js"></script>
<script type="text/javascript"> Bokeh.set_log_level("info"); </script>
            <meta charset="utf-8">
            <title>Bokeh Scatter Plots</title>
            <h1> embedding multiple graphs - can we do it live?</h1>
     
 
            {{ script }}

     
        {% for key in div.keys() %}
            {{ div[key] }}
        {% endfor %}
        </body>

    </html>

I’m still receiving the same error. :frowning:
Any other thoughts!?

@sasha Maybe, but please first edit your post to use proper code formatting so that it is more intelligible.

Also there is also alot of confusion in the content above:

  • There is a comment about Bokeh server, but this is not the kind of template for a Bokeh server app, it is the kind of template to embed standalone content using components.

  • Assuming standalone content is actually what is desired, the version of BokehJS that you are loading (0.9) is ancient. Really, really ancient, almost half a decade old, and completely unsupported at this point. The current latest version of Bokeh is 1.4 and 2.0 is around the corner.

@Bryan, I used the code format, but for some reason for some part, it did not work. I have edited my post so that you can see it correctly.
Also, I am new in writing an HTML template. All I used are in the Bokeh document and examples that I have found online.

Do you think the reason that render_template cannot access div is the version of Bokeh or something is wrong in my HTML template? Can you link me to the new version document where I may find my answer?

@sasha Code formatting based on indentation is fairly fragile and your post had unindented items in the middle of the code, breaking the formatting. For future reference, it’s more robust to use the triple-backtick fences ``` around code blocks.

You have several mismatched Bokeh CSS vs JS versions. You are loading version 0.12.14 for some and version 0.12.5 for others. THIS IS COMPLETELY UNSUPPORTED. All BokehJS JS and CSS versions need to match each other, and also critically important: must match the verison of the Python Bokeh pacakge you are using. Everything needs to line up.

As for the div error, your template looks like it is expecting a dict. But you are passing a tuple to components, so you will get a tuple (not a dict back). If you want a dict from components you have to pass in a dict to begin with. (It gives you back a structure like you pass to it, basically).