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

python save plotly plot to local file and insert into html

我正在使用 python 并计划生成交互式 html 报告。 This post 给出了一个很好的框架。

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

我发现离线绘图会为图表生成 html,但我不知道如何将其嵌入另一个 html。有人可以帮忙吗?

选项 1:在您的 Jupyter Notebook 中使用 plotly 的离线功能(我想您正在使用您提供的 link 中的 Jupyter Notebook)。您可以简单地将整个笔记本保存为 HTML 文件。当我这样做时,唯一的外部参考是 JQuery; plotly.js 将内嵌在 HTML 源代码中。

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

Hacky Option 3(原始版本仅供参考):如果你真的想继续使用Python,你可以使用一些hack来提取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 或内联 JavaScript 源的确切 plotly 版本(这会删除任何外部依赖性;但请注意法律方面)。

你最终得到一些像这样的 HTML 代码:

<html>
<head>
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
  <!-- 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>

注意:函数名称开头的下划线表明 _plot_html 不应该从外部代码调用。所以这段代码很可能会与 plotly 的未来版本中断。

目前有一个更好的选择,即离线绘制成 div,而不是完整的 html。 此解决方案不涉及任何黑客攻击。

如果您致电:

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

它会创建一个名为 file.html 的文件并在您的网络浏览器中打开它。但是,如果您这样做:

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

调用将 return 一个仅包含创建数据所需的 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 页面,其中包含按您想要的方式排列的多个图表,甚至 return 它可以作为 服务器对 ajax 的响应呼唤,很可爱

更新:

请记住,您需要包含 plotly js 文件才能使所有这些图表正常工作。

你可以包括

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

就在你得到的 div 之前。如果将此 js 放在页面底部,图表 将不起作用 .

我无法使用这些解决方案中的任何一个。我的目标是在一个笔记本中生成图表并在另一个笔记本中发布它们,因此对我来说,保留图表 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 的讨论,这可能是当前最好的方法。

要即兴创作以下代码,您可以调用 to_plotly_json() for ex:,

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_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>
<head>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
    <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))

您也可以根据 how to embed html into ipython output?

问题的答案使用 iframe
plotly.offline.plot(fig, filename='figure.html',validate=False)
from IPython.display import IFrame
IFrame(src='./figure.html', width=1000, height=600)

我最近需要将 Plotly Chart 导出到 HTML 个文件。

这是 2019 年的简单正确方法。

import plotly.offline    
plot(figure, "file.html")

最简单的方法是使用 plotly

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

在重要会议之前,我经常使用它来存储我的图表

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

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

参考:plotly documentation

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

注意:无花果是 go.Figure 的一个实例,无花果包含您的情节。

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>

在 Plotly 5 中(也可能在 4 中),BaseFigure.to_htmlinclude_plotlyjs 参数,默认情况下是 True

Specifies how the plotly.js library is included/loaded in the output div string.

If True, a script tag containing the plotly.js source code (~3MB) is included in the output. HTML files generated with this option are fully self-contained and can be used offline.

有趣的是,Plotly 图 HTML 嵌入可以用 Pyodide 说明。

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>

将它嵌入到另一个页面只需使用

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