2017-10-30 26 views
1

私はbokehのビジュアライゼーションに取り組んでいます。クライアント側で対話性を実装するのにCustomJSを使用しているので、 JavaScriptを使用して。 ColumnDataSourceCustomJSに渡すと、プロットをインタラクティブに更新できます。`CustomJS`を使ってPythonからbokehに任意の` json`データを渡す方法

しかし、私は何もできません、いくつかの任意のjsonデータを出力htmlに埋め込むだけです。以下の自己完結型の例を参照してください:私の場合は

from bokeh.io import output_file 
from bokeh.layouts import widgetbox 
from bokeh.models import CustomJS 
from bokeh.models.widgets import Div, Button 
from bokeh.plotting import show 

data_for_client = { 
    "x": 3, 
    "y": { 
     "foo": [1, 2, 3], 
     "bar": {"some_bar": "doge", "other bar": "much json"} 
    }, 
    "z": [[1, 2], [3, 4]] 
} 

callback = CustomJS(args={"data_for_client": data_for_client}, code=""" 
    console.log(data_for_client); 
""") 

content = widgetbox(
    Button(label="click here", callback=callback), 
    Div(text="some complicated interactive stuff based on json content here") 
) 

output_file("issue.html") 
show(content) 

data_for_clientjson複雑深くネストされ、このjsonの異なる部分がいくつかのウィジェットとのユーザインタラクションに応じて使用されています。

ユーザーの操作に基づいてjsonデータに変更を加える必要はありません。また、リスナーや特別なものを添付する必要はありません。 CustomJSコールバックで使用できるjson値の内容が必要です。

単純な列データの場合は、ColumnDataSourceにデータをラップし、CustomJSにargとして渡すことができますが、普通のjsonデータと似たものは見つかりません。上記のコードは、メッセージで失敗します。

ValueError: expected an element of Dict(String, Instance(Model)), got {'data_for_client': {'x': 3, 'y': {'foo': [1, 2, 3], 'bar': {'some_bar': 'doge', 'other bar': 'much json'}}, 'z': [[1, 2], [3, 4]]}} 

答えて

1

そうでなければ、辞書のキーとして辞書({...}を)使用することはできませんので、あなたは、関連するラインに"data_for_client"に最初data_for_clientを変更する必要があります。

from bokeh.io import output_file 
from bokeh.layouts import widgetbox 
from bokeh.models import CustomJS 
from bokeh.models.widgets import Div, Button 
from bokeh.plotting import show 

data_for_client = { 
    "x": 3, 
    "y": { 
     "foo": [1, 2, 3], 
     "bar": {"some_bar": "doge", "other bar": "much json"} 
    }, 
    "z": [[1, 2], [3, 4]] 
} 

# Here is the change: 
callback = CustomJS(args={"data_for_client": data_for_client}, code=""" 
    console.log(data_for_client); 
""") 

content = widgetbox(
    Button(label="click here", callback=callback), 
    Div(text="some complicated interactive stuff based on json content here") 
) 

output_file("issue.html") 
show(content) 
+0

[OK]を私の一部のfacepalm。しかし、これは問題を解決するものではありません。私はこの点について質問を編集しました。 –

+0

Ajax/Json-Datasourceのようなものがあると思われます。 – MEE

+0

Ajaxデータソースが存在し、私が知る限りWebサーバーからデータを送信するためのものです。私はドキュメントでjsonのソースが見つかりませんでした。 –

1

あなたは文字列として渡すことができます、私はそこにjson文字列からjsonデータを読み込むためのjavascriptがあると思います。これはPythonに少なくとも存在します。

from bokeh.io import show 
from bokeh.layouts import widgetbox 
from bokeh.models import CustomJS, ColumnDataSource 
from bokeh.models.widgets import Div, Button 
import json 

data_for_client = { 
    "x": [3], 
    "y": { 
      "foo": [1, 2, 3], 
      "bar": {"some_bar": "doge", "other bar": "much json"} 
     }, 
    "z": [[1, 2], [3, 4]], 
} 

json_string = json.dumps(data_for_client) 

DumButton = Button(label=json_string) 

# Here is the change: 
callback = CustomJS(args={"db":DumButton}, code=""" 
    console.log(db.label); 
    var test=JSON.parse(db.label); 
    console.log(test); 
    for(key in test){console.log(test[key])} 
    """) 

content = widgetbox(
    Button(label="click here", callback=callback), 
) 

show(content) 
+0

これは技術的には機能しますが、JSONを解析する必要があるのでJSONが大きい場合は理想的ではありません(JSON.parse () 'javascriptで)' callback'が呼ばれるたびに呼び出されます。私は 'ColumnDataSource'の単一のセルに文字列としてjson全体を渡すことで、あなたと同様のソリューションを試しましたが、ユーザーのやりとりに目立つ遅延がありました。 –

+0

@SamDeMeyer私は動作するコードで私の答えを編集しました。 Python側ではjson.dumps、JS側ではjson.parseoを使用しています。それをもっと速くする方法があるかどうかはわかりません。 jsonをPython上のファイルに保存してからcustomJSから読み込む方が速いでしょうか?入れ子にされた双子屋を渡すためのきれいなボケの作り方を私は知らない。リストをリストにマップし、ColumnDataSourceを使用することができます – Seb

+0

問題は 'var test = JSON.parse(db.label);'行の 'JSON.parse'を呼び出すことです。これは、 'callback'が呼び出されるたびに(つまり、この例では'ここをクリック 'ボタンをクリックするたびに)再評価されます。 'ColumnDataSource'の場合、ブラウザにドキュメントをロードすると、データは一度だけ解析されます。現在のところ、他の方法はないとあなたは正しいかもしれません。しかし、この機能はとてもシンプルで、そこにあるはずです。 –

関連する問題