使用分类变量定义散景散点图中的颜色和标记

Use of a categorical variable to define colors and markers in bokeh scatter plot

我有一个 pandas 数据框,其中包含两个数据列(为简单起见,我们称它们为 'x' 和 'y'),以及一个分类列(例如 'color'值 'red'、'green' 和 'blue')。现在我想使用 bokeh 生成具有不同标记符号的散点图('red'->'x'、'green'->'o' 和 'blue'-> 'triangle').

虽然我确实找到了一个解决方案,我手动提取了 'x' 和 'y' 值的相关部分,但我认为应该可以使用 "categorical" 在一个命令中执行此操作在散景中绘制。但是,文档主要考虑条形图,当我尝试在 ColumnDataSource 中使用 df.groupby('color') 的结果时,在散点图中绘制 'x' 和 'y'(带有源=source) 失败,因为未找到列名 'x' 和 'y'。

下面是一个示例代码来说明问题:

import pandas as pd
import bokeh.plotting as plt

df = pd.DataFrame(data=[[0., 0., 'red'], [1., 0., 'red'], [1., 1., 'green'],
                        [1., 2., 'blue'], [2., 1., 'blue']],
                  columns=['x', 'y', 'color'])
source = plt.ColumnDataSource(df.groupby('color'))
# source = plt.ColumnDataSource(df) -- this would work for colors
fig = plt.figure()
fig.scatter('x', 'y', color='color', source=source)
plt.show(fig)

此代码段显示了所需的最低限度。没有 groupby,color='color' 实际上有效,但在我的真实示例中,分类变量具有非颜色值。此外,如何根据要求指定多个符号?

更新:下面的原始答案仍然有效,但这种事情现在也可以通过颜色和标记映射变换更容易地完成:

from bokeh.plotting import figure, show
from bokeh.sampledata.iris import flowers
from bokeh.transform import factor_cmap, factor_mark

SPECIES = ['setosa', 'versicolor', 'virginica']
MARKERS = ['hex', 'circle_x', 'triangle']

p = figure(title = "Iris Morphology")
p.xaxis.axis_label = 'Petal Length'
p.yaxis.axis_label = 'Sepal Width'

p.scatter("petal_length", "sepal_width", source=flowers, legend_field="species", fill_alpha=0.4, size=12,
          marker=factor_mark('species', MARKERS, SPECIES),
          color=factor_cmap('species', 'Category10_3', SPECIES))

show(p)


原答案

GroupBy 传递给 CDS 对您没有帮助,因为这会创建 汇总数据 的 CDS,但您需要所有个人点。这是使用 CDSViewGroupFilter 完成您所要求的一种方法,如 Providing Data for Plots and Tables:

中所述
import pandas as pd

from bokeh.io import show
from bokeh.models import ColumnDataSource, CDSView, GroupFilter
from bokeh.plotting import figure


df = pd.DataFrame(data=[[0., 0., 'red'], [1., 0., 'red'], [1., 1., 'green'],
                        [1., 2., 'blue'], [2., 1., 'blue']],
                  columns=['x', 'y', 'color'])

source = ColumnDataSource(df)

# create views for the different groups
red = CDSView(source=source, filters=[GroupFilter(column_name='color', group='red')])
green = CDSView(source=source, filters=[GroupFilter(column_name='color', group='green')])
blue = CDSView(source=source, filters=[GroupFilter(column_name='color', group='blue')])

p = figure()

# use the views with different glyphs
p.circle('x', 'y', size=15, color='red', source=source, view=red)
p.square('x', 'y', size=15, color='green', source=source, view=green)
p.triangle('x', 'y', size=15, color='blue', source=source, view=blue)

show(p)

看起来似乎有一些非常简单和容易的改进可以减少代码量(例如,可能 source.group 方法来完成那些 CDSView行做,或者可能是字形方法的参数来指定组)。我鼓励您提交 GitHub feature request issue 以进一步讨论。