I want to be able to upload a file to a web application and have each column of the file plotted against the values in the first column. In this particular example, y and error should be plotted against t, yielding two curves.
t
0.0000
1.0000
1.2300
y
1.2345
0.9871
0.5545
error
1.4E-4
-4.9E-3
8.2E-3
I managed to get the upload part working properly but am lost on how I could use the info from a file to plot a curve.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF_8">
<title>Uploader</title>
</head>
<body>
<h1>Upload your file</h1>
<form id = "upload-form" action = "{{ url_for('upload') }}" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" accept = "file/*" multiple/>
<input type = "submit" value ="upload"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Uploaded</title>
</head>
<body>
Uploaded Successfully
</body>
</html>
import os
from flask import Flask,render_template,request
from bokeh.plotting import figure
from bokeh.io import output_file,show
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
fg = figure(x_axis_label ="x",y_axis_label = "y")
x = [1,2,3,4]
y = [1,2,3,4]
fg.circle(x,y)
#app.route("/")
def index():
return render_template("view.html")
#app.route("/upload", methods=['POST'])
def upload():
target = os.path.join(APP_ROOT,'files/')
print(target)
if not os.path.isdir(target):
os.mkdir(target)
for file in request.files.getlist("file"):
print(file)
filename = file.filename
destination = "/".join([target,filename])
print(destination)
file.save(destination)
lines = file.read().split('\n') # a list, each element is a line
for line in lines:
x_raw, y_raw, error_raw = line.split(' ') # split the line into three, assign them to variabes
x, y, error = float(x_raw), float(y_raw), float(error_raw) # parse each part into a floating point number
return render_template("uploaded.html")
if __name__ == "__main__":
app.run(debug=True)
You can get the contents of a uploaded file as a string without saving it with file.read()
Read file data without saving it in Flask
Then parse the string. If your file were like this:
0.0000 1.2345 1.4E-4
1.0000 0.9871 -4.9E-3
1.2300 0.5545 8.2E-3
You could use this to extract the values:
lines = file.read().split('\n') # a list, each element is a line
for line in line:
x_raw, y_raw, error_raw = line.split(' ') # split the line into three, assign them to variabes
x, y, error = float(x_raw), float(y_raw), float(error_raw) # parse each part into a floating point number
string.split() works like:
>>> "a,b,c;d,e,f".split(';')
['a,b,c', 'd,e,f']
Related
I'm trying to parse the testObj in the html into JSON, but it includes so much formatting.
I already tried to remove the non-ascii characters in the object, but json.loads() and yaml still can't parse the string into an object.
How can I parse the string into an object?
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Sample Document</title>
</head>
<body></body>
<script>
const testObj = {
a: 1,
b: 2,
c: 3,
};
</script>
</html>
Python Script
import lxml.html
import urllib.request
import os
import json
import yaml
def removeNonAscii(str):
return ''.join(i for i in str if ord(i)>31 and ord(i)<126)
with urllib.request.urlopen('file:///'+os.path.abspath('./test.html')) as url:
page = url.read()
tree = lxml.html.fromstring(page)
x = tree.xpath("//script")[0].text_content()
json_str = x.strip().split('testObj = ')[1][:-1]
str = removeNonAscii(json_str)
print(str)
# >>> {a: 1,b: 2,c: 3,}
# Attempt 1 - This doesn't work as object doesn't originally have double quotes
# data = json.loads(str)
# >>> json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes
# Attempt 2 - Not sure how to detect or get rid of formatting
# data = yaml.load(str, yaml.SafeLoader)
# >>> ScannerError: While scanning for the next token found character '\t' that cannot start any token
print(data.a)
# >>> Should return 1
Edit: In my actual use case, the JSON object is very large and I cannot recreate the string. I need to remove the formatting and/or add double quotes to make it proper JSON so it can parse, but not sure how to do it. I'm close getting it to {a: 1,b: 2,c: 3,} but it still doesn't want to parse.
If it is as shown (not minified) then you can use the following regex to extract the string then hjson to add the quoted keys
import hjson, re
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Sample Document</title>
</head>
<body></body>
<script>
const testObj = {
a: 1,
b: 2,
c: 3,
};
</script>
</html>'''
s = re.search(r'const testObj = ([\s\S]+?);', html).group(1)
res = hjson.loads(s)
print(res)
Regex:
This question is not a duplicate because I have stored the image address in a dataset and i need to retrieve those images that are present in my folder using a machine learning model, store it in a list and display those images in a browser I am creating a movie recommendation system in flask. I need to display poster image along with the name, but the browser doesn't seem to view the image. Here is my code:
app.py:
from flask import Flask,render_template
from flask import request
from sample import get_title_from_index
from sample import get_poster_from_index
from sample import similar_movies
from flask import jsonify
from PIL import Image
import array as arr
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def predict():
if 'movie_input' in request.form:
movies = similar_movies(request.form['movie_input'])
i=0
print("Top 5 similar movies are:")
e1= []
p1=[]
for element in movies:
e1.insert(0,get_title_from_index(element[0]))
image= Image.open(get_poster_from_index(element[0]))
p1.insert(0,image)
i=i+1
if i>5:
break
else:
e1 = "No movies selected. Please, select something!"
p1 = ""
return render_template('predictor.html', movie=e1,poster=p1)
if __name__ == '__main__':
app.run(debug=True)
predictor.html:
<!doctype html>
<html>
<head>
</head>
<body>
<form method="POST">
<input type="text" name="movie_input" maxlength="500" >
<input type="submit" value="Submit" method="get" >
</form>
<p>
{{movie[0]}}
{{poster[0]}}
</p>
</body>
</html>
sample.py
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
df = pd.read_csv("movies.csv")
def get_title_from_index(index):
return df[df.index == index]["title"].values[0]
def get_index_from_title(title):
return df[df.title == title]["index"].values[0]
def get_poster_from_index(index):
return df[df.index == index]["poster"].values[0]
def combine_features(row):
return row["keywords"]+"" +row["cast"]+""+row["genres"]+""+row["director"]
def similar_movies(movie_input):
features = ['keywords','cast','genres','director']
df["poster"] = df["poster"].fillna("")
for feature in features:
df[feature] = df[feature].fillna("") #filling all NaNs with blank string
df["combined_features"] = df.apply(combine_features,axis=1)
cv = CountVectorizer() #creating new CountVectorizer() object
count_matrix = cv.fit_transform(df["combined_features"])
cosine_sim = cosine_similarity(count_matrix)
movie_index = get_index_from_title(movie_input)
similar_movies = list(enumerate(cosine_sim[movie_index]))
sorted_similar_movies = sorted(similar_movies,key=lambda x:x[1],reverse=True)[1:]
return sorted_similar_movies
The browser view:
browser view
The browser view shows that the image is present but doesn't seems to view it.
dataset view
movie dataset view
folder view
flask folder
Please review my code and let me know the necessary changes.
You can't just output an image file into html. You have you have encode it an put it in an html IMG tag.
If you encode the image data into base64, you can do something like:
{{movie[0]}}
<img src="data:image/png;base64, {{poster[0]}}" />
For encoding the image, see Encoding an image file with base64
I have configured xampp on windows to work with python 2.7 and Pygments. My php code is highlighted properly in Pygments on the website. The code has colors, span elements, classes.
That is how it looks:
But I cannot get line numbers.
As I have read tutorials it depends on the linenos value in python script. The value should be either table or inline or 1 or True.
But it does not work for me. I still gives the same final code
<!doctype html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="gh.css">
</head>
<body>
<div class="highlight highlight-php"><pre><code><span class="nv">$name</span> <span class="o">=</span> <span class="s2">"Jaś"</span><span class="p">;</span>
<span class="k">echo</span> <span class="s2">"Zażółć gęślą jaźń, "</span> <span class="o">.</span> <span class="nv">$name</span> <span class="o">.</span> <span class="s1">'.'</span><span class="p">;</span>
<span class="k">echo</span> <span class="s2">"hehehe#jo.io"</span><span class="p">;</span>
</code></pre></div>
</html>
How to add line numbers? I put two files of the website below:
index.py
import sys
from pygments import highlight
from pygments.formatters import HtmlFormatter
# If there isn't only 2 args something weird is going on
expecting = 2;
if ( len(sys.argv) != expecting + 1 ):
exit(128)
# Get the code
language = (sys.argv[1]).lower()
filename = sys.argv[2]
f = open(filename, 'rb')
code = f.read()
f.close()
# PHP
if language == 'php':
from pygments.lexers import PhpLexer
lexer = PhpLexer(startinline=True)
# GUESS
elif language == 'guess':
from pygments.lexers import guess_lexer
lexer = guess_lexer( code )
# GET BY NAME
else:
from pygments.lexers import get_lexer_by_name
lexer = get_lexer_by_name( language )
# OUTPUT
formatter = HtmlFormatter(linenos='table', encoding='utf-8', nowrap=True)
highlighted = highlight(code, lexer, formatter)
print highlighted
index.php
<?php
define('MB_WPP_BASE', dirname(__FILE__));
function mb_pygments_convert_code($matches)
{
$pygments_build = MB_WPP_BASE . '/index.py';
$source_code = isset($matches[3]) ? $matches[3] : '';
$class_name = isset($matches[2]) ? $matches[2] : '';
// Creates a temporary filename
$temp_file = tempnam(sys_get_temp_dir(), 'MB_Pygments_');
// Populate temporary file
$filehandle = fopen($temp_file, "w");
fwrite($filehandle, html_entity_decode($source_code, ENT_COMPAT, 'UTF-8'));
fclose($filehandle);
// Creates pygments command
$language = $class_name ? $class_name : 'guess';
$command = sprintf('C:\Python27/python %s %s %s', $pygments_build, $language, $temp_file);
// Executes the command
$retVal = -1;
exec($command, $output, $retVal);
unlink($temp_file);
// Returns Source Code
$format = '<div class="highlight highlight-%s"><pre><code>%s</code></pre></div>';
if ($retVal == 0)
$source_code = implode("\n", $output);
$highlighted_code = sprintf($format, $language, $source_code);
return $highlighted_code;
}
// This prevent throwing error
libxml_use_internal_errors(true);
// Get all pre from post content
$dom = new DOMDocument();
$dom->loadHTML(mb_convert_encoding('
<pre class="php">
<code>
$name = "Jaś";
echo "Zażółć gęślą jaźń, " . $name . \'.\';
echo "<address>hehehe#jo.io</address>";
</code>
</pre>', 'HTML-ENTITIES', "UTF-8"), LIBXML_HTML_NODEFDTD);
$pres = $dom->getElementsByTagName('pre');
foreach ($pres as $pre) {
$class = $pre->attributes->getNamedItem('class')->nodeValue;
$code = $pre->nodeValue;
$args = array(
2 => $class, // Element at position [2] is the class
3 => $code // And element at position [2] is the code
);
// convert the code
$new_code = mb_pygments_convert_code($args);
// Replace the actual pre with the new one.
$new_pre = $dom->createDocumentFragment();
$new_pre->appendXML($new_code);
$pre->parentNode->replaceChild($new_pre, $pre);
}
// Save the HTML of the new code.
$newHtml = "";
foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $child) {
$newHtml .= $dom->saveHTML($child);
}
?>
<!doctype html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="gh.css">
</head>
<body>
<?= $newHtml ?>
</body>
</html>
Thank you
While reading the file try readlines:
f = open(filename, 'rb')
code = f.readlines()
f.close()
This way you do the following it will get multiple lines :
formatter = HtmlFormatter(linenos='table', encoding='utf-8', nowrap=True)
Suggestion:
More pythonic way of opening files is :
with open(filename, 'rb') as f:
code = f.readlines()
That's it python context manager closes this file for you.
Solved!
nowrap
If set to True, don’t wrap the tokens at all, not even inside a tag. This disables most other options (default: False).
http://pygments.org/docs/formatters/#HtmlFormatter
I'm building my first web application using Flask. The concept of the web app is to manipulate and visualize data using Pandas and Bokeh. All of this has been relatively straight forward.
Now I'm at a point where I'm plotting information on a map of New York using GMapPlot. When I use output_file to show the plot I get the expected result.
expected
However when I try to return the plot to my own html template the map is empty.
actual
Here's my .py file (apologies for the messy code).
import pandas as pd
import datetime
from flask import render_template, request
from web_app.app import app
from bokeh.io import output_file, show
from bokeh.embed import components
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle, DataRange1d, PanTool, WheelZoomTool, BoxSelectTool
)
#app.route('/heatmap', methods=['GET', 'POST'])
def generate_heatmap():
date1 = datetime.datetime.strptime(request.form['startFilter'],"%Y-%m-%d").date()
date2 = datetime.datetime.strptime(request.form['stopFilter'], "%Y-%m-%d").date()
date2 += datetime.timedelta(days=1)
date_start = str(date1)
date_stop = str(date2)
df = pd.read_csv("...", sep=",")
df = df.set_index(['starttime'])
df = df.loc[date_start:date_stop]
start_lats = pd.Series(df['start station latitude']).unique()
stop_lats = pd.Series(df['end station latitude']).unique()
start_long = pd.Series(df['start station longitude']).unique()
stop_long = pd.Series(df['end station longitude']).unique()
lats = start_lats.tolist() + stop_lats.tolist()
long = start_long.tolist() + stop_long.tolist()
map_options = GMapOptions(lat=40.741557, lng=-73.990467, map_type="roadmap", zoom=11)
plot = GMapPlot(
x_range=DataRange1d(), y_range=DataRange1d(), map_options=map_options, title="NYC"
)
source = ColumnDataSource(
data=dict(
lat=lats,
lon=long,
)
)
circle = Circle(x="lon", y="lat", size=8, fill_color="blue", fill_alpha=0.8, line_color=None)
plot.add_glyph(source, circle)
plot.add_tools(PanTool(), WheelZoomTool(), BoxSelectTool())
output_file("gmap_plot.html")
show(plot)
script, div = components(plot)
return render_template('heatmap.html', script = script, div = div)
and my HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Heatmap</title>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.css" type="text/css" />
<script type="text/javascript" src="http://cdn.bokeh.org/bokeh/release/bokeh-0.11.1.min.js"></script>
{{ script | safe }}
</head>
<body>
<div class='bokeh'>
{{ div | safe }}
</div>
</body>
I'm a beginner with both these tools, but I put them to work by doing:
from web_app.app import app
from flask import render_template
from bokeh.embed import file_html
from bokeh.plotting import figure
from bokeh.resources import CDN
#app.route('/example', methods=['GET'])
def example():
plot = figure()
plot.circle([1,2], [3,4])
html = file_html(plot, CDN)
return render_template('whatever.html', plot=html)
Then, using Jinja2 in the template:
{{ plot|safe }}
I want to show OpenCV processed image with web interface (made with CherryPy). Code below works fine:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
return data.tostring()
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
However: I would like to embed the image in html so I can (for example) add another image or other data to the same page.
I have tried the following code:
import cherrypy
import cv2
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpeg', image)
return """ <html>
<head>
<title>CherryPy static imagl</title>
</head>
<html>
<body>
<img src=" """ + data + """:image/jpeg" />
</body>
</html>"""
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
But this gives the following error:
<img src=" """ + data + """:image/jpeg" />
TypeError: cannot concatenate 'str' and 'numpy.ndarray' objects
Converting the numpy arry to a string using the following code also does not work (it gives no error but displays only characters):
<img src=" """ + data.tostring() + """:image/jpeg" />
Anyone who can give me some more insight? Thanks in advance!
The following code does the trick :)
import cherrypy
import cv2
import base64
class Picture(object):
def __init__(self):
self.cam = cv2.VideoCapture(0)
#cherrypy.expose
def index(self):
_, image = self.cam.read()
_, data = cv2.imencode('.jpg', image)
jpeg_base64 = base64.b64encode(data.tostring())
return """
<html>
<head>
<meta http-equiv="refresh" content="1" />
<title>Cherrypy webcam</title>
</head>
<html>
<body>
<img src='data:image/jpeg;base64,%s' />
<img src='data:image/jpeg;base64,%s' />
</body>
</html>
""" % (jpeg_base64, jpeg_base64)
if __name__ == '__main__':
cherrypy.config.update({'server.socket_host': '127.0.0.1', 'server.socket_port': 80, })
cherrypy.quickstart(Picture())
This code displays the same picture two times. and the:
<meta http-equiv="refresh" content="1" />
refreshes the code every second.