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
Related
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
I am making a website that tracks population statistics. The site needs to update about every 5 seconds with the latest information.
Here is the relevant code for displaying the pandas df on the page (in a file titled "home.html"):
{% block content %}
<h1>Population Tracker</h1>
{% for index, label,data in pop_df.itertuples %}
<div class = "row__data">
<p>{{label}}: {{data}}</p>
</div>
{% endfor %}
{% endblock content %}
Here is the code for my scraper (in a separate file called "scraper.py")
class Scraper():
def __init__(self):
self.URL = "https://countrymeters.info/en/Japan"
def scrape(self):
"Scrapes the population data once"
page = requests.get(self.URL)
soup = BeautifulSoup(page.content,'html.parser')
data_div = soup.find_all('div',class_="data_div")[0]
table = data_div.findAll("table")[0]
tr = table.findAll('tr')
labels = []
numbers = []
for n, i in enumerate(tr):
number = i.findAll('td',{"class":"counter"})[0].text # numbers
label = i.findAll('td',{"class":"data_name"})[0].text # labels
labels.append(label)
numbers.append(number)
pop_df = pd.DataFrame(
{
'Labels':labels,
'Data': numbers
}
)
return pop_df
In my views.py file, here is what I have done:
from django.shortcuts import render
from bsoup_tracker.scraper import Scraper
scraper = Scraper()
df = scraper.scrape()
def home(request):
context = {
'pop_df':df
}
return render(request,'tracker/home.html',context)
Basically, I would like to be able to call the render onto my home.html page every 5 seconds to reupdate the page, without needing refreshes. I have tried to look elsewhere and see that Ajax could help; however I do not know where to begin.
Instead of using Django to render the page, create API and call every after 5 minutes and after getting the results, refresh the HTML content using JavaScript.
If you need more information please let me know.
AJAX stands for "asynchronous JavaScript and XML" so as you thought that would be the way to go if you need to fetch data from your backend and refresh the interface.
The base component to do so in the XmlHttpRequest object in vanilla JavaScript. However, I strongly advice using a library like jQuery, to me it's really easier to use. With vanilla JS, jQuery or any other library you choose, you can modify DOM to expose data you got from your backend. The major drawback is that you will probably end up with not so clean code which will get harder and harder to maintain.
Nowadays the most common solution would be to use djangorestframework (not mandatory, you can also use django's JsonResponse) to create an API along with a nodeJS framework like React or VueJS to create your interface using API's data. That way you will have a lot more control on your interface.
Finally, if you need to have some sort of live website (pulling data and refreshing interface every 5 seconds seems like a poor design pattern to me), you should use websockets for your frontend and ASGI in backend (instead of WSGI). Django-channel is a nice package to do so, but just Google "django websockets" and you will find a lot of documentation.
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.
I was wondering if anyone knew a good way (preferably a built in method, but I'm open to writing my own of course) to get the <script> and <div> tags from the HTML output of the Plotly offline client.
I'm already familiar with bokeh and really enjoy using it for 2D visualization, but would really like to integrate Plotly as well for its 3D visualization capabilities.
Let me know if you need any extra details about the project.
If you call:
plotly.offline.plot(data, filename='file.html')
It creates a file named file.html and opens it up in your web browser. However, if you do:
plotly.offline.plot(data, include_plotlyjs=False, output_type='div')
the call will return a string with only the div required to create the chart, which you can store in whatever variable you desire (and not to disk).
I just tried it and it returned, for a given chart that I was doing:
<div id="82072c0d-ba8d-4e86-b000-0892be065ca8" style="height: 100%; width: 100%;" class="plotly-graph-div"></div>
<script type="text/javascript">window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL="https://plot.ly";Plotly.newPlot("82072c0d-ba8d-4e86-b000-0892be065ca8",
[{"y": ..bunch of data..., "x": ..lots of data.., {"showlegend": true, "title": "the title", "xaxis": {"zeroline": true, "showline": true},
"yaxis": {"zeroline": true, "showline": true, "range": [0, 22.63852380952382]}}, {"linkText": "Export to plot.ly", "showLink": true})</script>
Notice how its just a tiny portion of an html that you are supposed to embed in a bigger page. For that I use a standard template engine like Jinga2.
With this you can create one html page with several charts arranged the way you want, and even return it as a server response to an ajax call, pretty sweet.
Update:
Remember that you'll need to include the plotly js file for all these charts to work.
You could include <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> just before putting the div you got. If you put this js at the bottom of the page, the charts won't work.
With Plotly 4, use plotly.io.to_html:
import plotly
# Returns a `<div>` and `<script>`
plotly.io.to_html(figure, include_plotlyjs=False, full_html=False)
# Returns a full standalone HTML
plotly.io.to_html(figure)
Reference: https://plotly.com/python-api-reference/generated/plotly.io.to_html.html
Apologies for the necro-answer really wanted to add a comment to Fermin Silva left behind (https://stackoverflow.com/a/38033016/2805700) - but long standing lurker reputation prevents me.
Anyhow I had a similar need and encoutered an issue with plotly 2.2.2
plotly.offline.plot(data, include_plotlyjs=False, output_type='div')
The include_plotlyjs parameter was being ignored when outputting to a div. Based on the comments above, I found a workaround. Basically let plotly plot to file, which does respect the include_plotlyjs parameter. Load into beautiful soup and inject the link to the latest plotly.js on the cdn.
import plotly
import bs4
# return as html fragment
# the include_plotlyjs argument seems to be
# ignored as it's included regardless when outputting to div
# found an open issue on here - https://github.com/plotly/plotly.py/issues/1043
plotly.offline.plot(
plot_output,
filename = filename,
config = plot_config,
include_plotlyjs = False,
auto_open = False,
)
# load the file
with open(filename) as inf:
txt = inf.read()
soup = bs4.BeautifulSoup(txt)
# add in the latest plot-ly js as per https://stackoverflow.com/a/38033016/2805700
js_src = soup.new_tag("script", src="https://cdn.plot.ly/plotly-latest.min.js")
# insert it into the document
soup.head.insert(0, js_src)
# save the file again
with open(filename, "w") as outf:
outf.write(str(soup))
Cheers
Lets say I have a very simple Bokeh plot:
from bokeh.plotting import figure
p = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p.line([1, 2, 3], [1, 4, 9])
The figure nicely produces HTML
html = p.__repr_html__()
What is all of the other stuff that I need in order to embed this in a web page? I prefer to link out to externally hosted javascript rather than inlining everything.
My ideal answer is of the form "Just copy-paste these three lines:..."
To embed a Bokeh plot in your webpage without having to inline the JS/CSS you can use bokeh.embed.components together with bokeh.resources.CDN as shown in the example below
http://docs.bokeh.org/en/latest/docs/user_guide/embedding.html#components
from bokeh.plotting import figure
from bokeh.resources import CDN
from bokeh.embed import components
plot = figure()
plot.circle([1,2], [3,4])
script, div = components(plot, CDN)
Take into consideration that using these components assumes that BokehJS has already been loaded, for instance either inline in the document text, or from CDN.
The CDN tags that you'll have to add in your html page to render the plots are, e.g. for bokeh version 0.8.2:
<link href="http://cdn.bokeh.org/bokeh/release/bokeh-0.8.2.min.css" rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.8.2.min.js">
Make sure that those links correspond to the version that you actually passed to components. You can get those links by doing:
In [1]: from bokeh.resources import CDN
In [2]: CDN.js_files
Out[2]: ['http://cdn.bokeh.org/bokeh/release/bokeh-0.8.2.min.js']
In [3]: CDN.css_files
Out[3]: ['http://cdn.bokeh.org/bokeh/release/bokeh-0.8.2.min.css']