Ok, I have managed to create a flask page that shows a bokeh image -- now I have to somehow put that into a template
https://gist.github.com/cloudformdesign/a0c5f2e8558ea3b60f0a
What I would like is to create a webpage with a few text boxes where the user can type the data they want to graph and it will be graphed below the text boxes. The user can select new data they want graphed and the graph will update.
I am very bad at coding in html, so I am very bad in creating templates. How would I do something like this?
I created my own example, thanks to #elyase
https://github.com/bokeh/bokeh/tree/master/examples/embed/simple
This is a very simple example of embedding bokeh pages in an html page. The example giving by #elyase was helpful, but didn't actually work with python3 (I could not import or install pyaudio). It was also overly complicated for what I was trying to ask. The gist above gives a very simple answer with only two files, all in the same directory. Thanks a ton!
Basically you need to create a view which will serve as static image, and you get the image url from that route.
I haven't got your included library so I'm going to use matplotlib and numpy to simulate what you are trying to attempt. This isn't a FULL solution for you (it's in the simplest working way using 2 views and 1 simple template), but you should be able to understand all the ESSENTIAL techniques which let you finish off your page.
I have a few comments and guidelines, and I think the code itself is pretty much self explanatory.
OK, here is the view main.py:
from flask import Flask, render_template, request, send_file
import matplotlib.pyplot as plt
import numpy as np
from StringIO import StringIO
app = Flask(__name__)
#app.route('/plot/')
def plot():
try:
# try to get the query string like ?width=xxx&height=xxx
height = int(request.args.get('height'))
width = int(request.args.get('width'))
except ValueError:
# if height, width not available, set a default value
height, width = 100, 100
# I randomly generate the plot which just based on H x W
# you should be able to generate yours from your library
to_draw = np.random.randint(0, 255, (height, width))
img = plt.imshow(to_draw)
# you can convert the graph to arrays and save to memory
imgIO = StringIO()
img.write_png(imgIO, noscale=True) # save to memory
imgIO.seek(0)
# and send that image as file as static file of url
# like... /plot/?width=100&height=100
return send_file(imgIO, mimetype='image/png')
# this is the main page with the form and user input
#app.route('/', methods=['GET', 'POST'])
def index():
# set the default values
height, width = 100, 100
# handle whenever user make a form POST (click the Plot button)
if request.method == 'POST':
try:
# use this to get the values of user input from the form
height = int(request.form['height'])
width = int(request.form['width'])
except ValueError:
pass
# and pass the context back to the template
# if no form is POST, default values will be sent to template
return render_template('index.html', height=height, width=width)
if __name__ == '__main__':
app.debug = True
app.run()
And the template at templates/index.html:
<html>
<head>
<title>Micro Plot!</title>
</head>
<body>
<h1>Interactive Plot</h1>
<form action="/" name="plot" method="POST">
<p><input type="text" name='height' value="{{ height }}" /></p>
<p><input type="text" name='width' value="{{ width }}" /></p>
<p><input type="submit" value="Plot Now!"></p>
</form>
<img src="{{ url_for('plot', height=height, width=width) }}" />
</body>
</html>
The trick is to set the image src to send a GET request to the url, and then Flask's /plot/ view to render an in-memory image and feed back as static.
Key Notes:
The url_for will then dynamically generate the src as like /plot/?width=xxx&height=xxx.
To get the querystring from the url in the view, use request.args.get('KeyName').
Once your plot is ready, save it in the memory with Python StringIO module and use Flask's send_file to serve as static content.
You should read and learn more about Flask and HTML, you cannot build something really amazing without having a good understanding of how these things work together.
I hope this helps you understand the underlying techniques, and Good Luck!
I ended up creating my own answer with the help of elyase, and the code was pulled into an example folder in the bokeh project. Check it out here:
https://github.com/bokeh/bokeh/tree/master/examples/embed/simple
Related
So I send a Form to my Flask App and wish to receive the Form image data input and pass it to another function.
Example of form:
<form action="https://example.com/api/accept_form" method="POST" enctype="multipart/form-data">
<label for="fileupload"><input type="file" name="fileupload" value="fileupload" id="fileupload" accept="image/*">
Select a file to upload</label>
<br><button id="submit">Post to Instagram</button>
</form>
On the flask app:
def image_function(image):
#DO SOMETHING WITH THE IMAGE
#main.route("/api/accept_form", methods=["POST"])
def manipulate_image():
image = request.form["fileupload"]
image_function(image)
I can see how the image data looks using the print command:
request.files["fileupload"] = <FileStorage: '666650673.jpg' ('image/jpeg')>
request.files["fileupload"].read() = b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00H\x00H\x00\x00\xff\xe1\x00 and so on ...'
How do I pass the image to another function in the Flask App as if it was the original .jpg submitted, called from the Flask Apps current directory using "./666650673.jpg"?
References:
https://linuxhint.com/python-string-decode-method/
https://stackoverflow.com/a/2324133/14843373
https://github.com/williballenthin/python-evtx/issues/43
My mistake, as #teddybearsuicide pointed out was that I was passing a file handle and not a file pointer.
Maybe there is a better way but I just saved it locally on the EC2 based on this
Solution
request.files["image"].save("./imageToSave.jpg")
And called it as you would any file in your directory.
image = "./imageToSave.jpg"
I would prefer not to have had to save it so if anyone knows how to pass the file handle directly to achieve the same effect that would be great.
I am very new to web-development (first project) and have started playing around in Flask. The other day I made a very simple temperature converter which I was running on my local host. The page had a form input to type a value, two radio buttons with Fahrenheit and Celsius to define the system of the value, then a convert button. Here is a screenshot:
Here is my Flask code ("main.py"):
from flask import Flask, render_template
from flask import request, redirect
import temperature, convert, determine_system
app = Flask(__name__)
#app.route('/')
def html():
return render_template('index.html')
#app.route('/convert', methods = ['POST'])
def convert():
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
if __name__ == "__main__":
app.run()
As you can see, the first function called "html()" initially renders the "index.html" file and the function "convert()" is executed upon clicking the "Convert" button. There are a few other functions that I have in other .py files in the directory that convert the number to the new system.
Here is the body of my "index.html" code:
<body>
<div id="banner">
<h1>Temperature Converter</h1>
<p class="lead">Use this tool to convert temperature between measurement systems</p>
</div>
<form action="/convert" method="post" target="dummyframe">
<input type="text" name="temperature"></input>
<input type="radio" name="system" value="Fahrenheit">Fahrenheit</input>
<input type="radio" name="system" value="Celsius">Celsius</input>
<br>
<br>
<input type="submit" value="Convert"></input>
</form>
</body>
</html>
To display the converted temperature on the webpage, I currently have another HTML file called "convert.html" in my templates directory that is an exact copy of the "index.html" file, except it includes the following three lines of code in the body after the :
div id="output"></div>
<p class="output-statement">{{ temp }}° {{ system }} is equal to {{ new_temp }}° {{ destination_system }}</p>
</div>
In my Flask file ("main.py), I instruct the "convert()" function to render the "convert.html" template which includes the output statement in the code above:
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
This then results in the following (notice the new web address):
I suspect that my way of outputting the converted temperature by redirecting to a new HTML file and web address (http://127.0.0.1:5000/convert) is not efficient or even the correct way of showing accomplishing this. What is the proper way to output something like this? Is there something I can add to the "index.html" file that would allow me to get rid of the "convert.html" file completely? If so, what would I change the last line of the "convert()" function in my Flask ("main.py") file to?
Thank you in advance and any links with more information on this concept are very appreciated!
Yes there is a more efficient solution where you do not need the convert.html:
This is what you will want in your main route. (note: I suggest renaming your route function to something like "index" or "temp" other than "html")
#app.route('/', methods=["GET","POST"])
def html():
output = ""
if request.method == "POST":
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
output = f"{ temp}° { system } is equal to { new_temp }° { destination_system }"
return render_template('index.html', output=output)
Make sure to import request. using: from flask import request
and in your index.html you will now have:
<div id="output"></div>
<p class="output-statement">{{output}}</p>
</div>
And make sure to change form action to action="#" or action=""
First of all, I am very new to this so I hope I can explain myself the best I can.
I have a project in college in which we are using Flask to create a web app.
We need to gather inputs from users and then predict certain values with a model I have created, saved with Pickle and load it in my app .Now when I access to my page , I can see the home page shows and I am able to enter inputs but then the 'predict' page is not showing and giving me the error 'The method is not allowed for the requested URL'. I have consulted and follow different approaches to do this, for example from this article: https://www.kdnuggets.com/2019/10/easily-deploy-machine-learning-models-using-flask.html and this https://towardsdatascience.com/deploy-a-machine-learning-model-using-flask-da580f84e60c but still not able to make it work.
Any help, tips or good tutorials would be so much appreciated! Thank you so much in advance and sorry for this long post.
My project folder has the following contents:
app.py
model.pkl(This is my model saved on my disk using Pickle)
Powerproduction dataset.csv( the original dataset)
request.py
model.py ( this is the model )
import numpy as np
from flask import Flask, request, jsonify, render_template
import pickle
app = Flask(__name__)
model = pickle.load(open('model.pkl', 'rb'))
#app.route('/')
def home():
return render_template('index.html')
#app.route('/predict',methods=['POST'])
def predict():
int_features = [float(x) for x in request.form.values()]
final_features = [np.array(int_features)]
prediction = model.predict(final_features)
output = round(prediction[0], 2)
return render_template('index.html', prediction_text='Power output should be $ {}'.format(output))
#app.route('/results',methods=['POST'])
def results():
data = request.get_json(force=True)
prediction = model.predict(final_features)
output = prediction[0]
return jsonify(output)
if __name__ == "__main__":
app.run(debug=True)`
import requests
url = 'http://127.0.0.1:5000/'
r = requests.post(url,json={'wind speed':})
print(r.json())
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import pickle
dataset = pd.read_csv('Powerproduction dataset.csv')
X = dataset.loc['speed']
y = dataset.loc['power']
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X.values.reshape(-1,1), y)
pickle.dump(regressor, open('model.pkl','wb'))
model = pickle.load(open('model.pkl','rb'))
print(model.predict(np.array([[34.00]]))[0])
<head>
<meta charset="UTF-8">
<title>Wind speed and power output prediction</title>
</head>
<body style="background: #000;">
<h1>Power output predictions</h1>
<!-- Main Input For Receiving Query to our ML -->
<form action="{{ url_for('home')}}"method="post">
< />
<input type="text" name="wind speed" placeholder="wind speed" required="required" />
<button type="submit" class="btn btn-primary btn-block btn-large">Predict power output</button>
</form>
<br>
<br>
{{ prediction_text }}
</div>
</body>
</html>
Your action references your home route:
action="{{ url_for('home')}}
You want this to point to your predict route:
action="{{ url_for('predict') }}"
You should also have a space after " (but most browsers parse this correctly):
action="{{ url_for('predict') }}" method="post">
The empty < /> in your index.html should also be removed.
I'd also fix the indentation, usually you don't indent after #app.route(..) and make sure you have an empty line between function end and your next route to make it more readable (there is a standard named PEP-8 that defines how Python code should look - Pycharm and other editors will usually give you hints if you don't conform):
#app.route('/predict',methods=['POST'])
def predict():
..
#app.route(...)
def foo():
..
I am trying to create a very simple one-page Flask application for a python script that I have. The script requires multiple user inputs in a for-loop with the number of loops being user input as well.
Here is the code in my script to make it more clear:
def shared_books():
import requests as re
from bs4 import BeautifulSoup
import time
num_lists = int(input('Enter the number of lists you would like to search:'))
urls = []
page_counts = []
for i in range(num_lists):
urls.append(input(f'Enter the url for list {i + 1}:'))
page_counts.append(int(input(f'Enter the number of pages for list {i + 1}:')))
I want a simple HTML that will ask the user for the number of lists, then the URL and page count for each list as is shown in my function. Then it will run the entire function.
The HTML code I have right now is super simple and I don't want much else outside of the input parts:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
Please let me know how I can set up this application!
Firstly, I suggest you take a look at the Flask docs. You are doing it right in terms of having a view function, but the input() python keyword doesn't work like that in Flask. Instead, you should render an html template which you can then put your form input field into. Here is an example:
from flask import Flask, render_template
#flask initialising stuff, read docs for info
#app.route("/home")
def home():
return render_template("home.html")
Flask runs on your computer's local server "localhost", which is not publicly accessible. It conventionally runs on port 5000, which gives the name "localhost:5000".
When someone visits "localhost:5000/home", flask will look for a file called "home.html" in a pre-designated templates folder – the default is a directory called "templates" which you should put your html files into.
So if this is your "home.html" file:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
When you load the page associated with a specific function, it will return a template which is rendered as html. The above should look something like this:
And that is how to start.
Thank you for the answers! I haven't quite solved the previous issue but have approached it from a different angle which is working now! I will potentially post again if I don't solve it.
I am using flask forms to do what I was trying.
Hi all, im a bit new in Python.
So I have a confused issue for me. I need to store image in database, and after that I have to display each image on client side. Im using Flask for rest request.
So here I have my simpl marckup for submitind
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="image">Select image</label>
<input type="file" name='img' id='image'>
<input type="submit" id='upload_img'>
</form>
and here I get my request and save it to my DB
#app.route("/upload", methods=["POST"])
def upload_image():
# get current image file
img_file = request.files['img']
# get Content Type and File Name of current image
content_type = img_file.content_type
filename = img_file.filename
# save to GridFS my image
# fields <-- recive the id of just saved image
fields = db.FS.put(img_file, content_type=content_type, filename=filename)
# store the filename and _id to another database
# so here we can much morea easaly get image from our GridFS
db.Mongo['images'].insert({"filename": filename, "fields": fields})
return index(images=[])
My simple database model
class db(object):
URI = "mongodb://localhost:27017"
Mongo = None
FS = None
#staticmethod
def initialize():
client = pymongo.MongoClient(db.URI)
db.Mongo= client['gallery']
db.FS = GridFS(Database.DATABASE)
And all saves is successfully.
Retrive my image from DB and try to send it on clietn
#app.route('/get_all_images')
def get_image():
images = db.Mongo['gallery'].find({})
# try to get just a first image _id and fing it at GridFS files
image = db.FS.get(images[0]["fields"])
#send to the client
return index(images=image.read())
Here is markup for display image from the response
<div>
<img src="data:image/png;base64,{{images}}" alt="">
<div>{{images}}</div>
</div>
and finnaly I get something like this enter image description here
the response is look like this:
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00w\x00\x00\x00\x7f\x08\x06\x00\x00\x00\xd5j]\xe7\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\xc9e<\x00\x00\x03"iTXtXML:com.adobe.xmp\x00\x00\x00\x00\x00
The problam is that I cant figute out how to convert this byte format into real image..and display it on a web page directly from database.
I try to make several variants to solve this problam..but in some how my mind is blow up..and I really dont undestand how to work with it.
Thanks for your time :)
IF somebady have any idias or advice how can I show images from database into client side...
I did it! :)
I figured out how to fix this by myself.
Actually the problem was in my response...and in some case on client side too.
Because when I send request from the server, I send the data in byte format,
print(type(image.read()))
<class 'bytes'>
while at the client I suggested the something like binary string
<img src="data:image/png;base64,{{images}}" alt="">
There is my solution code:
import codecs
base64_data = codecs.encode(image.read(), 'base64')
image = base64_data.decode('utf-8')
And on the client I receive the string, which I paste into the img tag...and taddaaaa I got image from my database.
Thanks all who try to help me or figure out how to fix my issue.
I'm not sure that is the best practice, but it works.
P.S. sorry for my English :P