34

I recently discovered plotly and find it really good for graphing, now I have a problem which I want to save multiple plot into a single html, how to do it please?

*I want to save multiple plot, i.e fig, fig1, fig 2 and so on, NOT one subplot which has multiple plot in it, because I found that the plot within subplot is too small.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Victor
  • 659
  • 3
  • 8
  • 19

4 Answers4

82

In the Plotly API there is a function to_html which returns HTML of the figure. Moreover, you can set option param full_html=False which will give you just DIV containing figure.

You can just write multiple figures to one HTML by appending DIVs containing figures:

with open('p_graph.html', 'a') as f:
    f.write(fig1.to_html(full_html=False, include_plotlyjs='cdn'))
    f.write(fig2.to_html(full_html=False, include_plotlyjs='cdn'))
    f.write(fig3.to_html(full_html=False, include_plotlyjs='cdn'))

https://plot.ly/python-api-reference/generated/plotly.io.to_html.html

You can also use Beautiful Soup to do DOM manipulation and insert DIV exactly where you need it in the HTML.

https://beautiful-soup-4.readthedocs.io/en/latest/#append

remram
  • 4,805
  • 1
  • 29
  • 42
Milos K
  • 1,009
  • 8
  • 5
  • This is exactly what I want, thank you for your beautiful neat suggestion! – Victor Jan 23 '20 at 15:09
  • I want to further ask, after I have got this html generated, what is the fastest/most simplest way to save it as pdf? – Victor Jan 23 '20 at 18:43
  • 7
    Install pdfkit https://pypi.org/project/pdfkit/ `pip install pdfkit` Then you can use it like: ```import pdfkit pdfkit.from_file('p_graph.html', 'out.pdf') ``` – Milos K Jan 23 '20 at 19:18
  • much appreciate! – Victor Jan 23 '20 at 22:42
  • f.write(fig.to_html(full_html=False, include_plotlyjs='cdn')) in this code, can fig be a variable i.e. figure_name? so that I can use a for loop to loop through my list of fig name and do something like figure_name.to_html() – Victor Jan 23 '20 at 22:55
  • If I understood your question correctly the answer is yes. In the code I've provided fig is a figure object. You can create a list of figure objects and then iterate through the list of figures and do the same logic. For example if you have `figures= [figure1, figure2, fiigure3]`: `for fig in figures: f.write(fig.to_html(full_html=False, include_plotlyjs='cdn'))` Ths part goes after you open the file for writing. – Milos K Jan 24 '20 at 11:42
  • yes, I want to do something like this, and I managed to find a solution, which i actually need to use the function eval(), so it your code it would be figures= [figure1, figure2, fiigure3]: for fig in figures: f.write(eval(fig).to_html(full_html=False, include_plotlyjs='cdn')) – Victor Jan 24 '20 at 12:39
  • 4
    I suggest using `include_plotlyjs='cdn'` only in the first figure and `include_plotlyjs=False` in subsequent. No need to load javascript multiple times. – TNT Jan 28 '21 at 13:54
  • i do not understand the inputs for this solution. how I have to save the fig(s) – Alex May 02 '21 at 16:33
  • this might be a really stupid question, I got this to work, able to write all the plotly chart into one html, but I cant format this html chart. How do I insert
    in btween charts
    – llu13701 Mar 25 '22 at 18:26
2

It depend how do you build the html page. If it is with from plotly.offline.plot(fig, filename='name.html') than it is not possible. As you mentioned than subplot are too small, you can play with play with height and weight variable in layout:

On layout:

from plotly.offline import plot
from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots(
rows=3, cols=1, shared_xaxes=True, 
vertical_spacing=0.02)

fig.add_trace(go.Scatter(x=[0, 1, 2], y=[10, 11, 12]),
          row=3, col=1)

fig.add_trace(go.Scatter(x=[2, 3, 4], y=[100, 110, 120]),
          row=2, col=1)

fig.add_trace(go.Scatter(x=[3, 4, 5], y=[1000, 1100, 1200]),
          row=1, col=1)

fig.update_layout(height=1200, width=600,
              title_text="Stacked Subplots with Shared X-Axes")
fig['layout']['yaxis1'].update(domain=[0, 0.2])
fig['layout']['yaxis2'].update(domain=[0.3, 0.7])
fig['layout']['yaxis3'].update(domain=[0.8, 1])

plotly.offline.plot(fig, filename='name.html')

If you build by yourself the html page you can render the html divs as http://www.codingwithricky.com/2019/08/28/easy-django-plotly/ and play on height and width variable of layout to make it bigger or smaller.

Renaud
  • 2,709
  • 2
  • 9
  • 24
2

Here is an example that looks pretty good:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import numpy as np
import plotly

y1 = np.random.randn(200) - 1
y2 = np.random.randn(200)
y3 = np.random.randn(200) + 1
x = np.linspace(0, 1, 200)

colors = ['#3f3f3f', '#00bfff', '#ff7f00']

fig = make_subplots(
    rows=3, cols=2,



    column_widths=[0.55, 0.45],
    


    row_heights=[1., 1., 1.],
    specs=[[{"type": "scatter"}, {"type": "xy"}],
           [{"type": "scatter"}, {"type": "xy", "rowspan": 2}],
           [{"type": "scatter"},            None           ]])


fig.add_trace(
    go.Scatter(x = x, 
                y = y1,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#3f3f3f',
                width=1),
                showlegend=False,
                ),
    row=1, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y2,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#00bfff',
                width=1),
                showlegend=False,
                ),
    row=2, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y3,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#ff7f00',
                width=1),
                showlegend=False,
                ),
    row=3, col=1
)


boxfig= go.Figure(data=[go.Box(x=y1, showlegend=False, notched=True, marker_color="#3f3f3f", name='3'),
                        go.Box(x=y2, showlegend=False, notched=True, marker_color="#00bfff", name='2'),
                        go.Box(x=y3, showlegend=False, notched=True, marker_color="#ff7f00", name='1')])

for k in range(len(boxfig.data)):
     fig.add_trace(boxfig.data[k], row=1, col=2)

group_labels = ['Group 1', 'Group 2', 'Group 3']
hist_data = [y1, y2, y3]

distplfig = ff.create_distplot(hist_data, group_labels, colors=colors,
                         bin_size=.2, show_rug=False)

for k in range(len(distplfig.data)):
    fig.add_trace(distplfig.data[k],
    row=2, col=2
)
fig.update_layout(barmode='overlay')
plotly.offline.plot(fig, filename='test.html')
#fig.show()
Essegn
  • 153
  • 1
  • 9
1

building on @mil0s answer, here is a small function that takes several plotly images and combined them into one html file, with a possible separator between them, and an auto-open function like in plotly:

def combine_plotly_figs_to_html(plotly_figs, html_fname, include_plotlyjs='cdn', 
                                separator=None, auto_open=False):
    with open(html_fname, 'w') as f:
        f.write(plotly_figs[0].to_html(include_plotlyjs=include_plotlyjs))
        for fig in plotly_figs[1:]:
            if separator:
                f.write(separator)
            f.write(fig.to_html(full_html=False, include_plotlyjs=False))

    if auto_open:
        import pathlib, webbrowser
        uri = pathlib.Path(html_fname).absolute().as_uri()
        webbrowser.open(uri)
Amir
  • 1,871
  • 1
  • 12
  • 10