散景:在图像字形上启用悬停工具
Bokeh: enable hover tool on image glyphs
是否可以在图像(由 image()
、image_rgba()
或 image_url()
创建的字形)上启用悬停工具,以便在悬停在点上时显示一些上下文数据的图像。在文档中,我只找到了用于线或标记等字形的悬停工具的参考和示例。
可能的解决方法:
我认为可以将 2d 信号数据转换为包含 x、y 和值列的柱状 Dataframe 格式。并使用 rect
字形代替图像。但这也需要正确处理颜色映射。特别是,当值是实数而不是可以传递给某些调色板的整数时处理这种情况。
好的,在更深入地研究文档和示例之后,我可能会自己回答这个问题。
图像(2d 信号)数据的悬停效果在 Bokeh 中设计此功能的方式没有任何意义。如果需要添加一些附加到数据点的额外信息,则需要将数据放入适当的数据模型 - 平面模型中。
整理数据
基本上,需要将数据整理成包含 x、y 和值列的表格格式(参见 Tidy Data article by H.Wickham)。现在每一行代表一个数据点,并且可以自然地添加任何上下文信息作为附加列。
例如,以下代码将完成工作:
def flatten(matrix: np.ndarray,
extent: Optional[Tuple[float, float, float, float]] = None,
round_digits: Optional[int] = 0) -> pd.DataFrame:
if extent is None:
extent = (0, matrix.shape[1], 0, matrix.shape[0])
x_min, x_max, y_min, y_max = extent
df = pd.DataFrame(data=matrix)\
.stack()\
.reset_index()\
.rename(columns={'level_0': 'y', 'level_1': 'x', 0: 'value'})
df.x = df.x / df.x.max() * (x_max - x_min) + x_min
df.y = df.y / df.y.max() * (y_max - y_min) + y_min
if round_digits is not None:
df = df.round({'x': round_digits, 'y': round_digits})
return df
rect
字形和 ColumnDataSource
然后,使用 rect
字形而不是 image
并相应地映射 x,y 并且值列 color-mapped 正确地符合字形的颜色美学。
值的颜色映射
- 在这里您可以使用 min-max 标准化,乘以您要使用的颜色数和
round
- 使用 bokeh builtin palettes 将计算出的整数值映射到特定的颜色值。
综上所述,这是一个示例图表函数:
def InteractiveImage(img: pd.DataFrame,
x: str,
y: str,
value: str,
width: Optional[int] = None,
height: Optional[int] = None,
color_pallete: Optional[List[str]] = None,
tooltips: Optional[List[Tuple[str]]] = None) -> Figure:
"""
Notes
-----
both x and y should be sampled with a constant rate
Parameters
----------
img
x
Column name to map on x axis coordinates
y
Column name to map on y axis coordinates
value
Column name to map color on
width
Image width
height
Image height
color_pallete
Optional. Color map to use for values
tooltips
Optional.
Returns
-------
bokeh figure
"""
if tooltips is None:
tooltips = [
(value, '@' + value),
(x, '@' + x),
(y, '@' + y)
]
if color_pallete is None:
color_pallete = bokeh.palettes.viridis(50)
x_min, x_max = img[x].min(), img[x].max()
y_min, y_max = img[y].min(), img[y].max()
if width is None:
width = 500 if height is None else int(round((x_max - x_min) / (y_max - y_min) * height))
if height is None:
height = int(round((y_max - y_min) / (x_max - x_min) * width))
img['color'] = (img[value] - img[value].min()) / (img[value].max() - img[value].min()) * (len(color_pallete) - 1)
img['color'] = img['color'].round().map(lambda x: color_pallete[int(x)])
source = ColumnDataSource(data={col: img[col] for col in img.columns})
fig = figure(width=width,
height=height,
x_range=(x_min, x_max),
y_range=(y_min, y_max),
tools='pan,wheel_zoom,box_zoom,reset,hover,save')
def sampling_period(values: pd.Series) -> float:
# @TODO think about more clever way
return next(filter(lambda x: not pd.isnull(x) and 0 < x, values.diff().round(2).unique()))
x_unit = sampling_period(img[x])
y_unit = sampling_period(img[y])
fig.rect(x=x, y=y, width=x_unit, height=y_unit, color='color', line_color='color', source=source)
fig.select_one(HoverTool).tooltips = tooltips
return fig
#### 注意:但是这会带来相当高的计算代价
在 Alexander Reshytko 上面的自我回答的基础上,我已经实现了一个基本上可以下架的版本,其中包含一些示例。修改以适合您自己的应用程序应该更直接一些,并且不依赖 Pandas 数据帧,我并不真正使用或理解。 Github: Bokeh - Image with HoverTool
处的代码和示例
散景版本 0.12.16 更新
Bokeh 版本 0.12.16 支持 HoverTool
image
glyphs
。看:
bokeh release 0.12.16
对于较早的散景版本:
这是我使用 bokeh.plotting.image
将鼠标悬停在图像上并在其顶部添加具有悬停功能的不可见 (alpha=0
) bokeh.plotting.quad
的方法数据坐标。我将它用于大约 1500 行和 40000 列的图像。
# This is used for hover and taptool
imquad = p.quad(top=[y1], bottom=[y0], left=[x0], right=[x1],alpha=0)
这里显示了一个完整的示例和图像,可以选择颜色条的最小值和最大值,还可以选择 color_mapper
:Utilities for interactive scientific plots using python, bokeh and javascript. 更新: 最新的散景已经支持 matplotlib
cmap
调色板,但是当我创建这段代码时,我需要从 matplotlib.cm.get_cmap
生成它们
在此处显示的示例中,我决定不在 bokeh.models.HoverTool
函数内使用 tooltips=None
在图像上显示工具提示。相反,我将它们显示在单独的 bokeh.models.Div
字形中。
是否可以在图像(由 image()
、image_rgba()
或 image_url()
创建的字形)上启用悬停工具,以便在悬停在点上时显示一些上下文数据的图像。在文档中,我只找到了用于线或标记等字形的悬停工具的参考和示例。
可能的解决方法:
我认为可以将 2d 信号数据转换为包含 x、y 和值列的柱状 Dataframe 格式。并使用 rect
字形代替图像。但这也需要正确处理颜色映射。特别是,当值是实数而不是可以传递给某些调色板的整数时处理这种情况。
好的,在更深入地研究文档和示例之后,我可能会自己回答这个问题。
图像(2d 信号)数据的悬停效果在 Bokeh 中设计此功能的方式没有任何意义。如果需要添加一些附加到数据点的额外信息,则需要将数据放入适当的数据模型 - 平面模型中。
整理数据
基本上,需要将数据整理成包含 x、y 和值列的表格格式(参见 Tidy Data article by H.Wickham)。现在每一行代表一个数据点,并且可以自然地添加任何上下文信息作为附加列。
例如,以下代码将完成工作:
def flatten(matrix: np.ndarray,
extent: Optional[Tuple[float, float, float, float]] = None,
round_digits: Optional[int] = 0) -> pd.DataFrame:
if extent is None:
extent = (0, matrix.shape[1], 0, matrix.shape[0])
x_min, x_max, y_min, y_max = extent
df = pd.DataFrame(data=matrix)\
.stack()\
.reset_index()\
.rename(columns={'level_0': 'y', 'level_1': 'x', 0: 'value'})
df.x = df.x / df.x.max() * (x_max - x_min) + x_min
df.y = df.y / df.y.max() * (y_max - y_min) + y_min
if round_digits is not None:
df = df.round({'x': round_digits, 'y': round_digits})
return df
rect
字形和 ColumnDataSource
然后,使用 rect
字形而不是 image
并相应地映射 x,y 并且值列 color-mapped 正确地符合字形的颜色美学。
值的颜色映射
- 在这里您可以使用 min-max 标准化,乘以您要使用的颜色数和
round
- 使用 bokeh builtin palettes 将计算出的整数值映射到特定的颜色值。
综上所述,这是一个示例图表函数:
def InteractiveImage(img: pd.DataFrame,
x: str,
y: str,
value: str,
width: Optional[int] = None,
height: Optional[int] = None,
color_pallete: Optional[List[str]] = None,
tooltips: Optional[List[Tuple[str]]] = None) -> Figure:
"""
Notes
-----
both x and y should be sampled with a constant rate
Parameters
----------
img
x
Column name to map on x axis coordinates
y
Column name to map on y axis coordinates
value
Column name to map color on
width
Image width
height
Image height
color_pallete
Optional. Color map to use for values
tooltips
Optional.
Returns
-------
bokeh figure
"""
if tooltips is None:
tooltips = [
(value, '@' + value),
(x, '@' + x),
(y, '@' + y)
]
if color_pallete is None:
color_pallete = bokeh.palettes.viridis(50)
x_min, x_max = img[x].min(), img[x].max()
y_min, y_max = img[y].min(), img[y].max()
if width is None:
width = 500 if height is None else int(round((x_max - x_min) / (y_max - y_min) * height))
if height is None:
height = int(round((y_max - y_min) / (x_max - x_min) * width))
img['color'] = (img[value] - img[value].min()) / (img[value].max() - img[value].min()) * (len(color_pallete) - 1)
img['color'] = img['color'].round().map(lambda x: color_pallete[int(x)])
source = ColumnDataSource(data={col: img[col] for col in img.columns})
fig = figure(width=width,
height=height,
x_range=(x_min, x_max),
y_range=(y_min, y_max),
tools='pan,wheel_zoom,box_zoom,reset,hover,save')
def sampling_period(values: pd.Series) -> float:
# @TODO think about more clever way
return next(filter(lambda x: not pd.isnull(x) and 0 < x, values.diff().round(2).unique()))
x_unit = sampling_period(img[x])
y_unit = sampling_period(img[y])
fig.rect(x=x, y=y, width=x_unit, height=y_unit, color='color', line_color='color', source=source)
fig.select_one(HoverTool).tooltips = tooltips
return fig
#### 注意:但是这会带来相当高的计算代价
在 Alexander Reshytko 上面的自我回答的基础上,我已经实现了一个基本上可以下架的版本,其中包含一些示例。修改以适合您自己的应用程序应该更直接一些,并且不依赖 Pandas 数据帧,我并不真正使用或理解。 Github: Bokeh - Image with HoverTool
处的代码和示例散景版本 0.12.16 更新
Bokeh 版本 0.12.16 支持 HoverTool
image
glyphs
。看:
bokeh release 0.12.16
对于较早的散景版本:
这是我使用 bokeh.plotting.image
将鼠标悬停在图像上并在其顶部添加具有悬停功能的不可见 (alpha=0
) bokeh.plotting.quad
的方法数据坐标。我将它用于大约 1500 行和 40000 列的图像。
# This is used for hover and taptool
imquad = p.quad(top=[y1], bottom=[y0], left=[x0], right=[x1],alpha=0)
这里显示了一个完整的示例和图像,可以选择颜色条的最小值和最大值,还可以选择 color_mapper
:Utilities for interactive scientific plots using python, bokeh and javascript. 更新: 最新的散景已经支持 matplotlib
cmap
调色板,但是当我创建这段代码时,我需要从 matplotlib.cm.get_cmap
在此处显示的示例中,我决定不在 bokeh.models.HoverTool
函数内使用 tooltips=None
在图像上显示工具提示。相反,我将它们显示在单独的 bokeh.models.Div
字形中。