Bokeh scatter plots not showing - python

I tried to make a flask app that gets a CSV file from the user, then fits my ML algorithm and finally shows two scatter plots.
Although I could show individual scatter plots via Markup(file_html(plot_obj, CDN, "my plot"), when I use components(plot_obj), and render_template to show both of them together it does not show any of them. Also, I have no error in the console.
I am able to upload the data, then run my algorithm and get the results in the console, however I still don't see the plots.
here is my app.py:
from prad_run import fit
from plots_anomalies import tsne_plot
from bokeh.resources import INLINE, CDN
from bokeh.plotting import figure
import os
from flask import Flask, flash, request, redirect, render_template
from pr_run import fit
from plots import tsne_plot
app = Flask(__name__)
#app.route('/',methods = ['GET'])
def home():
return render_template('home.html')
#app.route('/', methods=['POST'])
def results():
if request.method == 'POST':
file = request.files['file']
df = pd.read_csv(file)
gold_label, df_pr = fit(df)
y_pr = df_pr.loc[:, 'avg_score']
X_tsne = df_pr.drop(columns='avg_score')
tsne_value = plot(X_tsne)
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_pr = figure(title="Predicted results",plot_width=300, plot_height=300)
tsne_df = pd.DataFrame(data=tsne_value, columns=["v1", "v2"])
tsne_df["pr"] = [1 if x > 0.115 else 0 for x in y_pr]
colormap = {1: 'red', 0: 'green'}
tsne_df['color'] = tsne_df['pr'].map(lambda x: colormap[x])
print(tsne_df['color'].values)
p_pr.scatter(tsne_df['v1'], tsne_df['v2'], color=tsne_df['color'], fill_alpha=0.8, size=7)
js1, divs1 = components(p_true)
js2, divs2 = components(p_pr)
return render_template("home.html", js1=js1, divs1=divs1,js2=js2, divs2=divs2 )
In my home.html:
<!doctype html>
<html>
<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>
<meta charset="UTF-8">
<head>
<title>Figure examples</title>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<link
href="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.css"
rel="stylesheet" type="text/css">
<link
href="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.css"
rel="stylesheet" type="text/css">
<link
href="https://cdn.bokeh.org/bokeh/release/bokeh-tables-1.4.0.min.css"
rel="stylesheet" type="text/css">
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-1.4.0.min.js"></script>
{{ script|safe }}
</head>
<body>
<div style="width: 20%; display: inline-block;">
{{ divs1 | safe }}
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
{{ js1 | safe }}
</div>
<div style="width: 20%; display: inline-block;">
{{ divs2 | safe }}
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
{{ js2 | safe }}
</div>
</body>
</html>
Any idea what is causing this problem?

The <script> tags returned by components have to go in the <head> not <body>. Additionally, you don't need to load BokehJS from CDN multiple times as you are doing above.
You might also want to consider the newer json_items API for embedding, which can be simpler in many cases:
https://docs.bokeh.org/en/latest/docs/user_guide/embed.html?highlight=components#json-items

I found out that the reason that my plots did not display was using Conda environment. If you use Bokeh and Flask I encourage you to use virtualenv in the same folder that you are making your app instead of creating Conda environment.

Related

Bokeh plot not visible in flask application

This is a flask application which usually works.
My plots generated with bokeh are not showing up on the page at all. I can see that they are added to the html when I look with the tools but they're not visible. The page does not break and I can visit it as normal. I have tried everything from their page but now I just want the simplest example to work. When applied the json variant I just got a json printed on the page where the plot's supposed to be.
What have I missed?
EDIT: A minimum working example is also apreciated.
My route
from flask import Blueprint, render_template, redirect, url_for, flash
import json
from bokeh.embed import json_item, server_document, components
from bokeh.plotting import figure, curdoc
from bokeh.resources import CDN
from bokeh.sampledata.iris import flowers
from bokeh.layouts import gridplot
from bokeh.models import BoxSelectTool, LassoSelectTool
from bokeh.client import pull_session
test_bp = Blueprint(
'test_bp', __name__,
template_folder='templates',
static_folder='static'
)
#test_bp.route('/test_site', methods=['GET', 'POST'])
def test_site_view():
plot = figure()
plot.circle([1, 2], [3, 4])
script, div = components(plot)
return render_template(
'test.html',
script=script,
div=div
)
My test.html
{% extends "base.html" %}
<header>
{{ script|safe }}
</header>
{% block content %}
<h1>Plot</h1>
<div>
{{ div|safe }}
</div>
{% endblock %}
base.html includes
<head>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-2.1.0.min.js"
crossorigin="anonymous"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.1.0.min.js"
crossorigin="anonymous"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.1.0.min.js"
crossorigin="anonymous"></script>
<link href="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.1.0.min.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" />
</head>
For starters, you are trying to load CDN resources that don't actually exists. Bokeh stopped publishing separate CSS files at version 2.0. Since it is important that the CDN and Python versions match, it's best to just always let Bokeh itself format the necessary resources:
#test_bp.route('/test_site', methods=['GET', 'POST'])
def test_site_view():
plot = figure()
plot.circle([1, 2], [3, 4], size=40)
script, div = components(plot)
return render_template(
'test.html',
script=script,
div=div,
resources=CDN.render()
)
works with this template:
<head>
{{ resources|safe }}
</head>
<header>
{{ script|safe }}
</header>
{% block content %}
<h1>Plot</h1>
<div>
{{ div|safe }}
</div>
{% endblock %}

Python - Flask - MatPlotLib

I am trying to embed a plot from a function that I pass into my flask application.
The below does everything fine but launches the plot outside of the browser.
I've read a lot about IO and all but I'm confused on how/where to handle that.
The function runBB() in app.py returns plt.show(). After being passed symbol which is retrieved from the form. Should I be passing fig instead to do the IO calculations in app.py or should I do that in the file that holds the function?
I don't want to save the file anywhere as I want this to be dynamic from the stand point of multiple not overwriting the saved file which is what IO gets around I believe.
app.py
#Dashboard page
#app.route("/dashboard", methods = ["POST", "GET"])
def dashboard():
if person["is_logged_in"] == True:
return render_template("dashboard.html", email = person["email"], name = person["name"])
else:
return redirect(url_for('login'))
#app.route("/form", methods = ["POST", "GET"])
def form():
if request.method == "POST":
symbol = request.form["symbol"]
bytes_obj = runBB(symbol)
return render_template("dashboard.html", symbol=bytes_obj)
dashboard.html
{% extends "layout.html" %}
{% block content %}
<head>
<title>Welcome</title>
<link rel="stylesheet" type="text/css" href="{{url_for('static', filename = 'dashboard.css')}}">
<link rel="stylesheet" type="text/css" href="../static/dashboard.css">
</head>
<body>
<div class="main">
<h1 class="name">Hi, {{name}}</h1>
<form action="{{ url_for('form') }}" method ="POST">
<p><input placeholder="Enter your symbol" type="text" name="symbol"></p>
<p><input type="submit" value="Run Report" class="btn-default"></p>
</form>
<P>{{bytes_obj}}</P>
<!-- <hr style="width: 30%"> -->
<h3 class="email">{{email}}</h3>
</div>
</body>
{% endblock %}
Can someone point me in the right direction?
I've tried to comprehend other similar stackoverflow questions and can't seem to grasp this or put it together.
Please refer to this link to learn how to do this using:
import io
import base64
https://gitlab.com/snippets/1924163

How to handle errors in Django

I want to make my django app as user friendly as possible and I want to handle appropriate errors and have it push out an error message sort of like an alert in javascript. I want to do this when there's no file uploaded. So when the upload button is pressed and nothing have been uploaded there would be an alert message sent out.
My view, views.py:
def upload(request):
if "GET" == request.method:
return render(request, 'uploadpage/upload.html', {})
else:
excel_file = request.FILES["excel_file"]
# you may put validations here to check extension or file size
wb = openpyxl.load_workbook(excel_file)
# getting a particular sheet by name out of many sheets
worksheet = wb['Summary']
# iterating over the rows and
# getting value from each cell in row
seller_info = []
for cells in worksheet.iter_rows(min_col=2, max_col=2, min_row=1, max_row=5):
for cell in cells:
seller_info.append(str(cell.value))
return render(request, 'uploadpage/upload.html', {"excel_data": seller_info})
My template, uploadpage/upload.html:
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="{% static 'css/upload.css' %}">
<head>
<div id='banner-container'>
<div id='banner'>
<h1 id='header'>MY APP</h1>
<i class="glyphicon glyphicon-cloud" style="font-size:60px;color:lightblue;text-shadow:2px 2px 4px #000000;"></i>
</div>
<div>
<body>
<div id='upload-container' >
<span><h1>Upload File !</h1></span>
<span><h2>Upload Here</h2></span>
<form method="post" enctype="multipart/form-data">
<div id='input'>
{% csrf_token %}
<input type="file" name="excel_file">
<div id='btn'><button type="submit">Upload File</button> </div>
</form>
<div>
</div>
</body>
{{ excel_data }}
</head>
</html>
Django provided us a message framework which allow you to attach messages and then you can render it on your template by using JavaScript or simply just use django template.
My favorite library to show message on my web application is toastr. You can go to the document page to see how you will integrate into your project.
On your views:
from django.contrib import messages
# ...
def upload(request):
if "GET" == request.method:
messages.error(request, "There's no file uploaded")
return render(request, 'uploadpage/upload.html', {})
# ...
Then on your template you can use it like so:
...
<head>
...
<link href="toastr.min.css" rel="stylesheet" />
</head>
<body>
...
<script src="toastr.min.js"></script>
{% if messages %}
<script>
toastr.options = {
"showDuration": "300",
"hideDuration": "1000",
"timeOut": "5000"
}
{% for message in messages %}
toastr.{{ message.tags }}("{{ message }}");
{% endfor %}
</script>
{% endif %}
</body>
message.tags: Using to match with the function of toastr, for example if you want to show an error by using messages.error(...) then the message.tags will be error, when your template rendered it turned to toastr.error("Your message here") and then you'll see the toast message on your browser.
Hope that helps!
There's two ways to go about it:
You can create a client-side check that prevents the form from being sent with Javascript. That is not Django-specific and you'll have no trouble finding examples.
You catch the fact that no file was sent and set an extra flag for the upload.html template. Untested example code:
message = None
data = None
if request.FILES:
data = # process file
message = "Upload successful!"
else:
message = "Please upload a file!"
return render(request, 'upload.html', {"data": data, "message": message})
Then you can show the message in the template:
{% if message %}
<div class="message">{{message}}</div>
{% endif %}

Folium map in Django only says 'None'

I am trying to create map in Django using folium. There is no error message, but instead of the map it displays the word 'None'.
I have a django web app that reads from a postgressql database and displays the records. That is working. I want to add a map with markers, and the markers will get coordinates from the postgresql data. When I try to create a map using iframe, I get the word 'None'. I have tried just hard coding a starting location to just create the map. I still get the word 'None'.
I also typed the hard coded coordinates into google maps, and made a flask app that creates the map. They show up fine.
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from .models import PhotoInfo
import folium
import pandas
# Create your views here.
def index(request):
VarPhotoInfo = PhotoInfo.objects.order_by('DateTaken')
context = {'PhotoInfo': VarPhotoInfo }
return render(request,'natureapp/index.html',context)
def show_map(request):
#creation of map comes here + business logic
#PhotoInfo1 = PhotoInfo.objects.order_by('DateTaken')
map = folium.Map(location=[33.57137166666667, -117.76325])
map.save("natureapp/map.html")
context = {'my_map': map }
return render(request, 'natureapp/map.html', context)
map.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NatureMapper</title>
</head>
<h1>Map goes here </h1>
{{ my_map.render }}
</html>
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NatureMapper</title>
</head>
<h1>Here it is! </h1>
{% if PhotoInfo %}
{% for Photo in PhotoInfo %}
<p>there is info.</p>
<p> {{ Photo.PhotoName }}</p>
<p> {{ Photo.Lat }}</p>
<p> {{ Photo.Long }}</p>
<p> <img src="{{ Photo.PhotoImage.url }}" width = "240" alt=""></p>
{% endfor %}
{% else %}
<p>there is no info.</p>
{% endif %}
<iframe id="encoder_iframe" height=95% width="90%" src="{% url 'show_map' %}">
</iframe>
</html>
There is no error message. Just the word 'None'

use python pandas to show csv to placeholder in web file

I have a csv file and need to convert it to view it in html. I know python pandas can do it with
df = pd.read_csv("myfile.csv")
df.to_html('output.html')'
but I don't want to show it in single web page, I have index.html file and I want to show it in there but in another section.
found the answer using tablib
from flask import Flask, render_template
import tablib
import os
app = Flask (__name__)
dataset = tablib.Dataset()
with open(os.path.join(os.path.dirname(__file__),'email.csv')) as f:
dataset.csv = f.read()
#app.route("/")
def index():
data = dataset.html
#return dataset.html
return render_template('index.html', data=data)
if __name__ == "__main__":
app.run()
index.html
<html>
<head>
<meta charset="utf-8" />
<link rel=stylesheet type=text/css href="{{ url_for('static',
filename='css/style.css') }}"/>
<title>Show CSV</title>
</head>
<body>
<div class="table">
{% block body %}
{{ data|safe }}
{% endblock %}
</div>
</body>
</html>

Categories

Resources