2016-12-07 11 views
0

ColumnDataSourceの内容がインラインで変更されたことを図に知らせる方法があるかどうかは疑問です。私はnumpy配列を含むColumnDataSourceを持っています。図の更新時には、毎回メモリを割り当てるのを節約するためにいくつかのインプレース配列スライスの割り当てをしたいだけです。更新を強制的に表示するには、some_renderer.data_has_changed()の行に沿って何かを表示してください。次のコードは、realloc=True、各更新時numpyアレイを作成するコストで所望の挙動を与え、そしてrealloc=Falseパッチを更新しない問題を示す:ColumnDataSourceのnumpy配列の内容を変更するときにBokeh図形が更新されない

import numpy as np 
from bokeh.plotting import figure 
from bokeh.models import ColumnDataSource 
from bokeh.layouts import column 
from bokeh.io import curdoc 
from bokeh.models.widgets import Select 


class AppData: 

    def __init__(self, n, realloc=False): 
     self.p_source = None 
     self.c_source = None 
     self.x = np.linspace(0, 10, 20) 
     self.n = n 
     self.ys = [np.sin(self.x) - i for i in range(self.n)] 
     self.realloc = realloc 
     self.line = None 
     self.patch = None 

    def update_module(self, a, b): 
     assert b - a == 5 

     p_data = dict() 
     c_data = dict() 
     if self.p_source is not None: 
      p_data.update(self.p_source.data) 
     if self.c_source is not None: 
      c_data.update(self.c_source.data) 
     ys = [self.ys[j] for j in range(a, b)] 
     if "x" not in c_data or self.realloc: 
      c_data["x"] = self.x 
     if "x" not in p_data or self.realloc: 
      p_data["x"] = np.array(c_data["x"].tolist() + c_data["x"][::-1].tolist()) 

     n_r = len(ys[0]) 
     n_p = 2*n_r 
     if "ys" not in p_data or self.realloc: 
      p_data["ys"] = np.empty((n_p)) 

     p_data["ys"][:n_r] = ys[0] 
     p_data["ys"][n_r:] = np.flipud(ys[-1]) 
     c_data["y"] = ys[2] 
     if self.p_source is None: 
      self.p_source = ColumnDataSource(data=p_data) 
     else: 
      self.p_source.data = p_data 
     if self.c_source is None: 
      self.c_source = ColumnDataSource(data=c_data) 
     else: 
      self.c_source.data = c_data 
     if self.line is not None: 
      print(max(self.line.data_source.data["y"])) 
      print(max(self.patch.data_source.data["ys"])) # The value changes, but the figure does not! 

# initialize 
realloc = False # Not updating figure - set to True to get the expected behaviour 
app_data = AppData(10, realloc=realloc) 
app_data.update_module(4, 4 + 5) 
s1 = figure(width=500, plot_height=125, title=None, toolbar_location="above") 
app_data.line = s1.line("x", "y", source=app_data.c_source) 
app_data.patch = s1.patch("x", "ys", source=app_data.p_source, alpha=0.3, line_width=0) 
select = Select(title="Case", options=[str(i) for i in range(5)], value="4") 

def select_case(attrname, old, new): 
    a = int(select.value) 
    app_data.update_module(a, a + 5) 

select.on_change('value', select_case) 
layout = column(select, s1) 
curdoc().add_root(layout) 
curdoc().title = "Example of patches {}being updated".format("not " if not realloc else "") 

上記のコードはbokeh serve --show example.pyと実行可能であるべきで、与えられましたbokehバージョン0.12.3であり、スクリプトがexample.pyとして保存されていること。

希望のプロットは、色付きパッチを移動して、ラインが常にその中央にとどまるようにしますが、reallocTrueに設定されている場合、パッチは更新されません。

ご協力いただければ幸いです!

答えて

0

データは最終的にシリアル化され、ネットワーク経由で送信され、BokehJSクライアントライブラリでシリアル化されなくなります。スライシングで賢明にしようとすると節約はほとんどありません。それは他のステップからのオーバーヘッドを上回ります。

データソースの更新によってプロットが更新されるようにするには、データソースの.data属性をすべてに更新することをお勧めします。一例として、sliders demoから:検討が効率であるときは全く真実である

# Generate the new curve 
x = np.linspace(0, 4*np.pi, N) 
y = a*np.sin(k*x + w) + b 

# This causes the plot to change -- nothing else needed 
source.data = dict(x=x, y=y) 
+1

。この例は実際に私のコードの煮詰めのバージョンです。最初の考えは、変更可能なデータをさまざまなレンダラーにバインドしてから、自動的にプロットを更新するか、またはレンダラーのリストをループして更新するように指示することでした。今私のデザインを再考する必要があることがわかります。ありがとう! –

+0

Bokehの "更新することを伝える"ことはあまりありません。新しいプロパティ値を設定するのは一般的に自動的に行われます。 1つの例外は、CDS列*を変更している場合です。このような変更は検出できないため、呼び出すことができる明示的な「トリガ」があります。しかし、それは(おそらく)有用な唯一の時間です。警告は、すべてのCDSカラムは常に同じ長さ*でなければならないということです。そのため、一度に '.data 'をすべて設定するのが最も安全で最も推奨される方法です。 – bigreddot

+0

おそらく興味があるかもしれませんが、[バッチ更新をサポートする]問題は未解決です(https://github.com/bokeh/bokeh/issues/5438) – bigreddot

関連する問題