将plotly绘图保存到本地文件并插入到html中

66 人关注

我正在使用 python 和 plotly 来制作交互式 html 报告。 This post 提供了一个很好的框架。

如果我在线制作图表(通过 plotly),并将网址插入 html 文件中,它就能工作,但刷新图表需要很长时间。我想知道我是否可以离线制作图表,并将其嵌入到 html 报告中,这样加载速度就不成问题了。

我发现plot offline可以为图表生成一个HTML,但我不知道如何将其嵌入另一个HTML中。有谁能帮忙吗?

python
plotly
cone001
cone001
发布于 2016-03-28
14 个回答
Fermin Silva
Fermin Silva
发布于 2022-06-19
已采纳
0 人赞同

目前有一个更好的选择,那就是在一个div中做离线绘图,而不是一个完整的html。 这个解决方案不涉及任何黑客。

如果你打电话。

plotly.offline.plot(data, filename='file.html')

它创建了一个名为file.html的文件,并在你的网络浏览器中打开它。然而,如果你这样做。

plotly.offline.plot(data, include_plotlyjs=False, output_type='div')

的调用将返回一个只包含创建数据所需的div的字符串,例如。

<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>

请注意,它只是html的一小部分,你应该把它嵌入到一个更大的页面中。为此,我使用一个标准的模板引擎,如Jinga2。

有了它,你可以创建一个html页面,其中有几个以你想要的方式排列的图表,甚至可以把它作为一个服务器对Ajax调用的响应, pretty sweet.

请记住,你需要包括plotly js文件,所有这些图表才能发挥作用。

You could include

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> 

就在放你得到的那个div之前。如果你把这个js放在页面的底部,那么图表won't work.

0_0
谢谢。您的答案 here 其中包含了关键的一句话:"你可以在放上你得到的div之前包括 <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> 。",这为我解决了问题。
@0_0 你是对的。我没有把这部分内容写在这里,因为上面的答案中已经提到了。我也会把它加到这里,供以后参考。
我想知道为什么他们把这些简单的东西作为复活节彩蛋放在那里,....plus 100来回答这个问题。:)
@Fermin Silva 你能举个例子说明如何在ajax调用中返回/使用该返回值吗?
@MahdiGhelichi 你需要 eval 你从ajax得到的代码,因为简单地将html附加到DOM上是不行的。请看一下 subinsb.com/how-to-execute-javascript in-ajax-response (还要记住,盲目地从服务器上执行js可能有点不安全)
JPW
JPW
发布于 2022-06-19
0 人赞同

Option 1 :在您的Jupyter笔记本中使用plotly的离线功能(我想您从您提供的链接中使用的是Jupyter笔记本)。你可以简单地将整个笔记本保存为一个HTML文件。当我这样做时,唯一的外部参考是JQuery;plotly.js将在HTML源中被内联。

Option 2 :最好的方法可能是直接针对 plotly 的 JavaScript 库编码。这方面的文档可以在这里找到。 https://plot.ly/javascript/

更新 :调用内部函数从来都不是一个好主意。我建议使用@Fermin Silva给出的方法。在较新的版本中,现在也有一个专门的函数用于此。 plotly.io.to_html (见 https://plotly.com/python-api-reference/generated/plotly.io.to_html.html )

黑客方案3 (原始版本仅作参考)。如果你真的想继续使用Python,你可以使用一些黑客来提取它生成的HTML。你需要一些最新版本的 plotly(我用 plotly.__version__ == '1.9.6' 测试过)。现在,你可以使用一个内部函数来获取生成的HTML。

from plotly.offline.offline import _plot_html
data_or_figure = [{"x": [1, 2, 3], "y": [3, 1, 6]}]
plot_html, plotdivid, width, height = _plot_html(
    data_or_figure, False, "", True, '100%', 525)
print(plot_html)

你可以简单地将输出结果粘贴在你的 HTML 文档的某个地方。只要确保你在标题中包括对 plotly 的引用。

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

另外,你也可以引用你用来生成HTML的确切plotly版本,或者内联JavaScript源代码(这样可以消除任何外部依赖;但是要注意法律问题)。

You end up with some HTML code like this:

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> </head> <!-- Output from the Python script above: --> <div id="7979e646-13e6-4f44-8d32-d8effc3816df" style="height: 525; width: 100%;" class="plotly-graph-div"></div><script type="text/javascript">window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL="https://plot.ly";Plotly.newPlot("7979e646-13e6-4f44-8d32-d8effc3816df", [{"x": [1, 2, 3], "y": [3, 1, 6]}], {}, {"showLink": false, "linkText": ""})</script> </body> </html>

Note:该函数名称开头的下划线表明,_plot_html并不是为了从外部代码中调用。因此,这段代码很可能会在未来的 plotly 版本中被破坏。

Ben
在我的Sankey图测试中, _plot_html 产生的代码比 plotly.offline.plot(data, filename='file.html') 少,后者似乎包含JSON中的默认值。js api允许人们在创建后更有效地更新图,json定义与python相同,这确实是一个不错的选择。
GKS
@JPW 鉴于_plot_html已被废弃,现在该如何操作呢?
Maximilian Peters
Maximilian Peters
发布于 2022-06-19
0 人赞同

除了其他答案外,另一个可能的解决方案是在绘图图上使用 to_json()

不需要定制JSON序列化器或使用内部解决方案。

import plotly
# create a simple plot
bar = plotly.graph_objs.Bar(x=['giraffes', 'orangutans', 'monkeys'], 
                            y=[20, 14, 23])
layout = plotly.graph_objs.Layout()
fig = plotly.graph_objs.Figure([bar], layout)
# convert it to JSON
fig_json = fig.to_json()
# a simple HTML template
template = """<html>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
    <div id='divPlotly'></div>
    <script>
        var plotly_data = {}
        Plotly.react('divPlotly', plotly_data.data, plotly_data.layout);
    </script>
</body>
</html>"""
# write the JSON to the HTML template
with open('new_plot.html', 'w') as f:
    f.write(template.format(fig_json))
    
aerijman
你能以这种方式将多个情节传入html模板吗?
@Maximiliano Peters 它做到了。谢谢你。我没有注意到变量被传入字符串的方式和python的格式。你的答案是最干净的,也是唯一能让我快速工作的答案!
Itachi
Itachi
发布于 2022-06-19
0 人赞同

认为答案需要根据最近的版本进行更新。(plotly==4.9.0)

fig.write_html("path/to/file.html")

reference: plotly 文档

David Marx
David Marx
发布于 2022-06-19
0 人赞同

我没能让这些解决方案奏效。我的目标是在一个笔记本中生成绘图,然后在另一个笔记本中发布,所以持久化绘图的HTML对我来说并不重要,重要的是有一些方法可以将绘图序列化到磁盘上,以便在其他地方重新构建。

我想出的解决方案是将 fig 对象序列化为JSON,然后使用plotly的 "json chart schema "从JSON中建立图表。这个演示全部是python的,但如果你需要的话,使用这个JSON序列化策略并直接调用plotly的javascript库,在HTML中建立一个绘图应该是很简单的。

import numpy as np
import json
from plotly.utils import PlotlyJSONEncoder
from plotly.offline import download_plotlyjs, init_notebook_mode, iplot
import plotly.graph_objs as go
init_notebook_mode()
def plotlyfig2json(fig, fpath=None):
    Serialize a plotly figure object to JSON so it can be persisted to disk.
    Figures persisted as JSON can be rebuilt using the plotly JSON chart API:
    http://help.plot.ly/json-chart-schema/
    If `fpath` is provided, JSON is written to file.
    Modified from https://github.com/nteract/nteract/issues/1229
    redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder))
    relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder))
    fig_json=json.dumps({'data': redata,'layout': relayout})
    if fpath:
        with open(fpath, 'wb') as f:
            f.write(fig_json)
    else:
        return fig_json
def plotlyfromjson(fpath):
    """Render a plotly figure from a json file"""
    with open(fpath, 'r') as f:
        v = json.loads(f.read())
    fig = go.Figure(data=v['data'], layout=v['layout'])
    iplot(fig, show_link=False)
## Minimial demo ##
n = 1000
trace = go.Scatter(
    x = np.random.randn(n),
    y = np.random.randn(n),
    mode = 'markers')
fig = go.Figure(data=[trace])
#iplot(fig)
plotlyfig2json(fig, 'myfile.json')
plotlyfromjson('myfile.json')

编辑:根据相关github上的讨论issue,这可能是目前最好的方法。

@Wayne 我认为这是不正确的。OP指出他们正在寻求嵌入一个 互动式 chart, whereas the static image export functionality is by definition not 互动式 (i.e. the image is "static").
VarunVk
VarunVk
发布于 2022-06-19
0 人赞同

最简单的方法是使用 pio from plotly

import plotly.io as pio
pio.write_html(fig, file='Name.html', auto_open=True)

我在重要的会议前用它来存储我的图表,已经用了很多了。

如同在 plotly.com/python/interactive-html-export 如果你添加 kwarg "include_plotlyjs",你可以额外定义整个 plotly.js 是否被保存在 html 中。
Paul Rougieux
Paul Rougieux
发布于 2022-06-19
0 人赞同

你也可以根据问题的答案来使用iframe how to embed html into ipython output ?

plotly.offline.plot(fig, filename='figure.html',validate=False)
from IPython.display import IFrame
IFrame(src='./figure.html', width=1000, height=600)
    
sohail
sohail
发布于 2022-06-19
0 人赞同

要改进下面的代码,你可以直接调用to_plotly_json(),例如:。

def plotlyfig2json(fig, fpath=None):
    Serialize a plotly figure object to JSON so it can be persisted to disk.
    Figures persisted as JSON can be rebuilt using the plotly JSON chart API:
    http://help.plot.ly/json-chart-schema/
    If `fpath` is provided, JSON is written to file.
    Modified from https://github.com/nteract/nteract/issues/1229
    redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder))
    relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder))
    fig_json=json.dumps({'data': redata,'layout': relayout})
    if fpath:
        with open(fpath, 'wb') as f:
            f.write(fig_json)
    else:
        return fig_json
--------------------------------------------
Simple way:
fig = go.Figure(data=['data'], layout=['layout'])
fig.to_plotly_json()    
    
"To improvise "还是你的意思是 "为了 improve code from 这个答案 "?
saaj
saaj
发布于 2022-06-19
0 人赞同

在Plotly 5中(也可能在4中)。 BaseFigure.to_html include_plotlyjs 参数,默认为 True

指定如何将 plotly.js 库包含/加载到输出div字符串中。

如果 True ,输出中会包含一个包含 plotly.js 源代码的脚本标签(~3MB)。用这个选项生成的HTML文件是完全独立的,可以脱机使用。

有趣的是,Plotly的数字HTML嵌入可以用以下方式来说明 Pyodide right here.

const plotlyScript = `
  import plotly.express as px
  fig = px.bar(y=[0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
  fig.to_html(full_html=False)
async function main() {
  const pyodideUrl = 'https://cdn.jsdelivr.net/pyodide/v0.17.0/full/'
  const pyodide = await loadPyodide({'indexURL': pyodideUrl})
  await pyodide.loadPackage(['pandas'])  // needed for plotly
  const html = await pyodide.runPythonAsync(plotlyScript)
  const fragment = document.createRange().createContextualFragment(html)
  const output = document.getElementById('plotly-output')
  output.textContent = ''
  output.append(fragment)
main()
<script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyodide.js"></script>    
<div id="plotly-output">Loading pyodide... It may take a minute.</div>
KansaiRobot
KansaiRobot
发布于 2022-06-19
0 人赞同

要把它嵌入另一个页面,只需使用

<iframe width="560" height="315" title="Plot1" src="./scatter1.html"></iframe>  

但如果你能做到这一点,为什么还要去找麻烦呢?不保存在文件中而不是它,直接嵌入它

import plotly.offline as pyo
import plotly.graph_objs as go
import numpy as np
#generate the Plot
np.random.seed(42)
random_x = np.random.randint(1,101,100)
random_y = np.random.randint(1,101,100)
data = [go.Scatter(
    x = random_x,
    y = random_y,
    mode = 'markers',
the_plot= pyo.plot(data, include_plotlyjs=False, output_type='div')
print(the_plot)
num=11
strTable = '<html><head><title>Plots and Reports</title><script src="https://cdn.plot.ly/plotly-latest.min.js"></script></head><body><table style="width:100%"><tr><th>Plot</th><th>Something else</th></tr>'
strRW = "<tr><td>"+the_plot+ "</td><td>"+str(num)+"</td></tr>"
strTable = strTable+strRW
strTable = strTable+"</table></body></html>"
hs = open("theReport.html", 'w')
hs.write(strTable)
    
Anass Lahrech
Anass Lahrech
发布于 2022-06-19
0 人赞同

我最近需要将Plotly图表导出为HTML文件。

以下是2019年的简单正确方法。

import plotly.offline    
plot(figure, "file.html")
    
Montoya Daniel
Montoya Daniel
发布于 2022-06-19
0 人赞同

如果你想在HTML中插入fig(go.Figure),也许你应该尝试使用它。

注意:其中fig是go.Figure的一个实例,fig包含你的绘图。

import json
import plotly.graph_objects as go
# step 1 convert fig to json
data = fig.to_json() #return one string
# step 2, save data in the file
filename = 'name_file.json'
with open ('' + filename + 'w') as file:
  json.dump(data, file, indent=4)

之后你就可以在HTML代码中插入json文件,但你应该插入依赖关系。

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    
DSeal6
DSeal6
发布于 2022-06-19
0 人赞同

只是为那些希望将plotly数字以HTML可读字符串的形式呈现在HTML模板中的人补充这个主题。我最近不得不这样做,想分享一下...

基本上,如果你有一个HTML文件,你想把一个plotly的数字作为静态图像放置,一种方法是插入一个img类,并在src kwarg中添加一个数字的字符串表示。比如说。

class="max-width" border="0" style="display:block; padding:0px; line-; font-size: 0px; border:0px; color:#000000;text-decoration:none;max-width:100% !important; width:100%;" align="top" height="350" width="1000" alt="" src="" <---- this is where you can add a string rep of figure

要从 plotly 中生成任何图形的字符串代表,你可以使用以下函数。

def render_base64_image_from_plotly_fig(fig):
    """Render a base64 encoded image from a plotly figure.
    Args:
        fig (dict): Plotly figure information (data and layout).
    Returns:
        str: base64 encoded string of plotly graph.
    # render figure to .png image
    img_bytes = fig.to_image(format="png")
    # encode into b64
    encoding = b64encode(img_bytes).decode()
    # create b64 image placeholder
    img_b64 = "data:image/png;base64," + encoding
    return img_b64

输出字符串可以插入src="",您将有一个HTML渲染的plotly图表版本。

注意:如果你直接从IDE中复制,要注意输出字符串的截断......这让我很头疼。基本上,一个被截断的base64字符串会以'.'截断,但'.'在base64字符串中是一个被禁止的字符。如果你想保证这种情况不会发生,就把输出的字符串写到你的机器上的一个.txt文件里,然后从里面复制和粘贴。

with open('html.txt', 'w') as f:
    f.write(img_b64)
    f.close()

我希望这能帮助到别人

tensor
tensor
发布于 2022-06-19
0 人赞同

作为Plotly的替代方案,你可以使用utilmy来保存HTML 在磁盘上,无需额外配置。

!pip install utilmy
from utilmy.viz import vizhtml as vi
import pandas as pd
url='https://raw.githubusercontent.com/AlexAdvent/high_charts/main/data/stock_data.csv'
df = pd.read_csv(url)
doc.h2('Stock Market Analysis')
doc.h4('plot Data in table format')
doc.table(df,  table_id="test", custom_css_class='intro',use_datatable=True)
doc.hr()
doc.h4('Stock tseries graph')
doc.plot_tseries(
    df,coldate    = 'Date', 
    date_format   = '%m/%d/%Y', 
    coly1         = ['Open', 'High', 'Low', 'Close'],