在 Bokeh 中使标记 fill_alpha 值依赖

make marker fill_alpha value-dependent in Bokeh

在 Bokeh 中,是否可以让标记 alpha 随指定字段中的值变化?

例如,要按字段改变颜色和标记:

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.transform import factor_cmap,factor_mark

df = some dataframe
palette = ['#440154', '#404387', '#29788E', '#22A784', '#79D151', '#FDE724']
bok_sym = ['circle','asterisk','square_x','circle_x','diamond','hex']
cat_lst = list(df['cat_field'].unique())

df_cds = ColumnDataSource(data=df)

fig = figure(some kwargs)
fig.scatter(x='x',y='y',
            source = df_cds,
            marker = factor_mark('cat_field',bok_sym,cat_lst)
            fill_color = factor_cmap('cat_field',palette,cat_lst),
           )
show(fig)

似乎没有针对 alpha 的类似显式函数,但 bokeh.transform 确实提供了通用变换

https://docs.bokeh.org/en/latest/docs/reference/transform.html

我尝试添加以下内容:

from bokeh.transform import transform

alph_lst = [0.2,0.9,0.9,0.9,0.9,0.9]

fig.scatter(x='x',y='y',
                source = df_cds,
                marker = factor_mark('cat_field',bok_sym,cat_lst)
                fill_color = factor_cmap('cat_field',palette,cat_lst),
                fill_alpha = transform('cat_field',dict(zip(cat_lst,alph_lst))),
               )

但是没有成功。

干杯

编辑:

我会注意到我已经(未成功)尝试将透明度作为十六进制代码的一部分传递:

调色板 = ['#44015433', '#404387E6', '#29788EE6', '#22A784E6', '#79D151E6', '#FDE724E6']

正如您在问题中所述,您绝对可以使用自定义转换来实现这一点。绕过它们有点麻烦(在我看来),但希望这段代码能解决它。

基本上,您需要 3 个步骤来创建自定义 javascript 函数并将其应用于散景中的字段名称:

  1. 编写 javascript 实现所需转换的代码。在我们的例子中,我们只是将分类值映射到字典中的 alpha 级别。
  2. 将此 javascript 片段放入 CustomJSTransform 对象中,将必要的参数作为字典提供给它。在这种情况下,我在 python 中构建了 factor -> alpha 映射并将其传递给 javascript。我们使用了 vfunc 参数,因为我们想将此转换应用于数据中类别的每个实例。
  3. 在您对绘图函数的调用中 p.scatter 使用 transform 函数将您指定的列名称与您的自定义转换联系起来。在这种情况下 alpha = transform("cat_field", categorical_alpha_transformer)
import pandas as pd
import numpy as np

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.transform import factor_cmap, factor_mark, transform
from bokeh.models.transforms import CustomJSTransform
from bokeh.io import output_notebook, show

output_notebook()

v_func  = """
var new_xs = new Array(xs.length)
for(var i = 0; i < xs.length; i++) {
    new_xs[i] = alpha_map[xs[i]]
}
return new_xs
"""

df = pd.DataFrame({
    "cat_field": list("abcdef"), 
    "x": list(range(6)), 
    "y": list(range(6)),
})

palette = ['#440154', '#404387', '#29788E', '#22A784', '#79D151', '#FDE724']
bok_sym = ['circle','asterisk','square_x','circle_x','diamond','hex']
alphas = [.1, .25, .4, .55, .7, .85, 1]
cat_lst = list(df['cat_field'].unique())

alpha_map = dict(zip(cat_lst, alphas)) # {"a": .1, "b": .25, ... "f": 1}
categorical_alpha_transformer = CustomJSTransform(args={"alpha_map": alpha_map}, v_func=v_func)


df_cds = ColumnDataSource(data=df)

fig = figure(width=250, height=250)
fig.scatter(
    x='x',
    y='y',
    source = df_cds,
    marker = factor_mark('cat_field', bok_sym, cat_lst),
    fill_color = factor_cmap('cat_field', palette, cat_lst),
    size=20,
    alpha = transform("cat_field", categorical_alpha_transformer)
    
)

show(fig)