I am currently trying to create a very simple app that displays a recipe and a network diagram.
I have gotten most of the way there, but I am receiving the following error:
Uncaught ReferenceError: Bokeh is not defined
at HTMLDocument.fn (?description=blueberry+pancakes:29:5)
I have tried implementing the solutions at the following locations:
Python Flask App with Interactive Bokeh plots
Embedding a bokeh plot in Flask
Embedding bokeh plot and datatable in flask
Bokeh plot not visible in flask application
but nothing is really changing.
Below is my current version of index.html.
<html>
<head>
<title>Recipes</title>
<style>
.row {
display: flex;
}
.column {
flex: 50%;
}
</style>
<script scr="https://cdn.pydata.org/bokeh/release/bokeh-3.0.0.min.js"></script>
<script scr="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.0.0.min.js"></script>
<script scr="https://cdn.pydata.org/bokeh/release/bokeh-tables-3.0.0.min.js"></script>
<script scr="https://cdn.pydata.org/bokeh/release/bokeh-gl-3.0.0.min.js"></script>
<link
href="https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css"
rel="stylesheet" type="text/css">
<link
href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css"
rel="stylesheet" type="text/css">
<link
href="https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css"
rel="stylesheet" type="text/css">
{{script | safe}}
</head>
<!-- <header>
{{ script|safe }}
</header> -->
<body>
<form action="" method="get">
Recipe Description: <input type="text" name="description">
<label for="diets">Choose a Diet:</label>
<select id="diets" name="diet_plan" size="2" multiple>
<option value="Vegan">Vegan</option>
<option value="Vegetarian">Vegetarian</option>
<option value="Nut-Free">Nut-Free</option>
<option value="Gluten-Free">Gluten-Free</option>
</select><br><br>
<input type="submit" value="Generate a recipe">
</form>
<h1>{{description}}</h1>
<h2>{{diet_plan}}</h2>
<div class="row">
<div class="column">
<h2>Ingredients</h2>
<ul>
{%for i in range(0, len)%}
<li>{{ingredients[i]}}</li>
{%endfor%}
</ul>
</div>
<div class="column">
<h2>Instructions</h2>
<ul>
{%for i in range(0, len)%}
<li>{{instructions[i]}}</li>
{%endfor%}
</ul>
</div>
</div>
<h1>{{div}}</h1>
<div>
{{div|safe }}
</div>
</body>
</html>
And here is the main portion of main.py.
from flask import Flask
from flask import request, render_template, send_file
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from bokeh.io import output_file, show
from bokeh.models import (BoxZoomTool, Circle, HoverTool, MultiLine, Plot, Range1d, ResetTool)
from bokeh.palettes import Spectral4
from bokeh.plotting import from_networkx, save
from bokeh.embed import components
from bokeh.resources import CDN
from io import BytesIO
import re
app = Flask(__name__)
#app.route("/")
def index():
description = request.args.get("description", "")
# diet_plan = request.form.getlist("diets", "")
diet_plan = request.args.get("diet_plan", "")
if description:
recipe, steps = get_ai_recipe()
ingredients = recipe["ingredient"] + " (" + recipe["qty"] + ")"
instructions = steps["instruction"]
script, div = generate_graph(recipe)
else:
recipe = None
steps = None
ingredients = pd.DataFrame({"ingredient" : []})
instructions = pd.DataFrame({"instruction" : []})
script, div = ("", "")
return render_template("index.html",
len = len(ingredients),
ingredients = ingredients,
instructions = instructions,
description = description,
diet_plan = diet_plan,
script = script,
div = div,
resources = CDN.render())
I didn't include the get_ai_recipe() or generate_graph() functions to save some space, but basically get_ai_recipe() returns 2 pandas dataframes, and generate_graph() returns a script and a div from components.
script, div = components(plot)
return script, div
So the "plot" in that code is an actual "Plot" class from bokeh.models. Pretty much every online example I saw when trying to debug this uses figure() instead of Plot(). I'm not sure if that has anything to do with my issue, but if it does, I would appreciate help in figuring out how to convert the Plot to a figure.
Additionally, I am very new to flask and html (this is my very first interaction with them, really), so I'm not sure what all of the scripts/links in the head section are doing. I also do not know if those are the most recent versions of those links. I used the original version from the examples online and then updated them as far as I could, but I'm not sure if they go any further. Some examples used all of those, and some used just one. I assume this is where my issue lies, but I am not sure.
The code is definitely generating the div, as I have it printed as a title on the page, but it's unable to find bokeh.
I would appreciate any help.
Thanks!
You are already passing the div with the plot,
but cannot tell how, try using bokeh.plotting.Figure and bokeh.embed.components;
import bokeh
# ...
empty_boxplot = bokeh.plotting.Figure(
plot_width=500,
plot_height=450
)
script, div = bokeh.embed.components(empty_boxplot)
you can then render it with Jinja in your index.html
<div id="plot">
{{ div }}
</div>
OK I figured it out.
The solution comes from here
Bokeh plot not visible in flask application
Which is a solution I tried to implement but failed to do so correctly.
Below is the correct solution.
main.py:
from flask import Flask
from flask import request, render_template, send_file
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from bokeh.io import output_file, show
from bokeh.models import (BoxZoomTool, Circle, HoverTool, MultiLine, Plot, Range1d, ResetTool)
from bokeh.palettes import Spectral4
from bokeh.plotting import from_networkx, save, figure
from bokeh.embed import components
from bokeh.resources import CDN
from io import BytesIO
import re
app = Flask(__name__)
#app.route("/")
def index():
description = request.args.get("description", "")
# diet_plan = request.form.getlist("diets", "")
diet_plan = request.args.get("diet_plan", "")
if description:
recipe, steps = get_ai_recipe()
ingredients = recipe["ingredient"] + " (" + recipe["qty"] + ")"
instructions = steps["instruction"]
script, div = generate_graph(recipe)
else:
recipe = None
steps = None
ingredients = pd.DataFrame({"ingredient" : []})
instructions = pd.DataFrame({"instruction" : []})
script, div = ("", "")
return render_template("index.html",
len = len(ingredients),
ingredients = ingredients,
instructions = instructions,
description = description,
diet_plan = diet_plan,
script = script,
div = div,
resources = CDN.render())
index.html:
<html>
<head>
<title>Recipes</title>
<style>
.row {
display: flex;
}
.column {
flex: 50%;
}
</style>
{{ resources|safe }}
</head>
<header>
{{ script|safe }}
</header>
<body>
<form action="" method="get">
Recipe Description: <input type="text" name="description">
<label for="diets">Choose a Diet:</label>
<select id="diets" name="diet_plan" size="2" multiple>
<option value="Vegan">Vegan</option>
<option value="Vegetarian">Vegetarian</option>
<option value="Nut-Free">Nut-Free</option>
<option value="Gluten-Free">Gluten-Free</option>
</select><br><br>
<input type="submit" value="Generate a recipe">
</form>
<h1>{{description}}</h1>
<h2>{{diet_plan}}</h2>
<div class="row">
<div class="column">
<h2>Ingredients</h2>
<ul>
{%for i in range(0, len)%}
<li>{{ingredients[i]}}</li>
{%endfor%}
</ul>
</div>
<div class="column">
<h2>Instructions</h2>
<ul>
{%for i in range(0, len)%}
<li>{{instructions[i]}}</li>
{%endfor%}
</ul>
</div>
</div>
<h1>{{div}}</h1>
<div>{{div|safe }}</div>
</body>
</html>
Related
I am trying to create youtube video downloader application using pytube and flask. All is done, except that a want to call pytube's stream download method from within the html script tag. How can i do it.
Here's my flask code
from flask import Flask, render_template, request
from pytube import YouTube
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html", data=None)
#app.route("/download", methods=["POST", "GET"])
def downloadVideo():
if request.method == "POST":
url = request.form["videourl"]
if url:
yt = YouTube(url)
title = yt.title
thumbnail = yt.thumbnail_url
streams = yt.streams.filter(file_extension='mp4')
data = [title, thumbnail, streams, yt]
return render_template("index.html", data=data)
if __name__ == "__main__":
app.run(debug=True)
and here's my html code
<!DOCTYPE html>
<html>
<head>
<title> Youtube Downloader </title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" href="static/css/style.css">
</head>
<body>
<div class="main">
<div class="header">
<div>
<img src="static/img/icon.png" width="48" height="48">
<h2> Youtube Downloader </h2>
</div>
<div>
<p> Convert and download youtube videos </p>
<p> in MP4 for free </p>
</div>
</div>
{% if not data %}
<div class="dform">
<form action="http://127.0.0.1:5000/download", method="POST">
<div class="inputfield">
<input type="input" name="videourl" placeholder="Search or Paste youtube link here" autocomplete="off">
<button type="submit"> Download </button>
</div>
</form>
</div>
{% else %}
<div class="videoinfo">
<img src="" class="thumbnail">
<h2> {{data[0]}} </h2>
</div>
<div class="quality">
<select id="streams">
{% for stream in data[2][:3] %}
<option value="{{stream.itag}}"> {{stream.resolution}} </option>
{% endfor %}
</select>
</div>
{% endif %}
</div>
<script type="text/javascript">
const image = document.querySelector(".thumbnail");
const select = document.querySelector("select");
let url = `{{data[1]}}`;
if (image) {
image.src = `${url}`;
window.addEventListener('change', function() {
var option = select.options[select.selectedIndex].value;
console.log(option);
{% set stream = data[3].get_by_itag(option) %}
{% stream.download() %}
});
}
</script>
</body>
</html>
I am trying to download the video using itag when a user clicks an option in the select element by using pytube get_by_itag() method.
From what I understand you want to do two things. You want to create a route on your flask app that will let serve up the youtube video based on an itag, and you want to be able to call that route from javascript.
This answer shows how to create a route to download the video.
To call a url that starts a file download from javascript you'll need to use the fetch method and open that link into an iFrame. This answer covers it.
Let me know if that covers your question.
I am trying to run a c++ executable from a flask application.
I created two input for the arguments and one button to submit and run the executable.
What I want to execute is this command line: ./Ex02_DriveStatus 5 blablabla.sw
The executable Ex02_DriveStatus is on the same folder than the python file.
When I run it from the terminal ./Ex02_DriveStatus 5 blablabla.sw
it's working well.But I would like to be able to run it from my flask application/ web interface.
Here is my python code:
import canopen
from datetime import datetime
import time
import os
import numpy as np
import argparse
from DriveLib import Drive
from flask import Flask
from flask import request
from flask import render_template
import subprocess
from subprocess import PIPE
# os.system("sudo ifconfig can0 down")
# os.system("sudo ip link set can0 type can bitrate 500000")
# os.system("sudo ifconfig can0 up")
app = Flask(__name__)
#app.route('/')
def home():
return render_template('flashing.html')
#app.route('/flashing/')
def home_flash():
return render_template('flashing.html')
#app.route('/flashing/', methods=['POST'])
def flash():
global node_id
global file_name
node_id = request.form['node_id']
file_name = request.form['file_name']
if request.form.get("submit"):
node_id = request.form['node_id']
file_name = request.form['file_name']
if node_id == '':
node_id = 0
if file_name == '':
file_name = 0
if request.method == 'POST':
output = run(node_id, file_name)
return render_template('flashing.html', output=output, node_id=node_id, file_name=file_name)
def run(node_id, file_name):
s=subprocess.run(["./Ex02_DriveStatus", node_id, file_name],stdout=PIPE)
print(s)
return s.stdout.decode("utf-8")
And my HTML code:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href='/static/main.css'/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type=text/javascript src="{{
url_for('static', filename='main.js') }}"></script>
<script>
window.addEventListener("load", function(){
// BASIC
numpad.attach({target: "demoA"});
// WITH OPTIONS
numpad.attach({target: "demoB"});
numpad.attach({target: "demoC"});
});
</script>
<title>FLASH the drive</title>
<p class="title"><strong>FLASH THE DRIVE</strong></p>
</head>
<body>
<div id="menu">
<ul id="onglets" >
<li class="active"> Flash drive </li>
<li> Test drive </li>
<li> Test module </li>
</ul>
</div>
<div class="content">
<!--test form-->
<form method="post" action="/flashing/">
<textarea id="output" name="output" rows="30" cols="50" style="resize:none" placeholder="//Your output here.">{{output}}</textarea><br>
<table>
<tr>
<td> <p>Chose the ID you want to flash with:</p> </td>
<td> <input name="node_id" id="demoA" style="height:50px;"> </td>
</tr>
<tr>
<td> <p>File name:</p> </td>
<td> <input name="file_name" style="height:50px;"> </td>
</tr>
<tr>
<td> <input id="buttonid" type="submit" name="submit" class="submit" value="FLASH"> </td>
</tr>
</table>
</form>
</div>
</body>
</html>
When I try this flask run it's running for ever without results.
I tried to create a python file test.py with just a print print("hello").
I assume this line is the problem:
s=subprocess.run(["./Ex02_DriveStatus", node_id, file_name],stdout=PIPE)
so I tested it with a simple file (the test.py):
s=subprocess.run(["python", file_name],stdout=PIPE)
and on the file_name input I would enter test.py and it is working.
So I don't know if it is because the executable from c++ gives me some conflict or if there is something I didn't write well.
Make sure your program is outputting to STDOUT.
Try removing the stdout=PIPE or try piping STDERR as well.
I am constructing HTML as part of a bigger project. The construction works, no issues with that. However I fear that the code is too verbose or that I am not using the full power of BeautifulSoup.
For Example: I am generating a div tag of class editorial that wraps a div of class editorial-title, editorial-image, editorial-subtitle, editorial-article in that order.
Sample HTML-
<div class="editorial">
<div class="editorial-title">Hello</div>
<div class="editorial-image"><img src="https://images.dog.ceo/breeds/collie-border/n02106166_2595.jpg"></div>
<div class="editorial-subtitle">world</div>
<div class="editorial-article">Yeah. But Parasite? It should have been Gone with the Wind!</div>
</div>
Here is the long code that works for small demo version of what I am trying to do -
from bs4 import BeautifulSoup
title = "Hello"
subtitle = "world"
image_url = "https://images.dog.ceo/breeds/collie-border/n02106166_2595.jpg"
article = "But Parasite? It should have been Gone with the Wind!"
editorial_container = BeautifulSoup('', 'html.parser')
editorial_container_soup = editorial_container.new_tag('div', attrs={"class": "editorial"})
editorial_soup = BeautifulSoup('', 'html.parser')
editorial_title = editorial_soup.new_tag('div', attrs={"class": "editorial-title"})
editorial_image = editorial_soup.new_tag('div', attrs={"class": "editorial-image"})
image = editorial_soup.new_tag('img', src=image_url)
editorial_subtitle = editorial_soup.new_tag('div', attrs={"class": "editorial-subtitle"})
editorial_article = editorial_soup.new_tag('div', attrs={"class": "editorial-article"})
editorial_title.append(title)
editorial_image.append(image)
editorial_subtitle.append(subtitle)
editorial_article.append(article)
editorial_soup.append(editorial_title)
editorial_soup.append(editorial_image)
editorial_soup.append(editorial_subtitle)
editorial_soup.append(editorial_article)
editorial_container_soup.append(editorial_soup)
editorial_container.append(editorial_container_soup)
print(editorial_container.prettify())
It does the job but I feel its too long. Is there a more elegant way to achieve this?
For the task that you are doing I would strongly consider using Jinja template instead of BeautifulSoup.
If you used Jinja, you just need to pass a dictionary with the editorial information to a editorial.html that could look like this:
<!-- reusable editorial.html -->
<div class="editorial">
<div class="editorial-title">{{ title }}</div>
<div class="editorial-image"><img src="{{ image }}"></div>
<div class="editorial-subtitle">{{ subtitle }}</div>
<div class="editorial-article">{{ article }}</div>
</div>
Include the editorial.html in the following html file, that will be loaded by flask. This will serve as your base template in this example.
<!-- template.html -->
<html>
<head>
<title>Jinja Sample</title>
</head>
<body>
{% include "editorial.html" %}
</body>
</html>
Using Flask
Start a flask app like the following:
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def editorial_test():
editorial_info = {
"title" : "Hello",
"image" : "https://images.dog.ceo/breeds/collie-border/n02106166_2595.jpg",
"subtitle" : "world",
"article" : "Yeah. But Parasite? It should have been Gone with the Wind!"
}
return render_template('template.html', editorial=editorial_info)
if __name__ == '__main__':
app.run(debug=True)
I haven't tested the code above. Have a look at this excellent tutorial for further clarification.
Render files directly
If you do not want to use Flask, you could render the webpage directly like this (Im assuming all files are in the same directory):
import jinja2
editorial_info = {
"title" : "Hello",
"image" : "https://images.dog.ceo/breeds/collie-border/n02106166_2595.jpg",
"subtitle" : "world",
"article" : "Yeah. But Parasite? It should have been Gone with the Wind!"
}
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
TEMPLATE_FILE = "template.html"
template = templateEnv.get_template(TEMPLATE_FILE)
outputText = template.render(editorial_info)
print(outputText)
Output
<html>
<head>
<title>Jinja Sample</title>
</head>
<body>
<div class="editorial">
<div class="editorial-title">Hello</div>
<div class="editorial-image"><img src="https://images.dog.ceo/breeds/collie-border/n02106166_2595.jpg"></div>
<div class="editorial-subtitle">world</div>
<div class="editorial-article">Yeah. But Parasite? It should have been Gone with the Wind!</div>
</div>
</body>
</html>
I need help, I have a Python script that do some work and print html web page.
I need to pass string from that outputed web page to that script.
Is that possible ?
In future I want to use radio buttons where user will thick data for plotting from predefinned ones.
Thanks for any advice...
My code:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# enable debugging
import cgitb
cgitb.enable()
import subprocess
import os
print "Content-type: text/html\n\n";
web = """
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
</head>
<body>
<div id='wrapper'>
<div id='header'>
</div>
<div id='content'>
<div class='content'>
<div><h3>GRAPH</h3></div>
<br>
<div style='height:520px;width:1000px;overflow:scroll;overflow-x:auto;overflow-y:hidden;'>
<img src='http://localhost/steps.png' alt='image' />
</div>
<br>
<button onclick="myFunction()">REFRESH</button>
<script>
function myFunction() {
location.reload();
}
</script>
<br>
<form action='/cgi-bin/test.py' method='post'>
nazov suboru: <input type='text' data='data'> <br />
<input type='submit' value='Submit' />
</form>
</div>
</div>
</div>
</body>
</html>
"""
print web
proc = subprocess.Popen(['gnuplot','-p'],
shell=True,
stdin=subprocess.PIPE,
)
proc.communicate("""
reset
set terminal pngcairo enhanced size 3000,500 font 'Arial,11' rounded;
set output '/opt/lampp/htdocs/%s.png'
set datafile separator "|"
plot \
\
'%s.txt' u 0:3 sm cs w l ls 1 t 'X-suradnice',\
'%s.txt' u 0:4 sm cs w l ls 2 t 'Y-suradnice',\
'%s.txt' u 0:5 sm cs w l ls 3 t 'Z-suradnice'
"""%(data,data,data,data))
Your question is quite hard to understand, but I think you are trying to work out how to access the data parameter submitted by the form POST. You can do that with the cgi module:
import cgi
form = cgi.FieldStorage()
data = form.getvalue('data')
My code:
<html>
<style type="text/css">
h1 {
position: absolute;
top: 5px;
left: 200px;
}
form #Edit1 {
position: absolute;
top: 37px;
left: 410px;
}
form #Edit2 {
position: absolute;
top: 37px;
left: 840px;
}
</style>
<font size="4" face="arial" color="#0000FF">
<h1>XML Search</h1>
</font>
<br/>
<br/>
<Form Action ="/search/" Method ="POST">
<div id="Edit1">
<INPUT TYPE = 'VARCHAR' name ='word' VALUE ="" size = "50">
</div>
<div id="Edit2">
<INPUT TYPE = "Submit" VALUE = "Search">
</div>
<br/>
<hr/>
{% csrf_token %}
</Form>
{% if list1 %}
<br/>
<head>
#!/usr/bin/python
# make a horizontal bar chart
from pylab import *
val = 3+10*rand(5) # the bar lengths
pos = arange(5)+.5 # the bar centers on the x axis
figure(1)
barh(pos,val, align='center')
{% for l in list1 %}
xticks(pos, ({{l.file_name}},))
{% endfor %}
xlabel('Performance')
title('How fast do you want to go today?')
grid(True)
show()
</head>
<body>
<div id="chart_div" style="width: 1000px; height: 500px;"></div>
</body>
{% endif %}
</html>
I have created an app in Django called 'search' which searches the keywords entered by the user in 10xml documents and maintain the frequency of their occurrence for each file. When user enters the words he gets the results as graphs. This above mentioned HTML code file is redirected from views.py file. On running the app on the server, the Python code employed alongwith the HTML code, gets printed as it is when user enters the keywords. How can I display the charts created in pylab in HTML page?
I have another idea, I used up Google charts earlier and they are working fine. The only problem with them is that they will not work if there is no Internet, and this will be a drawback in may app. Is there any way out to solve this, I mean how can we use Google charts statically? If anyone of you want you want me to upload my Google charts code, I can do that.
You need to use the FigureCanvasAgg backend and return a HttpResponse. See for instance:
[Django with Matplotlib][1]
How to use Matplotlib in Django?