web-dev-qa-db-ja.com

python plotlyプロットをローカルファイルに保存し、htmlに挿入します

私はpythonを使用し、製品にインタラクティブなHTMLレポートをプロットします。 この投稿 は素敵なフレームワークを提供します。

(plotlyを介して)オンラインでプロットを作成し、htmlファイルにURLを挿入すると、動作しますが、チャートの更新に時間がかかります。グラフをオフラインで作成し、htmlレポートに埋め込むことができるので、読み込み速度は問題になりません。

プロットをオフラインで作成するとチャートのhtmlが生成されますが、別のhtmlに埋め込む方法がわかりません。誰でも助けることができますか?

39
cone001

オプション1:Jupyter Notebookでplotlyのオフライン機能を使用します(提供しているリンクからJupyter Notebookを使用していると仮定します)。ノートブック全体をHTMLファイルとして簡単に保存できます。これを行う場合、外部参照はJQueryのみです。 plotly.jsはHTMLソースにインライン化されます。

オプション2:最善の方法は、おそらくplotlyのJavaScriptライブラリに対して直接コーディングすることです。これに関するドキュメントはここにあります: https://plot.ly/javascript/

Hackyオプション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の生成またはJavaScriptソースのインライン化に使用した正確なプロットバージョンを参照することもできます(外部依存関係は削除されますが、法的側面に注意してください)。

次のような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の将来のバージョンで壊れる可能性があります。

21
JPW

現在のところ、完全なhtmlではなくdivにオフラインでプロットするというより良い代替方法があります。このソリューションには、ハッキングは含まれていません。

あなたが電話した場合:

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

file.htmlという名前のファイルを作成し、Webブラウザーで開きます。ただし、次の場合:

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などの標準テンプレートエンジンを使用します。

これにより、複数のチャートを必要に応じて配置した1つのhtmlページを作成し、それをajax呼び出しに対するサーバー応答として返すこともできます。

更新:

これらすべてのチャートを機能させるには、プロットのjsファイルを含める必要があることに注意してください。

含めることができます

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

取得したdivを配置する直前。このjsをページの下部に配置すると、チャートは機能しません

110
Fermin Silva

これらのソリューションを機能させることはできませんでした。私の目標は、あるノートブックでプロットを生成し、別のノートブックで公開することでした。そのため、プロットHTMLを永続化することは、プロットをディスクにシリアル化して他の場所で再構築する方法を単に持つことほど重要ではありませんでした。

私が思いついた解決策は、figオブジェクトをJSONにシリアル化し、plotlyの「json chart schema」を使用してJSONからプロットを作成することです。このデモはすべてpythonですが、このJSONシリアル化戦略を使用してHTMLでプロットを作成し、それが必要な場合はプロットJavaScriptを直接呼び出すのは簡単です。

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 の議論ごとに、これがおそらく現在の最良のアプローチです。

7
David Marx

他の答えに加えて、別の可能な解決策は、プロット図で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))
2

以下のコードを即興で演奏するには、ex:の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()    

1
sohail