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

mcr*_*rot 6 python plot aspect-ratio bokeh

我正在Django应用程序中使用bokeh 1.0.1版本,并且我想将微观表面图像显示为具有颜色编码的高度和颜色栏的可缩放图像图。从原则上讲,这是可行的,但是我很难获得具有正确纵横比的图,只显示没有周围空间的图像。

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

  • 显示数据空间中宽度为sx=10,高度为的随机数据的图像sy=5(图像大小
  • 在初始视图和缩放时将轴限制为(0,sx)(0,sy)
  • 屏幕上的正方形至少在初始视图中应与数据空间中的正方形匹配

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

这是我的第一种方法:

尝试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)
Run Code Online (Sandbox Code Playgroud)

我还向图中添加了蓝色方块,以查看宽高比要求是否失败。

不幸的是,在生成的图片中,正方形不再是正方形,它的宽度是正方形的两倍。缩放和平移可以按预期进行。

尝试2

当通过使用而忽略范围时

plot = figure(match_aspect=True)
Run Code Online (Sandbox Code Playgroud)

我去拿这张照片。正方形是屏幕上的正方形,这很好,但是轴范围已更改,因此它周围有空间。我只希望图像覆盖数据区域。

尝试3

或者,在提供plot_height和时plot_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)
Run Code Online (Sandbox Code Playgroud)

我去拿这张照片。正方形也不再是正方形。这几乎可以完成,但是很困难,因为plot_width还包括颜色栏和工具栏。

我已经阅读了相应的博客文章 和相应的bokeh文档,但是无法正常工作。

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

更新资料

在与Gitter上的Bokeh开发人员进行对话之后(感谢Bryan!),看来我想要的几乎是不可能的。

原因是,如何match_aspect=True使数据空间中的正方形看起来像像素空间中的正方形:给定画布大小,这可能是由于sizing_mode对响应行为应用不同的设置而导致的,然后更改数据范围以使匹配的宽高比。因此,没有其他方法可以使像素宽高比与数据宽高比匹配,而无需在图像周围添加额外的空间,即将轴延伸到给定的边界上。另请参阅此问题的评论。

可以没有响应行为,然后相对于宽高比预先确定画布大小,但是由于内部绘图框周围的所有其他元素也占用空间,因此目前尚不完美。有一个PR可以直接控制内部框架的尺寸,但是我不确定该怎么做。

好吧,如果我放弃目标要紧轴怎么办?这是在上面的“尝试2”中完成的,但是图像周围有太多的空白空间,与图像打印所占用的空间相同。

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

x_range = DataRange1d(range_padding=10, range_padding_units='percent')
y_range = DataRange1d(range_padding=10, range_padding_units='percent')
Run Code Online (Sandbox Code Playgroud)

但它不会减少图周围的空间,而只会增加它。填充百分比应相对于dh和给定的图像尺寸dw

是否有人知道如何使用range_padding参数在上面的示例中使用较小的轴范围或以其他方式在图像图周围使用较小的填充(使用match_aspect=True)?我对此提出另一个问题

Ton*_*ony 5

您能接受这个解决方案(适用于 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))
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述