I'm building a web app using Flask. Part of that app is plotting some data using matplotlib. I can't seem to get legends to show up at all though. For instance, when I use this example code:
data = np.random.randint(0,10,(1000))
fig,ax = plt.subplots()
ax.hist(data,bins=10,edgecolor='black',label="Entry 1")
ax.legend()
This should give a plot with a legend. Now to feed it to my HTML template I first add:
output = dumps(mpld3.fig_to_dict(fig))
return output
Which should turn the plot into a JSON file. I save the JSON file in a dictionary I call 'plot' which I then feed to my HTML template as follows:
<script type="text/javascript">
mpld3.draw_figure("{{ plot['id'] }}", {{ plot['json']|safe }});
</script>
This works as in, a plot is drawn in my app. However it doesn't show a legend:
What is going wrong here?
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.
I am trying to print the URL for a plotly chart.
The command:
plot_url = py.iplot(fig, filename= 'chart name',auto_open=False)
print plot_url
returns:
plotly.tools.PlotlyDisplay object>
rather than:
https://plot.ly/23/~andrea.botti/
Any idea why that happens? This is preventing me from embedding the chart into a script that automatically generates a html report when a chart is made.
I think I've found the answer.
The issue was that I was using py.iplot instead of py.plot.
Changing the code to:
plot_url = py.plot(fig, filename= 'chart name',auto_open=False)
print plot_url
outputs the correct url.
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
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']