Bokeh散点图中的颜色点

7
我有一个简单的pandas.DataFrame,内容如下:
df = pd.DataFrame(
    {
        "journey": ['ch1', 'ch2', 'ch2', 'ch1'],
        "cat": ['a', 'b', 'a', 'c'],
        "kpi1": [1,2,3,4],
        "kpi2": [4,3,2,1]
    }
)

我将其绘制如下:
import bokeh.plotting as bpl
import bokeh.models as bmo
bpl.output_notebook()
source = bpl.ColumnDataSource.from_df(df)
hover = bmo.HoverTool(
    tooltips=[
        ("index", "@index"),
        ('journey', '@journey'),
        ("Cat", '@cat')
    ]
)
p = bpl.figure(tools=[hover])

p.scatter(
    'kpi1', 
    'kpi2', source=source)

bpl.show(p)  # open a browser

我无法根据cat对点进行着色。最终,我希望第一个和第三个点是同一种颜色,第二个和第四个点是两种更不同的颜色。

如何使用Bokeh实现这一目标?

3个回答

18

以下是一种避免手动映射的方法。我最近在这个github问题中偶然发现了bokeh.palettes,以及在这个问题中的CategoricalColorMapper。该方法将它们结合起来使用。可在此查看所有可用调色板,而CategoricalColorMapper的详细信息则可在此查看

我尝试直接在一个pd.DataFrame上运行这个方法时遇到了问题,并且还发现无法使用from_df()调用。根据文档,应该直接传递一个DataFrame,这对我有效。

import pandas as pd
import bokeh.plotting as bpl
import bokeh.models as bmo
from bokeh.palettes import d3
bpl.output_notebook()


df = pd.DataFrame(
    {
        "journey": ['ch1', 'ch2', 'ch2', 'ch1'],
        "cat": ['a', 'b', 'a', 'c'],
        "kpi1": [1,2,3,4],
        "kpi2": [4,3,2,1]
    }
)
source = bpl.ColumnDataSource(df)

# use whatever palette you want...
palette = d3['Category10'][len(df['cat'].unique())]
color_map = bmo.CategoricalColorMapper(factors=df['cat'].unique(),
                                   palette=palette)

# create figure and plot
p = bpl.figure()
p.scatter(x='kpi1', y='kpi2',
          color={'field': 'cat', 'transform': color_map},
          legend='cat', source=source)
bpl.show(p)

3
这真的是最简单的方法吗?看起来非常复杂,我需要添加两行代码和另一个字典,才能完成在R中<color = c>所能实现的操作。 - Thomas
3
我最初也因同样的原因来到这个问题,并且也是从 R/ggplot2 转过来的,我对 Python 的绘图社区感到非常失望。看看 plotly;同样的问题。你必须为每个系列创建列表,这似乎确实很复杂。我发布了这个答案,因为这是当时我能找到的最简单的方法(尽管我在 bokeh 方面相当菜鸟)。如果你能找到更简单的方法,请发另一个答案。 - Hendy
1
@mic 你会喜欢上 plotnine 的!这个回答是关于bokeh的,所以不适用于这里...但有趣的是我可以将整个绘图代码放入注释中,使用原始数据框(请注意,在plotnine的ggplot中必须引用变量)。 from plotnine import *; ggplot(df, aes(x='kpi1', y='kpi2', color='cat')) + geom_point() - Hendy
1
是的,我已经关注plotnine有一段时间了(我非常想念ggplot...)。不幸的是,我一直在为需要悬停和缩放功能的人创建图表,而且我真的无法摆脱plotly或bokeh。你的观察不仅有趣,而且突出了使用gg时代码可以变得多么简单、流畅和易读。 - mic
@mic 必须是 Python 吗?你看过 ggplotly 吗?或者考虑将静态图包装在 shiny/dash 中,以获得一些功能(不确定是否可以悬停,但类似的功能可能通过滑块或按钮来切换标签(ggrepel 层)和过滤阈值可能是可能的)。只是一个想法! - Hendy
显示剩余4条评论

2

为了完整起见,这里是使用低级别图表的调整代码:

import pandas as pd

import bokeh.plotting as bpl
import bokeh.models as bmo
bpl.output_notebook()


df = pd.DataFrame(
    {
        "journey": ['ch1', 'ch2', 'ch2', 'ch1'],
        "cat": ['a', 'b', 'a', 'c'],
        "kpi1": [1,2,3,4],
        "kpi2": [4,3,2,1],
        "color": ['blue', 'red', 'blue', 'green']
    }
)
df

source = bpl.ColumnDataSource.from_df(df)
hover = bmo.HoverTool(
    tooltips=[
        ('journey', '@journey'),
        ("Cat", '@cat')
    ]
)
p = bpl.figure(tools=[hover])

p.scatter(
    'kpi1', 
    'kpi2', source=source, color='color')

bpl.show(p)

请注意,颜色是“硬编码”到数据中的。
以下是使用高级图表的替代方法:
import pandas as pd

import bokeh.plotting as bpl
import bokeh.charts as bch
bpl.output_notebook()

df = pd.DataFrame(
    {
        "journey": ['ch1', 'ch2', 'ch2', 'ch1'],
        "cat": ['a', 'b', 'a', 'c'],
        "kpi1": [1,2,3,4],
        "kpi2": [4,3,2,1]
    }
)

tooltips=[
        ('journey', '@journey'),
        ("Cat", '@cat')
    ]
scatter = bch.Scatter(df, x='kpi1', y='kpi2',
                      color='cat',
                      legend="top_right",
                      tooltips=tooltips
                     )

bch.show(scatter)

bokeh.charts已经不存在了(https://github.com/bokeh/bokeh/issues/7152)。有没有一种最新的方法来完成这个?我真的很喜欢不必手动指定映射的想法。 - Hendy
Bokeh 经常在变化,我不知道。可能提出一个新问题是最好的选择。 - Dror
谢谢提醒!我实际上已经偶然发现了一种这样做的方法,并发布了一个新答案。我认为它很适合这里;这是谷歌搜索的热门结果,有先例可以更新答案,随着事物的变化(例如,在已经存在python2答案的情况下,提供一个python3答案)。 - Hendy
什么是“低级别”图表,什么是“高级别”图表? - Ian Boyd
这里描述了Bokeh是使用其低级构造函数还是高级构造函数。我猜即使上面的低级示例也不是最低级别的。最低级别将是使用线条和点构建图像。 - Dror
它在 3.1 s 版本中无法运行。错误:ValueError:未能验证 Line(id ='p4849',...).line_color:期望为 None 或 Color 类型的值,而实际得到了“color_key_in_dataframe”。 - Jaja

-2

你可以使用更高级别的Scatter,例如这里

或者在ColumnDataSource中提供一个颜色列,并在p.scatter(..., color='color_column_label')中引用它。


该页面不存在!(非常抱歉) - Ian Boyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接