Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display multiple mpld3 exports on a single HTML page #128

Closed
philsheard opened this issue Apr 10, 2014 · 17 comments
Closed

Display multiple mpld3 exports on a single HTML page #128

philsheard opened this issue Apr 10, 2014 · 17 comments

Comments

@philsheard
Copy link

I've been trying to work out how to export multiple individual figures to display them in a template using Flask. I think the solution is somewhere between the .fig_to_html and .fig_to_dict methods but I'm not JS-savvy enough to work it through.

There's a fuller description on this stackexchange question:
http://stackoverflow.com/questions/22981359/display-multiple-mpld3-exports-on-a-single-html-page

I'd be happy to submit an pull request to the docs if someone can explain what's needed.

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 11, 2014

Hi,
Glad you're finding this useful! This question is exactly why we created the fig_to_dict method. At a high level, this is what you'll want to do on your html page

  • load mpld3 & d3
  • create a separate <div> elements for each figure, each with a unique ID
  • embed (or load) the json representing the figures. This json string can be created by calling json.dumps(mpld3.fig_to_dict(fig))
  • run the javascript command mpld3.draw_figure(figid, figjson) for each figure.

Let me know if that makes sense, and please let me know if you think there might be a better way to approach this application!

@philsheard
Copy link
Author

Thanks Jake. That makes sense.

I'm not well versed in JS and so this question might seem simplistic but here goes...

Would both calls to `mpld3.draw_figure()' sit within the same script tags, and just be called one after the next?

This approach makes sense and I've done similar using the Vincent library to output Vega-friendly JSON. Perhaps just an example code snippet in the docs might highlight the use case for newcomers. Once I get this running I'll find a moment to submit an update to the docs.

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 11, 2014

For good measure, I just answered the question on stack overflow as well, and included a code snippet: http://stackoverflow.com/questions/22981359/display-multiple-mpld3-exports-on-a-single-html-page/ Let me know if that helps!

@philsheard
Copy link
Author

Thanks for the replies Jake, much appreciated (also btw started watching the Pycon scikit-learn talk but need to set time aside for the full session - nice work).

I've followed the steps and it's still not rendering the plot. Comparing my HTML output vs the generated HTML snippet I am quite sure it's to do with loading the mpld3.draw_figure command at some point, as that's what I seem to be missing (there's a segment in the snippet that checks for require.js and similar, which isn't in my template). Lack of JS knowledge means I know I'm missing something but not sure what.

Here's my output html from the flask app:

<html>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.1.js"></script>
<head>
</head>
<body>
    <div id="31056422"></div>
<script type="text/javascript">
    mpld3.draw_figure("31056422", {"width": 640.0, "axes": [{"xlim": [0.0, 1.0], "yscale": "linear", "axesbg": "#EAEAF2", "texts": [], "zoomable": true, "images": [], "xdomain": [0.0, 1.0], "ylim": [0.10000000000000001, 1.0], "paths": [{"edgecolor": "#FFFFFF", "facecolor": "#EAEAF2", "edgewidth": 0.3, "pathcodes": ["M", "L", "L", "L", "Z"], "yindex": 1, "coordinates": "axes", "dasharray": "10,0", "zorder": 1000001.0, "alpha": 1, "xindex": 0, "data": "data02", "id": "363454617730896"}], "sharey": [], "sharex": [], "axesbgalpha": null, "axes": [{"grid": {"color": "#FFFFFF", "alpha": 1.0, "dasharray": "10,0", "gridOn": true}, "position": "bottom", "nticks": 6, "tickvalues": null, "tickformat": null}, {"grid": {"color": "#FFFFFF", "alpha": 1.0, "dasharray": "10,0", "gridOn": true}, "position": "left", "nticks": 10, "tickvalues": null, "tickformat": null}], "lines": [{"color": "#4C72B0", "yindex": 1, "coordinates": "data", "dasharray": "10,0", "zorder": 2, "alpha": 1, "xindex": 0, "linewidth": 1.4, "data": "data01", "id": "363454617729168"}], "markers": [], "id": "363454616431568", "ydomain": [0.10000000000000001, 1.0], "collections": [], "xscale": "linear", "bbox": [0.125, 0.099999999999999978, 0.77500000000000002, 0.80000000000000004]}], "data": {"data02": [[0.8975694444444445, 0.9305555555555556], [0.9887992831541218, 0.9305555555555556], [0.9887992831541218, 0.9842171717171717], [0.8975694444444445, 0.9842171717171717]], "data01": [[0.7884709865986378, 0.8710796390880277], [0.6256711247135093, 0.2566109715010527], [0.3359447878854377, 0.8765248121061339], [0.6728601761695596, 0.5975763820467942], [0.18684948786574185, 0.6041075199829672], [0.19491972941282099, 0.9398912219119647], [0.9267704471973628, 0.12385185006121469], [0.6768653956251186, 0.22580041359511138], [0.40356197033368935, 0.12709640992649407], [0.017945334425159887, 0.912858451972148]]}, "id": "363454571411408", "toolbar": ["reset", "move"], "height": 440.0});
</script>
</body>
</html>

And below are the segments of flask code and template to generate:

CODE, excluding imports. I'm aware that some of this code (eg the random generator) is a bit of a hack to begin with but I'm a) a relative beginner and b) just trying to get a proof of concept up before tidying up:

app = Flask(__name__)

# Define a function that will return an HTML snippet.
def build_plot():
    x_deets = np.random.random(10)
    y_deets = np.random.random(10)
    fig, ax = plt.subplots()
    indata = pd.DataFrame(x_deets, y_deets,)
    indata.plot(ax=ax)
    output = dumps(mpld3.fig_to_dict(fig))
    return output

# Define our URLs and pages.
@app.route('/')
def render_plot():
    sample_list = list(np.random.randint(1,99999999,size=1))
    dict_of_plots = list()
    for i in sample_list:
        single_chart = dict()
        single_chart['id'] = i
        single_chart['json'] = build_plot()     
        dict_of_plots.append(single_chart)
    return render_template('plots.html', dict_of_plots=dict_of_plots)#snippet=plot_snippet)

if __name__ == '__main__':
    app.run(debug=True)

Template:

    <html>
    <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
    <script type="text/javascript" src="http://mpld3.github.io/js/mpld3.v0.1.js"></script>
    <head>
    </head>
    <body>
    {% for plot in dict_of_plots %}
        <div id="{{ plot['id'] }}"></div>
    {% endfor %}
    <script type="text/javascript">
    {% for plot in dict_of_plots %}
        mpld3.draw_figure("{{ plot['id'] }}", {{ plot['json']|safe }});
    {% endfor %}
    </script>
    </body>
    </html>

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 13, 2014

I think the issue is that valid div ids cannot start with a digit.

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 13, 2014

I believe that's a requirement of HTML, by the way, not of d3/mpld3.

@philsheard
Copy link
Author

That's it! I added a quick fig_ prefix to the template when naming /calling the div ID and it's now showing as many plots as I throw at it. Thanks Jake. I'll take a look to see where I might be able to suggest an addition to the docs to help others in future.

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 13, 2014

Comments on the docs (or even better, pull requests 😄) would be really helpful! Thanks

@radaniba
Copy link

Hello there !
I am a bit confused with the html output of mpld3, is it mandatory to have flask to render the html output ? If not how is the templating work ? Is there any example of multiple figure in a single html page ?
(Sorry I am asking a lot of question, just came through mpld3 and I find it extremely neat)

@jakevdp
Copy link
Collaborator

jakevdp commented Aug 20, 2014

No, you don't need flask.

All mpld3 does is produce JSON or html. Flask is a separate tool that lets you embed this output within a webpage or an app.

If you'd like to simply generate html, you can run something like the following:

import matplotlib.pyplot as plt
import mpld3

fig, ax = plt.subplots()
ax.plot(range(10))
mpld3.save_html(fig, "my_plot.html")

Opening the resulting html file with a browser should show you the plot.

Regarding multiple plots on a page, this stack overflow answer should help: http://stackoverflow.com/questions/22981359/display-multiple-mpld3-exports-on-a-single-html-page

@radaniba
Copy link

Exciting,

I am going to try this

Thanks for doing this @jakevdp

@drvinceknight
Copy link

@jakevdp I apologise for my ignorance and/or inability to find how to do this but how would I embed a json output of mpld3, using:

mpld3.save_json(fig, 'random_choice.json')

into an html slide deck? For clarity, I would rather not clip the json in to the html directly (as I want to be able to rerun my python script to obtain the plots). I'm guessing I'm just missing some basic json/html knowledge...

@jakevdp
Copy link
Collaborator

jakevdp commented Feb 5, 2015

Yes, you'd have to write a one-liner to load the JSON into javascript, and then call mpld3.draw_figure(json)

A google search turned-up this: http://stackoverflow.com/questions/7346563/loading-local-json-file

@drvinceknight
Copy link

I've been trying that (I really don't know what I'm doing here). So would
this be the line I need before your suggestion?

var json = $.getJSON("test.json");

Are there any libraries or js I need to put somewhere? (currently have
terrible WiFi so google-ing isn't that easy and I think that with a lot of
this explanations expect a certain entry level that I am not at :().

Thank you very much for your response! :)

On Thu, 5 Feb 2015 19:43 Jake Vanderplas notifications@github.com wrote:

Yes, you'd have to write a one-liner to load the JSON into javascript, and
then call mpld3.draw_figure(json)

A google search turned-up this:
http://stackoverflow.com/questions/7346563/loading-local-json-file


Reply to this email directly or view it on GitHub
#128 (comment).

@aflaxman
Copy link
Collaborator

aflaxman commented Feb 6, 2015

I would use d3.json to load the json, since you'll need that anyway for mpld3. Here is the javascript to do it:

      d3.json("test.json", function(error, json) {
        if (error) return console.warn(error);
        mpld3.draw_figure("mplplot", json);
      });

And here is a notebook that puts it together, which you will have to download and open with your own IPython because nbviewer is too paranoid to display it.

@drvinceknight
Copy link

Thanks Abraham,

I'll try that out!

Vince

On Fri Feb 06 2015 at 8:31:54 AM Abraham Flaxman notifications@github.com
wrote:

I would use d3.json to load the json, since you'll need that anyway for
mpld3. Here is the javascript to do it:

  d3.json("test.json", function(error, json) {
    if (error) return console.warn(error);
    mpld3.draw_figure("mplplot", json);
  });

And here is a notebook that puts it together
https://gist.github.com/aflaxman/0966ebf06e23e13db1a1, which you will
have to download and open with your own IPython because nbviewer is too
paranoid to display it.


Reply to this email directly or view it on GitHub
#128 (comment).

@aarumuga
Copy link

I am trying to display multiple htmltooltip plugin plots in a page. The plots shows up. But the HTMLtooltip plugin doesnt work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants