Geo*_*her 5 python bokeh jupyter-notebook
我需要一些帮助来配置服务器端 on_change 事件以在缩放绘图时触发。我有一个大型的二维数据数组(5000,>1000000),我希望使用散景将其可视化为图像。因此,我将数据 (skimage.transform.resize) 调整为散景图的宽度和高度。我正在尝试使用 on_change 函数在绘图缩放、平移或重置时调用调整大小。我已将回调附加到绘图 x_range 和 y_ranges 以在开始和结束更改时触发。但这(可以理解)会导致调整大小回调在每个缩放事件上被触发 4 次。能够在范围更改的任何子集上触发调整大小事件是可能的并且是可取的(例如,缩放可能不会更改 y_range.end),因此我不能简单地等待计算所有 on_change 事件。
示例代码:
import bokeh.plotting as bk
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
from bokeh.models import LinearColorMapper, ColumnDataSource
from skimage.transform import resize
import numpy as np
import xarray as xa
bk.output_notebook()
# Create a simple array image - basically lifted from https://docs.bokeh.org/en/latest/docs/gallery/image.html
N = 5000
x = np.linspace(0, 10*np.pi, N)
y = np.linspace(0, 10*np.pi, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)
# Using xarray as this is the array handling object of choice in production code
array = xa.DataArray(data = d, coords = (x, y), dims = ('x', 'y'))
class Plot():
def __init__(self, array, width = 800, height = 800):
# Probably unecessary, but done for syntactic familiarity
self.tla = array.to_pandas()
xrange = self.tla.index
yrange = self.tla.columns
# Configure plot object
self.p = bk.figure(height = height, width = width,
x_range = (xrange.min(), xrange.max()),
y_range = (yrange.max(), yrange.min()))
# Create ColoumnDataSource object with the resized input array, no arguments passed to
# simplify its use during callback
self.source = ColumnDataSource(data = {'image': [self.resize()]})
# Colormapper for image and colorbar control
self.color_mapper = LinearColorMapper(palette="Viridis256", low=-1, high=1)
# Create image
self.p.image('image', source = self.source, color_mapper=self.color_mapper,
dh=yrange.max() - yrange.min(), dw=xrange.max() - xrange.min(), x = xrange.min(), y=yrange.max())
# Add callback to x_range and y_range
self.p.x_range.on_change('end', self.callback)
self.p.x_range.on_change('start', self.callback)
self.p.y_range.on_change('end', self.callback)
self.p.y_range.on_change('start', self.callback)
def resize(self):
# Slice tla frame by x and y range bounds and then resize to fit plot height and width
return resize(self.tla.loc[self.p.x_range.start:self.p.x_range.end,
self.p.y_range.end:self.p.y_range.start].as_matrix(),
[self.p.plot_width, self.p.plot_height],
preserve_range = True, mode = 'reflect')
def modify_doc(self, doc):
# Add plot to document
doc.add_root(self.p)
def callback(self, attr, start, end):
# Call resize
data = ColumnDataSource(data = {'image': [self.resize()]}).data
# Re-assign computed data to ColumnDataSource object
self.source.data = data
print("Callback calculated @ {0}:{1}, {2}:{3}".format(self.p.x_range.start, self.p.x_range.end,
self.p.y_range.start, self.p.y_range.end))
# Create Plot
plot = Plot(array)
handler = FunctionHandler(plot.modify_doc)
app = Application(handler)
show(app)
Run Code Online (Sandbox Code Playgroud)
我还考虑过向绘图对象本身添加 on_event 更改,并向工具添加 on_change 回调,但似乎无法为这两个对象找到适当的触发器。
任何帮助或建议将不胜感激!
对于 Bokeh 的最新版本,以下是事件:
https://docs.bokeh.org/en/latest/docs/reference/events.html
您可以用来.on_event为它们注册回调。