2016-06-26 1 views
3

나는 탐구하고자하는 커다란 데이터 세트를 가지고 있습니다. 그러나 나는 여러 플롯을 만들고 싶지 않습니다. 난 단지 x와 y 축에 사용 된 열을 대화식으로 변경할 수있는 단일 플롯을 원하며 플롯 자체가 업데이트됩니다.Bokeh가 플롯 할 대화식으로 열을 변경합니다.

나는이 스크립트를 브라우저에 제공하기 위해 Bokeh를 사용하여 Python/Bokeh를 사용하여이 작업을 수행하려고합니다. 그러나 음모를 업데이트하는 방법을 명확하게 알지 못합니다. 기본 데이터 소스가 변경된 예제가 많이 있지만이 작업을 원하지는 않습니다. 단지 어떤 컬럼이 플롯되고 있는지를 변경하고자합니다.

나는 아래에서 내가하고자하는 간단한 예제를 만들었습니다. 데이터 소스의 x 및 y 열을 선택하기 위해 두 개의 '선택'위젯을 사용합니다. 이것들은 'Line'글리프가 참조하는 열을 변경하려고하는 콜백을 가지고 있습니다. 그러나 이것은 작동하지 않는 것 같습니다. 모든 조언을 환영 할 것입니다.

import numpy as np 

from bokeh.models import ColumnDataSource 
from bokeh.plotting import Figure 

from bokeh.models.widgets import Select,TextInput 
from bokeh.models.glyphs import Line 
from bokeh.models.layouts import HBox, VBox 
from bokeh.io import curdoc 


#============================================================================== 
#%% Define some Data 
#============================================================================== 
N = 200 

# Define the data to be used 
x = np.linspace(0,4.*np.pi,N) 
y = 3*np.cos(2*np.pi*x + np.pi*0.2) 
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4) 

source = ColumnDataSource({'x':x,'cos':y,'sin':z}) 


#============================================================================== 
#%% Layout 
#============================================================================== 


TOOLS = "box_select,lasso_select,help" 

# create a new plot 
plot = Figure(tools=TOOLS, title=None) 

# Make a line and connect to data source 
glyph = Line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6) 
plot.add_glyph(source, glyph) 

# Add list boxes for selecting which columns to plot on the x and y axis 
yaxis_select = Select(title="Y axis:", value="cos", 
          options=['x','cos','sin']) 


xaxis_select = Select(title="X axis:", value="x", 
          options=['x','cos','sin']) 


# Text input as a title 
text = TextInput(title="title", value='my sine wave plotter') 

# Layout widgets next to the plot      
controls = VBox(text,yaxis_select,xaxis_select) 

layout = HBox(controls,plot,width=800) 


#============================================================================== 
#%% Callbacks 
#============================================================================== 
# Put callbacks on the list boxes so that when they are changed the columns being 
# plotted get changed. 

def update_x_axis(attr, old, new): 
    # Change the column used for the x axis 
    glyph.x = xaxis_select.value 


def update_y_axis(attr, old, new): 
    # Change the column used for the y axis 
    glyph.y = yaxis_select.value 



yaxis_select.on_change('value', update_y_axis) 
xaxis_select.on_change('value', update_x_axis) 



#============================================================================== 
#%% Add to document root 
#============================================================================== 

curdoc().add_root(layout) 
curdoc().title = "Plotting app" 

답변

3

다음 스크립트는 잘 작동하는 것 같습니다. Bokeh Server는 아니지만 CustomJS 클라이언트 측 스타일을 대신 사용합니다.

import numpy as np 

from bokeh.models import ColumnDataSource 
from bokeh.plotting import Figure 

from bokeh.models.widgets import Select,TextInput 
from bokeh.models.layouts import HBox, VBox 
import bokeh.io 
from bokeh.models import CustomJS 

N = 200 

# Define the data to be used 
x = np.linspace(0,4.*np.pi,N) 
y = 3*np.cos(2*np.pi*x + np.pi*0.2) 
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4) 

source = ColumnDataSource(data={'x':x,'y':y, 'X': x, 'cos':y,'sin':z}) 


code=""" 
     var data = source.get('data'); 
     var r = data[cb_obj.get('value')]; 
     var {var} = data[cb_obj.get('value')]; 
     //window.alert("{var} " + cb_obj.get('value') + {var} ); 
     for (i = 0; i < r.length; i++) {{ 
      {var}[i] = r[i] ; 
      data['{var}'][i] = r[i]; 
     }} 
     source.trigger('change'); 
    """ 

callbackx = CustomJS(args=dict(source=source), code=code.format(var="x")) 
callbacky = CustomJS(args=dict(source=source), code=code.format(var="y")) 

# create a new plot 
plot = Figure(title=None) 

# Make a line and connect to data source 
plot.line(x="x", y="y", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source) 


# Add list boxes for selecting which columns to plot on the x and y axis 
yaxis_select = Select(title="Y axis:", value="cos", 
          options=['X','cos','sin'], callback=callbacky) 


xaxis_select = Select(title="X axis:", value="x", 
          options=['X','cos','sin'], callback=callbackx) 


# Text input as a title 
text = TextInput(title="title", value='my sine wave plotter') 

# Layout widgets next to the plot      
controls = VBox(text,yaxis_select,xaxis_select) 

layout = HBox(controls,plot,width=800) 

bokeh.io.show(layout) 

그러나 나는 그것이해야 할 때까지 함께 팅크했다. CustomJS 코드의 일부분이 왜 그렇게 복잡해야하는지 확신 할 수 없습니다.

특히 JS 파트의 for-loop 안의 두 줄은 실제로 필요하지만 실제로는 똑같은 것처럼 보입니다.

따라서 누군가가 실제로 설명 할 수있는 어떤 것을 생각해 낼 때까지는이 질문을 대답하지 않을 것입니다.

+0

내가 바라고 있지만

불행히도, 이러한 특정 필드를 편집 완벽하게 파이썬 솔루션을 얻을 수 없다는 것을 나는 '같으면 Javascript로 내 손을 더럽힐 필요가 없습니다. 가능하면 파이썬에 머물고 싶습니다. 그러나 이것은 효과가있는 것으로 보이며 장애물 위에 나를 데려옵니다. 감사. – Redlegjed

2

글리프가 좌표를 취하는 실제 소스 필드를 편집하려면 this question에있는 코드 변형이 필요합니다. ImportanceOfBeingErnest의 코드의 개정은 선택 위젯에서 모든 키를 원래 ColumnDataSource을 변경하거나 숨길 필요없이 정확한 결과를 얻을 : 나는 명확성을 위해 코드 문자열을 분리

import numpy as np 

from bokeh.models import ColumnDataSource 
from bokeh.plotting import Figure 

from bokeh.models.widgets import Select, TextInput 
from bokeh.models.layouts import HBox, VBox 
import bokeh.io 
from bokeh.io import curdoc 
from bokeh.models import CustomJS 

N = 200 

# Define the data to be used 
x = np.linspace(0, 4. * np.pi, N) 
y = 3 * np.cos(2 * np.pi * x + np.pi * 0.2) 
z = 0.5 * np.sin(2 * np.pi * 0.8 * x + np.pi * 0.4) 

data = {'x': x, 'cos': y, 'sin': z} 
source = ColumnDataSource(data=data) 

codex = """ 
      var column = cb_obj.value; 
      line1.glyph.x.field = column; 
      source.trigger('change') 
     """ 
codey = """ 
      var column = cb_obj.value; 
      line1.glyph.y.field = column; 
      source.trigger('change') 
     """ 

# create a new plot 
plot = Figure(title=None) 

# Make a line and connect to data source 
line1 = plot.line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source) 

callbackx = CustomJS(args=dict(line1=line1, source=source), code=codex) 
callbacky = CustomJS(args=dict(line1=line1, source=source), code=codey) 

# Add list boxes for selecting which columns to plot on the x and y axis 
yaxis_select = Select(title="Y axis:", value="cos", 
         options=data.keys(), 
         callback=callbacky 
        ) 

xaxis_select = Select(title="X axis:", value="x", 
         options=data.keys(), 
         callback=callbackx 
        ) 

# Text input as a title 
text = TextInput(title="title", value='my sine wave plotter') 

# Layout widgets next to the plot 
controls = VBox(text, yaxis_select, xaxis_select) 

layout = HBox(controls, plot, width=800) 

# bokeh.io.show(layout) 
curdoc().add_root(layout) 
curdoc().title = "Sliders" 

하지만 ImportanceOfBeingErnest의 인 String.format()을 사용했다 아주 깔끔한. ImportanceOfBeingErnest의 솔루션은 실제로 모두에서 자바 스크립트를 필요로하지 않습니다 (하지만 데이터 소스를 변경하지)

관련 문제