具有紧密轴和匹配纵横比的散景图像图

Image plot in bokeh with tight axes and matching aspect ratio

我在 Django 应用程序中使用 bokeh 1.0.1 版本,我想将微观表面图像显示为具有颜色编码高度和颜色条的可缩放图像图。原则上这是可行的,但我无法获得具有正确宽高比的图,只显示周围没有 space 的图像。

这是我想要实现的示例:结果图应该

对于图像,我只使用 x 方向 nx=100 点和 y 方向 ny=100 点的随机数据。

这是我的第一个方法:

尝试 1

from bokeh.models.ranges import Range1d
from bokeh.plotting import figure, show
from bokeh.models import LinearColorMapper, ColorBar
import numpy as np

sx = 10
sy = 5

nx = 100
ny = 100    
arr = np.random.rand(nx, ny)

x_range = Range1d(start=0, end=sx, bounds=(0,sx))
y_range = Range1d(start=0, end=sy, bounds=(0,sy))

# Attempt 1
plot = figure(x_range=x_range, y_range=y_range, match_aspect=True)

# Attempt 2
# plot = figure(match_aspect=True)

# Attempt 3
# pw = 400
# ph = int(400/sx*sy)
# plot = figure(plot_width=pw, plot_height=ph, 
#               x_range=x_range, y_range=y_range, match_aspect=True)

color_mapper = LinearColorMapper(palette="Viridis256", 
                                 low=arr.min(), high=arr.max())
colorbar = ColorBar(color_mapper=color_mapper, location=(0,0))

plot.image([arr], x=[0], y=[0], dw=[sx], dh=[sy],  
           color_mapper=color_mapper)
plot.rect(x=[0,sx,sx,0,sx/2], y=[0,0,sy,sy,sy/2], 
          height=1, width=1, color='blue')

plot.add_layout(colorbar, 'right')    
show(plot)

我还在图中添加了蓝色方块,以便查看,当 纵横比要求不合格。

不幸的是,在resulting picture中,正方形不再是正方形了,它的高是宽的两倍。缩放和平移按预期工作。

尝试 2

当使用

忽略范围时
plot = figure(match_aspect=True)

我会得到 this picture。正方形是屏幕上的正方形, 这很好,但是轴范围改变了,所以有 现在 space 围绕着它。我只想拥有被覆盖的数据区域 图片。

尝试 3

或者,当为图形提供 plot_heightplot_width 时, 具有预定义的宽高比,例如通过

pw = 800 # plot width
ph = int(pw/sx*sy)
plot = figure(plot_width=pw, plot_height=ph, 
              x_range=x_range, y_range=y_range, 
              match_aspect=True)

我会得到 this picture。正方形也不再是正方形了。几乎可以做到,但是很难,因为plot_width还包括颜色条和工具栏。

我读过this corresponding blog post 和相应的 bokeh documentation,但我无法让它工作。

有谁知道如何实现我想要的或是否不可能? 响应式行为也很好,但我们现在可以忽略它。 感谢您的任何提示。

更新

Gitter 上与 Bokeh 开发人员交谈后(感谢 Bryan!)看来我想要的几乎是不可能的。

原因是,match_aspect=True 如何使数据中的正方形 space 看起来像像素中的正方形 space:给定 canvas 大小,这可能是由于对响应行为应用了不同的 sizing_mode 设置,然后更改数据范围以具有匹配的纵横比。因此,没有其他方法可以使像素纵横比与数据纵横比相匹配,而无需在图像周围添加额外的 space,即在给定范围内扩展轴。另请参阅此 issue.

的评论

没有响应行为,然后根据纵横比预先固定 canvas 大小是可以做到的,但目前并不完美,因为内部图框周围的所有其他元素也需要 space。有一个 PR 可以直接控制内部框架尺寸,但我不确定该怎么做。

好吧,如果我放弃紧轴目标呢? 这是在上面的 "Attempt 2" 中完成的,但是图像周围有太多空白 space,与图像情节相同 space。

我尝试使用各种 range_padding* 属性,例如

x_range = DataRange1d(range_padding=10, range_padding_units='percent')
y_range = DataRange1d(range_padding=10, range_padding_units='percent')

但它不会减少地块周围的 space 数量,而只会增加它。以百分比表示的填充应相对于 dhdw 给出的图像尺寸。

有人知道如何使用 range_padding 参数来获得更小的轴范围或其他方法来在上面的示例中(使用 match_aspect=True)在图像图周围使用更小的填充吗? 我已经在上面打开了 another question

你能接受这个解决方案吗(适用于 Bokeh v1.0.4)?

from bokeh.models.ranges import Range1d
from bokeh.plotting import figure, show
from bokeh.layouts import Row
from bokeh.models import LinearColorMapper, ColorBar
import numpy as np

sx = 10
sy = 5

nx = 100
ny = 100
arr = np.random.rand(nx, ny)

x_range = Range1d(start = 0, end = sx, bounds = (0, sx))
y_range = Range1d(start = 0, end = sy, bounds = (0, sy))

pw = 400
ph = pw * sy / sx
plot = figure(plot_width = pw, plot_height = ph,
              x_range = x_range, y_range = y_range, match_aspect = True)

color_mapper = LinearColorMapper(palette = "Viridis256",
                                 low = arr.min(), high = arr.max())

plot.image([arr], x = [0], y = [0], dw = [sx], dh = [sy], color_mapper = color_mapper)
plot.rect(x = [0, sx, sx, 0, sx / 2], y = [0, 0, sy, sy, sy / 2], height = 1, width = 1, color = 'blue')

colorbar_plot = figure(plot_height = ph, plot_width = 69, x_axis_location = None, y_axis_location = None, title = None, tools = '', toolbar_location = None)
colorbar = ColorBar(color_mapper = color_mapper, location = (0, 0))
colorbar_plot.add_layout(colorbar, 'left')

show(Row(plot, colorbar_plot))

结果: