LoginSignup
10
9

More than 5 years have passed since last update.

python bokehで作ったplotをhtmlに埋め込む(Embed to html)

Last updated at Posted at 2018-08-02

前回作ったbokehのplotをhtmlに埋め込む

参考元:
https://www.udemy.com/the-python-mega-course/learn/v4/overview

bokehのチュートリアル:Embedding Plots
https://bokeh.pydata.org/en/latest/docs/user_guide/embed.html

bokhe.resourcesについて
https://bokeh.pydata.org/en/latest/docs/reference/resources.html

使うライブラリー:

from bokeh.embed import components
from bokeh.resources import CDN

htmlに埋め込むための部品を取り出す

bokehで作ったplotをhtmlに埋め込むためには4つの部品が居る。

  1. bokehのplot情報。bokheをshow()して表示されるhtmlで検証すれば確認できる。HTMLタグの<div class="bk-root">...</div>ブロック。
  2. Javascriptブロック。HTMLタグでは<script>ブロック
  3. cssのリンクURL
  4. javascriptのリンクURL

これら4つがあればhtmlにbokehのplot(グラフ)を埋め込むことができる。

plot元。前回の記事と全く同じ

bokehで作ったキャンドルスティックチャート(plot)
from datetime import datetime as dt
from bokeh.plotting import figure, show, output_file
from pandas_datareader import data as pdr
import fix_yahoo_finance as yf

start = dt(2018,4,1)
end = dt(2018,7,31)

yf.pdr_override()
df=pdr.get_data_yahoo(tickers="FB", start=start, end=end)

def inc_dec(close, open_):
    if close>open_:
        value="Increase"
    elif close<open_:
        value="Decrease"
    else:
        value="Equal"
    return value

df["Status"]=[inc_dec(c,o) for c,o in zip(df.Close, df.Open)]
df["Middle"]=(df.Close+df.Open)/2
df["Height"]=abs(df.Open-df.Close)

p=figure(x_axis_type="datetime", width=1000, height=300, title="Candlestick Chart", sizing_mode="scale_width")
p.grid.grid_line_alpha=0.3

p.segment(df.index, df.High, df.index, df.Low, color="black")

millisecond_of_12hour=12*60*60*1000
p.rect(df.index[df.Status=="Increase"], df.Middle[df.Status=="Increase"], millisecond_of_12hour, df.Height[df.Status=="Increase"],
       fill_color="#CCFFFF", line_color="black")
p.rect(df.index[df.Status=="Decrease"], df.Middle[df.Status=="Decrease"], millisecond_of_12hour, df.Height[df.Status=="Decrease"],
       fill_color="#FF3333", line_color="black")

output_file("Chandlestick Chart.html")
show(p)
上記のpの要素を取得。
from bokeh.embed import components
from bokeh.resources import CDN

script1, div1  = components(p)
script1
>>>
<script type="application/json" id=...
#すげぇ長いので以下略
</script>

div1
>>>
<div class="bk-root">
    <div class="bk-plotdiv" id="65ac11b3-23d4-4103-8fde-209bf594f2f1"></div>
</div> 


cdn_js=CDN.js_files
>>>
['https://cdn.pydata.org/bokeh/release/bokeh-0.12.13.min.js',
 'https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.13.min.js',
 'https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.13.min.js',
 'https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.13.min.js']

cdn_css=CDN.css_files
>>>
['https://cdn.pydata.org/bokeh/release/bokeh-0.12.13.min.css',
 'https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.13.min.css',
 'https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.13.min.css']

#今回はindex0のみ必要
cdn_js=CDN.js_files[0]
cdn_css=CDN.css_files[0]

  1. componentsメソッドにplotオブジェクトを渡せば、<script>ブロックと、<div>ブロック(plot情報)をstr型で取得可能
  2. javascriptのリンクURLとcssのリンクURLは、htmlから直接コピペしてきてもいい。しかし、CDNで取得可能。CDN.js_filesならjavascriptのURLがリストで得られる。widgetはスライダーなどを使ったplotなら必要。tableは表を使った場合。glは3Dグラフィックを使った場合に必要。今回はindex0のurlだけでおk。
  3. cssにはCDN.css_filesを使う
  4. これらscript1div1cdn_jscdn_cssをhtmlに渡す。

実際に表示させる

以前にflaskvirtualenvで作った仮想環境のhtmlに埋め込む。
htmlのコード全部をここに記述はしないが、重要なのだけ。

plot.html
{%extends "layout.html"%}
{%block content%}
<link rel="stylesheet" href={{cdn_css | safe}} type="text/css" />

<script type="text/javascript" src={{cdn_js | safe}}></script>
<div class="plot">
    <p>test for plot embeding</p>
</div>
{{script1 | safe}}
{{div1 | safe}}
{%endblock%}
  1. {%extends "layout.html"%}はflaskで別のhtmlコードを継承できる。{%block content%}{%endblock%}のコードが挿入される。
  2. {{ .py上の変数名 }}で.pyがファイルの変数を受け取ることができる。cdn_csscdn_jsscript1div1の4つ変数を受け取っている。flaskに付属してるjinja2ライブラリーの機能。
  3. {{|safe}}|safeは文字列などのエスケープを無効にする。
app.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/plot/')
def plot():
    #venv。仮想環境上にここでimportされてるmodule全部入れなきゃ動かないぜ
    import pandas as pd
    from datetime import datetime
    from bokeh.plotting import figure,show,output_file
    pd.core.common.is_list_like = pd.api.types.is_list_like
    from pandas_datareader import data as pdr
    import fix_yahoo_finance as yf

    #追加
    from bokeh.embed import components
    from bokeh.resources import CDN

    start=datetime(2018,1,1)
    end=datetime(2018,6,10)

    yf.pdr_override()
    #GOOG google
    df=pdr.get_data_yahoo(tickers="GOOG",start=start,end=end)

    def inc_dec(close, open_):
        if close > open_:
            value="Increase"
        elif close < open_:
            value="Decrease"
        else:
            value="Equal"
        return value

    df["Status"]=[inc_dec(c, o) for c, o in zip(df.Close, df.Open)]
    df["Middle"]=(df.Open+df.Close)/2
    df["Height"]=abs(df.Open-df.Close)

    p=figure(x_axis_type="datetime", width=1000, height=300, title="Candlestick Chart", sizing_mode="scale_width")
    p.grid.grid_line_alpha=0.3

    p.segment(df.index, df.High, df.index, df.Low, color="black")

    millisecond_of_hour12=12*60*60*1000
    p.rect(df.index[df.Status=="Increase"],df.Middle[df.Status=="Increase"],millisecond_of_hour12,
        df.Height[df.Status=="Increase"], fill_color="#CCFFFF", line_color="black")
    p.rect(df.index[df.Status=="Decrease"],df.Middle[df.Status=="Decrease"],millisecond_of_hour12,
        df.Height[df.Status=="Decrease"], fill_color="#FF3333", line_color="black")

    #追加
    script1, div1  = components(p)
    cdn_js=CDN.js_files[0]
    cdn_css=CDN.css_files[0]

    return render_template("plot.html",
    script1=script1,
    div1=div1,
    cdn_js=cdn_js,
    cdn_css=cdn_css)

    #output_file("CandileStick.html")
    #show(p)

@app.route('/')
def home():
    return render_template("home.html")

@app.route('/about/')
def about():
    return render_template("about.html")

if __name__=="__main__":
    app.run(debug=True)

flaskvirtualenvについてここではあまり触らない。
ただflaskはhtmlと.pyを繋げる。virtualenvは仮想環境を構築できる。
1. pd.core.common.is_list_like = pd.api.types.is_list_likeは仮想環境上でpandasを動かそうとするとエラーはく対策。pandasのversionが0.2~0.6だとエラーになるっぽい。v0.7で解決されるらしい。 参考元:stackoverflow :https://stackoverflow.com/questions/50394873/import-pandas-datareader-gives-importerror-cannot-import-name-is-list-like
2. render_templateでtemplatesフォルダにあるhtmlがレンダリング(描写)される。ついでに4つの変数もhtmlに渡している。
3. plot.htmlのURLにアクセスしたときに、bokehのplotが表示されるようになった

あとがき

日本人はFlaskよりDjangoのほうが好き?

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9