【问题标题】:python save plotly plot to local file and insert into htmlpython将绘图保存到本地文件并插入到html中
【发布时间】:2016-07-15 17:40:23
【问题描述】:

我正在使用 python 和 plotly 来生成交互式 html 报告。 This post 提供了一个不错的框架。

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

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

【问题讨论】:

    标签: python plotly


    【解决方案1】:

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

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

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

    有趣的是,可以在此处使用Pyodide 说明 HTML 嵌入。

    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>

    【讨论】:

      【解决方案2】:

      如果你想在 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>
      

      【讨论】:

        【解决方案3】:

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

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

        参考:plotly documentation

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

          【解决方案5】:

          选项 1:在您的 Jupyter Notebook 中使用 plotly 的离线功能(我想您正在使用您提供的链接中的 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 中中断。

          【讨论】:

          • 在我的桑基图测试中,_plot_html 生成的代码少于plotly.offline.plot(data, filename='file.html'),后者似乎包含 JSON 中的默认值。 js api可以让创建后更高效地更新图表,json定义和python中的一样,确实是一个不错的选择。;
          • @JPW 鉴于 _plot_html 已被弃用,现在如何工作?
          【解决方案6】:

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

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

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

          【讨论】:

            【解决方案7】:

            您也可以根据问题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)
            

            【讨论】:

              【解决方案8】:

              除了其他答案之外,另一种可能的解决方案是在情节图上使用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))
              

              【讨论】:

              • 你能通过这种方式将多个绘图传递到 html 模板中吗?
              • @Maximiliano Peters 确实如此。谢谢。我没有注意变量通过python格式传递到字符串中的方式。你的答案是最干净的,也是唯一对我有用的答案!
              【解决方案9】:

              要即兴发挥以下代码,您可以调用 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 improvise" 还是你的意思是"to improves this answer 的代码"?
              【解决方案10】:

              目前有一个更好的选择,即离线绘制到 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 调用的服务器响应返回,非常棒。

              更新:

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

              你可以包括

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

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

              【讨论】:

              • 谢谢。您的回答 here 包含关键行,“您可以在放置您得到的 div 之前包含 &lt;script src="https://cdn.plot.ly/plotly-latest.min.js"&gt;&lt;/script&gt;。”,这为我解决了这个问题。
              • @0_0 你是对的。我没有在此处包含该部分,因为上面的答案中已经提到过。我也会在这里添加以供将来参考
              • 我想知道为什么他们将这些简单的东西作为复活节彩蛋保留在文档中......加上 100 到这个答案! :)
              • @Fermin Silva 你能举例说明如何在 ajax 调用中返回/使用返回值吗?
              • @MahdiGhelichi 您需要 eval 从 ajax 返回的代码,因为简单地将 html 附加到 DOM 是行不通的。看看subinsb.com/how-to-execute-javascript-in-ajax-response(还要记住从服务器盲目执行js可能有点不安全)
              【解决方案11】:

              我无法让任何这些解决方案发挥作用。我的目标是在一个笔记本中生成绘图并将它们发布到另一个笔记本中,因此保留绘图 HTML 对我来说并不像简单地使用某种方法将绘图序列化到磁盘以在其他地方重建一样重要。

              我想出的解决方案是将fig 对象序列化为JSON,然后使用plotly 的“json 图表模式”从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 指定他们正在寻求嵌入 交互式 图表,而静态图像导出功能根据定义是非交互式的(即图像是“静态的”)。
              猜你喜欢
              • 1970-01-01
              • 2014-03-22
              • 1970-01-01
              • 2023-02-06
              • 1970-01-01
              • 1970-01-01
              • 2013-06-08
              相关资源
              最近更新 更多