I want to deploy a web map apps which containing several points and Plotly graphs as folium popup. Everything is fine until I want to deploy my web map apps in Flask, which when I click the point, the pop up shows error message says
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
Here is the popup code
#make a dataframe which is used for plotting the well head point in folium
df_point = pd.DataFrame(list(zip(wells, html_list, Longitude, Latitude)), columns =['Well_Name', 'HTML_list', 'Longitude', 'Latitude'])
#Start plotting well head in map with well log plot as a pop up widget
for i in range(0,len(df_point)):
html="""
<iframe src=\"""" + df_point['HTML_list'][i] + """\" width="700" height="800" frameborder="0">
""")
popup = folium.Popup(folium.Html(html, script=True))
# #Cirlce marker ver.
# folium.CircleMarker([df_point['Latitude'].iloc[i],df_point['Longitude'].iloc[i]],
# popup=popup,radius=3.5,opacity=1,color='#ccd132').add_to(map1)
#Marker with icon ver.
folium.Marker([df_point['Latitude'].iloc[i],df_point['Longitude'].iloc[i]],
popup=popup,icon=folium.Icon( icon='glyphicon-pushpin')).add_to(map1)
I put the HTML file, coordinate and name on dataframe which is called df_point, here is the dataframes
Well_Name HTML_list Longitude Latitude
0 Well 1F figWell 1F.html 96.083956 5.456862
1 Well 2F figWell 2F.html 96.356427 5.328133
and here is my Flask app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def render_the_map():
return render_template('testing_map.html')
if __name__ == '__main__':
app.run(debug=True)
and also here is the path if someone need my file path information
How do I put the Plotly graphs in HTML format as pop up folium on Flask? I'm still new in Flask development. Any help I would appreciate it, Thanks!
I found a solution based on Sebastian's answer, if someone want to make a Folium map and the pop up marker showing plotly html in Flask, here's how to do it
first, in the app.py, make a route for the plotly plot
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def render_the_map():
return render_template('testing_map.html')
#app.route('/figure1')
def figure_plotly1():
return render_template('figWell 1F.html')
#app.route('/figure2')
def figure_plotly2():
return render_template('figWell 2F.html')
if __name__ == '__main__':
app.run(debug=True)
and then, search your plotly code in your folium map html and change the iframe source to the defined route, so for example, my plotly html graph name is figWell 1F.html, try to ctrl+F in your main HTML folium map and change the iframe src to be like this
<iframe src="{{url_for('figure_plotly1')}}" width="700" height="800"
and it works like a charm
Related
I would like to ask how to implement Python run time and graphics on website as seen in this Udacity lesson on PD controller?
If run locally, matplotlib will generate a popup window containing the graphics. How is it capture and shown on the website? The text output is shown in the terminal. On Udacity, all of that are shown in a single page. How are they captured and displayed as such? What if you want to display live animation generated by things like turtle graphics?
And how do you provide a code input area with the code presentation as shown to the user? And how do you provide features like LaTex on your page like math.stackexchange.com?
Are there certain frameworks, API and languages you have to use, or is it independent of all that?
You need to use a python backend framework,
I use Django or Flask and run the mathplotlib on my backend and display it in the image formation using the HTML img tag
Here is the example in the flask
app.py
from flask import Flask, render_template
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4, 5])
plt.ylabel('some numbers')
plt.savefig('static/graph.png')
app = Flask(__name__)
#app.route('/')
def home():
return render_template("index.html")
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html>
<head>
<title>MathPlotLib</title>
</head>
<body>
<div><img alt="Sample Work" src="{{ url_for('static', filename='graph.png') }}">
</div>
</body>
</html>
File System
Main Folder
----templates
----index.html
----static
----graph.png
----app.py
Savefig
So the answer to your question would be instead of plt.show() you do a plt.savefig() as a temporary file in the backend and later add it to the website. There are saving formats like svg that will give you all the benefits of resizing and rendering on the front end side too.
In one of the requirement, I need to integrate Google Map with Dash framework and on map click - retrieve lat , long and address (on map click event).
I was able to retrieve the same using google API and flask framework using java script which gives Lat ,Long and Address based on map click event and renders Google Map
Here is the python code used in flask framework :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/map', methods=['GET', 'POST'])
def map():
location = {}
if request.method == "POST":
location = request.get_json()
# latitude = location['latitude']
# longitude = location['longitude']
print(location);
return render_template('map.html')
if __name__ == '__main__':
app.run(debug = True) # run app
Any guidance how to achieve the same using Dash Framework would be really helpful. I can share JS Script Code as well if needed.
You could use Dash Leaflet for the map visualization. It supports arbitrary tile provides, i.e. also Google, as well as click events. You would need another library for the reverse geocoding though, one options is Googles API.
Disclaimer: I am the maintainer of Dash Leaflet.
I can't run bokeh server within flask beind apache so now I'm trying to serve bokeh within flask locally. The figure does not render.
Here is the flask code:
from flask import Flask, render_template
app = Flask(__name__)
from bokeh.embed import server_document
#app.route("/")
def techblog():
try:
tag = server_document(url=r'/bokeh', relative_urls=True)
return render_template('techblog.html', tag=tag)
except Exception as e:
return str(e)
if __name__ == '__main__':
app.run(debug=True)
Here is the bokeh code:
from numpy.random import random
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import Button, ColumnDataSource
from bokeh.server.server import Server
def run(doc):
fig = figure(title='random data', width=400, height=200, tools='pan,box_zoom,reset,save')
source = ColumnDataSource(data={'x': [], 'y': []})
fig.line('x', 'y', source=source)
def click(n=100):
source.data = {'x': range(n), 'y': random(n)}
button = Button(label='update', button_type='success')
button.on_click(click)
layout = column(widgetbox(button), fig)
doc.add_root(layout)
click()
# configure and run bokeh server
kws = {'port': 5000, 'prefix':'/bokeh','allow_websocket_origin': ['127.0.0.1']}
server = Server(run, **kws)
server.start()
# if __name__ == '__main__':
server.io_loop.add_callback(server.show, '/')
server.io_loop.start()
Here is my html template:
<h1 style='color:blue'>Hello There!</h1>
</br>
{{ tag|safe }}
</br>
{{ tag }}
I'm running flask app via python. And on a separate command processor I run bokeh app via,
bokeh serve --allow-websocket-origin=localhost:5000 filename.py
I only get the tag without "safe" as
<script src="/bokeh/autoload.js?bokeh-autoload-element=1001&bokeh-app-path=/bokeh" id="1001"></script>
And I have this message on flask console. It is a standart 404:
"GET /bokeh/autoload.js?bokeh-autoload-element=1000&bokeh-app-path=/bokeh HTTP/1.1" 404 -
That'a all. No figure or button is rendered. What should I change to see the figure?
Edit: I've specified the port and the prefix in the bokeh code. The outcome has not changed.
Edit 2: I've add the console msj for 404 error on flask console.
There are a few things wrong:
You have not configured a port, so the Bokeh server will use its default port of 5006 (not 5000)
You have not configured an app path, so the Bokeh server will serve the app from its default location of / (not /bokeh)
It's also worth mentioning that if you whitelist localhost as an allow websocket origin, then it literally must be localhost in the URL bar (i.e. not 127.0.0.1, they are not interchangeable in this context)
Lastly, it's a lot of extra work to put the Bokeh app code in a plain python script that calls Server manually, etc. You could just put the contents of run in a file and call bokeh serve --port=5000 app.py and then the app will be available at localhost:5000/app
I add some details to #bigreddot's answer.
Code didn't work for me too. I even found exactly this code in some tutorial and main problem was that it was using nginx which was converting /bokeh to http://127.0.0.1/bokeh. But on local computer without nginx I have to change all urls.
EDIT: I found tutorial with this code https://rbtechblog.com/blog/deploy_bokeh_app
I start changing code and reduce it to create minimal code which works. I made changes similar to changes mentioned by bigreddot.
Bokeh
I put code directly in file without def and without Server
filename.py
from numpy.random import random
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import Button, ColumnDataSource
def click(n=100):
source.data = {'x': range(n), 'y': random(n)}
fig = figure(title='random data', width=800, height=400, tools='pan,box_zoom,reset,save')
source = ColumnDataSource(data={'x': [], 'y': []}) # place for data
fig.line('x', 'y', source=source) # draw plot
button = Button(label='update', button_type='success') # create button
button.on_click(click) # assign function to button
layout = column(fig, widgetbox(button)) # create layout
curdoc().add_root(layout) # add all to document
click() # generate random data at start
Now I can run it in console
bokeh serve filename.py
and I can see it in web browser using url
http://localhost:5006/filename
(bokeh should display this url in console after start - if you will use different file or options then you may see different url)
At this moment I don't need any other options but later I will need --allow-websocket-origin but I will describe it later.
BTW: I not use name bokeh.py because it can make problem to import original bokeh.
Flask
Because I don't use nginx which could convert /bokeh to http://localhost:5006/filename so I have to use full url in serve_document
For test I used render_template_string instead of render_template so I don't have to create templates/index.html so it will easier to copy and test code.
I removed try/except to get more details if there will be error.
app.py
from flask import Flask, render_template, render_template_string
from bokeh.embed import server_document
app = Flask(__name__)
#app.route("/")
def index():
tag = server_document(url='http://localhost:5006/filename')
#return render_template('index.html', tag=tag)
return render_template_string('''<div>{{ tag|safe }}</div>''', tag=tag)
if __name__ == '__main__':
app.run(debug=True)
Now I can run it
python app.py
and I can open page in web browser using standard url
http://localhost:5000/
but I will not see plot and bokeh will display
Refusing websocket connection from Origin 'http://127.0.0.1:5000';
use --allow-websocket-origin=127.0.0.1:5000
or set BOKEH_ALLOW_WS_ORIGIN=127.0.0.1:5000 to permit this;
currently we allow origins {'localhost:5006'}
so I have to restart bokeh with this option
bokeh serve filename.py --allow-websocket-origin=127.0.0.1:5000
(as bigreddot mentioned it has to be 127.0.0.1, not localhost)
And now flask should display plot.
BTW: if I use template without any HTML tag
render_template_string('''{{ tag|safe }}''', tag=tag)
then browser may treat all code (<script ...></scrip>) as part of <head></head> and it will not display it because browser never display elements which are in <head></head> even if there are correct images or plots.
So I am using python flask to develop a web application that asks the user for data, analyse the data in the backend using BLAST and R, and outputs interactive HTML plots that are stored in a local location (Templates) and to be displayed to the user.
Everything up to R outputs runs smoothly. I have opened the HTML files and confirmed the R codes ran as expected and the produced graphs are interactive. However when I render these HTMLs through flask the browser returns a black page. Using send_file was also fruitless to display the plots. I have confirmed that the path to the Java scripts for the interactive plot are in the same folder.
Going through the developers tool console reads the following error:
htmlwidgets.js:1 Uncaught SyntaxError: Unexpected token <
jquery.min.js:1 Uncaught SyntaxError: Unexpected token <
datatables.js:1 Uncaught SyntaxError: Unexpected token <
jquery.dataTables.min.js:1 Uncaught SyntaxError: Unexpected token <
Can someone please advise on how to successfully get the interactive R HTML outputs to show in flask?
When you use send_file or send_from_directory you would also need to serve the JavaScript libraries needed for the plot, this might be the reason for the blank page.
The same is true for render_template but according to the error messages it seems more like that your JS libraries were also rendered as templates and some < or > character got added or removed.
Try the following snippet which works for me and perhaps gives you a good start.
A very simple R script to create a standalone HTML file with a Plotly plot. A file called test.html is created in the /tmp directory. All JavaScript libraries and CSS files are in /tmp/test_files.
library(plotly)
library(htmlwidgets)
myData <- data.frame(x=c(1,2,3), y=c(3,2,1))
local_path <- '/tmp/'
ply <- plot_ly(myData, x = ~x, y = ~y, type='scatter', mode='markers+line')
saveWidget(widget=ply, file=paste(local_path, "test.html", sep=""), selfcontained = FALSE)
A minimal Flask server snippet to serve the plot and the JavaScript libraries is below. Starting flask and going in the browsesr to http://localhost:5000/ would show the plot and provide all need libraries.
from flask import Flask
from flask import send_from_directory
app = Flask(__name__)
#app.route('/')
def plotly():
return send_from_directory('/tmp/', 'test.html')
#app.route('/test_files/<path:path>')
def send_js(path):
return send_from_directory('/tmp/test_files', path)
I want build an offline application using plotly for displaying graphs . I am using python(flask) at the back end and HTML(javascript) for the front end . Currently I am able to plot the graph by sending the graph data as JSON object to front end and building the graph using plotly.js at the front end itself . But what I actually want is to build the graph at the server(backend ie python) side itself and then display the data in HTML . I have gone through the plotly documentation that builds the graph in python , but I dont know how to send the build graph to front end for display :(
Can someone help me on that ?
PS : I want to build an offline application
Updated Code
$(window).resize(function() {
var divheight = $("#section").height();
var divwidth = $("#section").width();
var update = {
width:divwidth, // or any new width
height:divheight // " "
};
var arr = $('#section > div').get();
alert(arr[1]);
Plotly.relayout(arr[0], update);
}).resize();
});
My suggestion would be to use the plotly.offline module, which creates an offline version of a plot for you. The plotly API on their website is horrendous (we wouldn't actually want to know what arguments each function takes, would we??), so much better to turn to the source code on Github.
If you have a look at the plotly source code, you can see that the offline.plot function takes a kwarg for output_type, which is either 'file' or 'div':
https://github.com/plotly/plotly.py/blob/master/plotly/offline/offline.py
So you could do:
from plotly.offline import plot
from plotly.graph_objs import Scatter
my_plot_div = plot([Scatter(x=[1, 2, 3], y=[3, 1, 6])], output_type='div')
This will give you the code (wrapped in <div> tags) to insert straight into your HTML. Maybe not the most efficient solution (as I'm pretty sure it embeds the relevant d3 code as well, which could just be cached for repeated requests), but it is self contained.
To insert your div into your html code using Flask, there are a few things you have to do.
In your html template file for your results page, create a placeholder for your plot code. Flask uses the Jinja template engine, so this would look like:
<body>
....some html...
{{ div_placeholder }}
...more html...
</body>
In your Flask views.py file, you need to render the template with the plot code inserted into the div_placeholder variable:
from plotly.offline import plot
from plotly.graph_objs import Scatter
from flask import Markup
...other imports....
#app.route('/results', methods=['GET', 'POST'])
def results():
error = None
if request.method == 'POST':
my_plot_div = plot([Scatter(x=[1, 2, 3], y=[3, 1, 6])], output_type='div')
return render_template('results.html',
div_placeholder=Markup(my_plot_div)
)
# If user tries to get to page directly, redirect to submission page
elif request.method == "GET":
return redirect(url_for('submission', error=error))
Obviously YMMV, but that should illustrate the basic principle. Note that you will probably be getting a user request using POST data that you will need to process to create the plotly graph.
You can use the .to_html() method:
https://plot.ly/python-api-reference/generated/plotly.graph_objects.Figure.html#plotly.graph_objects.Figure.to_html
import plotly.express as px
fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
div = fig.to_html(full_html=False) # Get the <div> to send to your frontend and embed in an html page