如何在Bokeh 12.4.1

时间:2017-02-22 01:54:38

标签: python-3.x heatmap bokeh

Bokeh的最新版本允许程序员将图例放在图表区域之外。这可以像描述here

那样完成
p = figure(toolbar_location="above")
r0 = p.circle(x, y)

legend = Legend(items=[
    ("sin(x)"   , [r0]),),
], location=(0, -30))

p.add_layout(legend, 'right')
show(p)

注意:图例对象通过add_layout附加到绘图上。图例对象本身由元组和字符串以及字形列表组成。

问题是当你只是绘制一个"数据"系列与下面的代码一样,改编自here

from bokeh.io import show
from bokeh.models import ColumnDataSource, HoverTool, LinearColorMapper
from bokeh.plotting import figure

col = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
row = ['A', 'B', 'C' , 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
'N', 'O', 'P']

# this is the colormap from the original NYTimes plot
colors = ["#75968f", "#a5bab7", "#c9d9d3", "#e2e2e2", "#dfccce",     
"#ddb7b1", "#cc7878", "#933b41", "#550b1d"]
mapper = LinearColorMapper(palette=colors)

source = ColumnDataSource(data = dict (
    row = test['plate_row'],
    col = test['plate_col'],
    values = test['Melt Temp']
))

TOOLS = "hover,save,pan,box_zoom,wheel_zoom"

p = figure(title="Plate Heatmap", x_range = (0.0,25.0), y_range =     
           list(reversed(row)), x_axis_location="above", tools=TOOLS)

r1 = p.rect(x="col", y="row", width=1, height=1,
       source=source, 
       fill_color={'field': 'values', 'transform': mapper},
       line_color=None)

legend = Legend(items=[
    ("test"   , [r1]),
], location=(0, -30))

p.add_layout(legend, 'left')
show(p)      # show the plot

这里的问题是只有一个字形。我真正需要的是解释不同颜色包含的值范围。显然,这是可能的,因为定义的here图表显示它是可能的。

更新

现在我正在写这个问题,我开始想,也许我可以只绘制多个系列,每个颜色一个......并且只绘制那些落在一定范围内的坐标......虽然看起来很笨重。所以任何想法都值得赞赏!

2 个答案:

答案 0 :(得分:1)

我找到了使用CategoricalColorMapper然后不创建显式图例对象的方法。 可能有一种方法可以使用相同的布局显式创建图例对象,稍后我会看一下。

import numpy as np
from bokeh.io import show
from bokeh.models import Legend
from bokeh.models import ColumnDataSource, HoverTool,CategoricalColorMapper
from bokeh.plotting import figure
from bokeh.palettes import Blues8

# values to assign colours on
values = np.arange(100,107)
# values that will appear in the legend!!!
legend_values = ['100-101','101-102','102-103','103-04','104-05','105-06',
                 '106-07']

source = ColumnDataSource(data = dict (
    row = np.arange(100,107),
    col = np.arange(100,107),
    values = np.arange(100,107),
    legend_values = legend_values
))
mapper = CategoricalColorMapper(factors=list(values),palette=Blues8)
TOOLS = "hover,save,pan,box_zoom,wheel_zoom"

p = figure(title="Plate Heatmap", x_range = (100,107), y_range =     
           [90,107], x_axis_location="above", tools=TOOLS)

r1 = p.rect(x="col", y="row", width=1, height=1,
       source=source, 
       fill_color={'field': 'values', 'transform': mapper},
       line_color=None,legend='legend_values')

p.legend.location = "bottom_right"
show(p)      # show the plot

请在此处查看图片1

答案 1 :(得分:1)

在研究了这一点之后,我发现了两种创建图例的方法,这些图例显示了每种颜色在热图上的含义:

1。)绘制几个字形系列:

首先,我将数字范围分成像这样的箱子:

min_value = test['Melt Temp'].min()
max_value = test['Melt Temp'].max()
increment = round((max_value - min_value)/9)
num_bins = [(lower, lower+increment) for lower in 
range(int(floor(min_value)), int(round(max_value)), 
int(round(increment)))]

然后,我从主表中创建子表,如下所示:

source_dict = {}
for range_tuple in num_bins: 
    range_data = test[(test['Melt Temp'] > int(range_tuple[0])) & 
    (test['Melt Temp'] <= int(range_tuple[1]))]
    source = ColumnDataSource(data = dict (
            row = range_data['x'],
            col = range_data['y'],
            values = range_data['Value']))
source_dict[range_tuple] = source

然后我用列数据源子表压缩颜色:

colors = RdYlBu9
glyph_list = []
for color, range_tuple in zip(colors, num_bins):
    r1 = p.rect(x="col", y="row", width=1, height=1,
           source=source_dict[range_tuple], 
           fill_color=color,
           line_color=None)
    glyph_list.append(r1)

最后,我创建了一个显式的图例对象,它需要字符串字形元组。然后,图例对象将附加到图中:

legend_list = [("{0}<={1}".format(bin[0], bin[1]), [glyph]) for bin, 
glyph in zip(num_bins, glyph_list)]
legend = Legend(items=legend_list, location=(0, -50))
p.add_layout(legend, 'left')
show(p)

这种方法的缺点:

  • 它似乎有点笨拙。
  • 我在尝试选择对象时发现的另一个潜在缺点:如果单击某个颜色的某个数据点,则会选择该颜色的所有数据点。根据您的要求,这可能是加号或减号。

2。)Colorbar:

第二种方法使用上面的@ Okonomiyaki评论,并且更加简单。基本要点是您使用颜色映射器来确定字形的颜色。您还可以在Okonomiyaki指出的情况下创建ColorBar

mapper = LogColorMapper(palette="Viridis256", low=min_value, 
    high=max_value)
source = ColumnDataSource(data = dict (
        row = test['x'], col = test['y'], values = test['value']))

p = figure(title="Plate Heatmap", x_range = (0.0,25.0), y_range = 
list(reversed(row)),
x_axis_location="above", plot_width=650, plot_height=400)

r1 = p.rect(x="col", y="row", width=1, height=1,
            source=source, 
            fill_color={'field': 'values', 'transform': mapper},
            line_color=None)

color_bar = ColorBar(color_mapper=mapper, ticker=LogTicker(),
                 label_standoff=12, border_line_color=None, 
                 location(0,0))
p.add_layout(color_bar, 'left')
layout = p
show(layout)

我喜欢这种方法的优雅。这种方法的唯一缺点是,您无法获得定义给定颜色的清晰数字。

如果其他人想出更优雅的方法,请 共享!