2016-09-28 36 views
4

我正在開發一個基於特定交互更新繪圖的散景(0.12.2)交互式應用程序。散景服務器獲取鼠標位置

現在我使用滑塊來更改圖中字形的位置,但我實際上想要訪問我的鼠標在特定圖形內的位置。

該數據集是一個多維矩陣(張量),密集的數據,每個圖顯示一個特定位置的維度。如果我在一個圖上更改標記字形的位置,則需要更新其他圖,這意味着我必須根據更新後的位置切割我的數據集。

這裏有一個簡單的例子,我嘗試使用懸停工具來得到我的背景虛化服務器更新功能的鼠標數據:

from bokeh.plotting import figure, ColumnDataSource 
from bokeh.models import CustomJS, HoverTool 
from bokeh.io import curdoc 

s = ColumnDataSource(data=dict(x=[0, 1], y=[0, 1])) 
callback = CustomJS(args=dict(s=s), code=""" 
     var geometry = cb_data['geometry']; 
     var mouse_x = geometry.x; 
     var mouse_y = geometry.y; 
     var x = s.get('data')['x']; 
     var y = s.get('data')['y']; 
     x[0] = mouse_x; 
     y[0] = mouse_y; 
     s.trigger('change'); 
    """) 
hover_tool = HoverTool(callback=callback) 
p = figure(x_range=(0, 1), y_range=(0, 1), tools=[hover_tool]) 
p.circle(x='x', y='y', source=s) 


def update(): 
    print s.data 

curdoc().add_root(p) 
curdoc().add_periodic_callback(update, 1000) 

不幸的是,服務器只輸出:

{「Y」 :[0,1], 'X':[0,1]}

{ 'Y':[0,1], 'X':[0,1]}

{ 'y' 的:[0,1],'x':[0,1]}

{ 'Y':[0,1], 'X':[0,1]}

是否有訪問鼠標位置(在Python代碼)的方法嗎?即使訪問字形的位置也是足夠的(因爲我可以用一些javascript代碼來改變字形的位置)。


編輯:所以我最近發現有這個tool_events.on_change(),我可以用於此目的。不幸的是它僅適用於TapToolLassoSelectTool工作BoxSelectTool,不是HoverTool:基於一個答案,我發現這裏

from bokeh.plotting import figure 
from bokeh.io import curdoc 
from bokeh.models.tools import BoxSelectTool, TapTool, HoverTool, LassoSelectTool 
from bokeh.models.ranges import Range1d 

TOOLS = [TapTool(), LassoSelectTool(), BoxSelectTool(), HoverTool()] 
p = figure(tools=TOOLS, 
      x_range=Range1d(start=0.0, end=10.0), 
      y_range=Range1d(start=0.0, end=10.0)) 

def tool_events_callback(attr, old, new): 
    print attr, 'callback', new 

p.tool_events.on_change('geometries', tool_events_callback) 
curdoc().add_root(p) 

How can I get data from a ColumnDataSource object which is synchronized with local variables of Bokeh's CustomJS function?。這個解決方案的問題在於我無法使用pan並觸發tool_events回調。我只能點擊(TapTool)或平移並觸發一次回調(Lasso/BoxSelectTool)。我實際上希望在每次鼠標移動時觸發這種回調。

回答

4

因此,我最近發現可以使用自定義模型來達到此目的。這意味着,擴展現有的工具,例如手勢工具,但實現/覆蓋你自己的功能。你需要運行一個散景服務器(顯然)。

$ bokeh serve dir_with_mainfile/ 

我所使用的是現在是這樣的: 創建一個文件MouseMoveTool.py:

from bokeh.models import Tool 
class MouseMoveTool(Tool): 
    # assuming your models are saved in subdirectory models/ 
    with open('models/MouseMoveTool.coffee', 'r') as f: 
     controls = f.read() 
    __implementation__ = controls 

然後創建MouseMoveTool。咖啡:

p = require "core/properties" 
GestureTool = require "models/tools/gestures/gesture_tool" 

class MouseMoveToolView extends GestureTool.View 
    ### Override the _pan function ### 
    _pan: (e) -> 
     frame = @plot_model.frame 
     canvas = @plot_view.canvas 

     vx = canvas.sx_to_vx(e.bokeh.sx) 
     vy = canvas.sy_to_vy(e.bokeh.sy) 
     if not frame.contains(vx, vy) 
      return null 

     # x and y are your mouse coordinates relative to the axes values 
     x = frame.x_mappers.default.map_from_target(vx) 
     y = frame.y_mappers.default.map_from_target(vy) 

     # update the model's geometry attribute. this will trigger 
     # the tool_events.on_change('geometries', ..) callback 
     # in your python code. 
     @plot_model.plot.tool_events.geometries = [{x:x, y:y}] 

class MouseMoveTool extends GestureTool.Model 
    default_view: MouseMoveToolView 
    type: "MouseMoveTool" 

    tool_name: "Mouse Move Tool" 
    icon: "bk-tool-icon-pan" 
    event_type: "pan" 
    default_order: 13 

module.exports = 
    Model: MouseMoveTool 
    View: MouseMoveToolView 

之後,你可以在你的main.py程序使用您的工具:

from models.MouseMoveTool import MouseMoveTool 
p = figure(plot_width=300, plot_height=300, tools=[MouseMoveTool()]) 
p.tool_events.on_change('geometries', on_mouse_move) 

def on_mouse_move(attr, old, new): 
    print new[0] # will print {x:.., y:..} coordinates