相关文章推荐
睿智的葫芦  ·  解决RStudio中"plot.new() ...·  1 周前    · 
满身肌肉的皮带  ·  js ...·  1 年前    · 
忐忑的灯泡  ·  CLion - 知乎·  1 年前    · 
狂野的充值卡  ·  DataGrip ...·  1 年前    · 
坏坏的仙人掌  ·  php - laravel-soar - ...·  1 年前    · 

Bokeh: 如何在图像图中添加图例和自定义颜色边界?

3 人关注

我有一个二维数组,我想用bokeh的 bokeh.plotting.figure.Figure.image 来绘制。它的效果很好。

现在,我想用图片的颜色添加一个图例。我没有找到任何适合我的例子。我想实现的图例与图片类似。

from bokeh.models import LinearColorMapper, ColorBar
from bokeh.plotting import figure, show
plot = figure(x_range=(0,1), y_range=(0,1), toolbar_location="right")
color_mapper =  LinearColorMapper(palette="YlGn9", low=-1, high=1, nan_color="white")
plot.image(image=[ndvi], color_mapper=color_mapper,dh=[1.0], dw=[1.0], x=[0], y=[0])
color_bar = ColorBar(color_mapper=color_mapper,label_standoff=12, border_line_color=None, location=(0,0))
plot.add_layout(color_bar, 'right')

此外,我想有一些自定义的颜色边界,有非固定的间隔。下面是一个用matplotlib做的例子。

cmap = colors.ListedColormap(['#27821f', '#3fa336', '#6ce362','#ffffff','#e063a8' ,'#cc3b8b','#9e008c','#59044f'])
bounds = [-1000, -500, -100, 0, 50, 100, 300, 500, 10000000]
norm = colors.BoundaryNorm(bounds, cmap.N)
fig, ax = plt.subplots()
ax.imshow(data, cmap=cmap, norm=norm)
    
python
bokeh
ISTI Vita
ISTI Vita
发布于 2019-12-20
1 个回答
JohanC
JohanC
发布于 2019-12-25
已采纳
0 人赞同

你可以选择红-黄-绿的调色板。在bokeh中,它的名字是 "RdYlGn5",后面的数字告诉你需要多少种颜色。要在图例中使用它,你需要从 bokeh.palettes 导入 RdYlGn5

对于创建图例,我只知道采用一些假的字形,如下面的代码。

我更新了我的例子,用非固定的间隔设置自定义边界的新要求。 This post 提供了一些指导。基本上,这个想法是使用一个较大的带有重复颜色的颜色图。这样的格式不适合一般类型的边界,但它适合你的边界,至少当最低和最高边界被解释为无限时。

我还试着用一些自定义的空间来布局图例,使所有的标签都能对齐。选择了一种背景颜色来与图例条目形成对比。

有一个颜色条,用来验证颜色图的边界在内部是如何工作的。验证之后,你可以不使用它。示例图片的数值从-1000到1000,以显示如何处理严格的色域限制之外的数值。

下面是一个有假数据的例子。

from bokeh.models import LinearColorMapper, Legend, LegendItem, ColorBar, SingleIntervalTicker
from bokeh.plotting import figure, show
import numpy as np
x, y = np.meshgrid(np.linspace(0, 10, 1000), np.linspace(0, 10, 1000))
z = 1000*np.sin(x + np.cos(y))
plot = figure(x_range=(0, 1), y_range=(0, 1), toolbar_location="right")
base_colors = ['#27821f', '#3fa336', '#6ce362','#ffffff','#e063a8' ,'#cc3b8b','#9e008c','#59044f']
bounds = [-1000, -500, -100, 0, 50, 100, 300, 500, 10000000]
low = -600
high = 600
bound_colors = []
j = 0
for i in range(low, high, 50):
    if i >= bounds[j+1]:
        j += 1
    bound_colors.append(base_colors[j])
color_mapper = LinearColorMapper(palette=bound_colors, low=low, high=high, nan_color="white")
plot.image(image=[z], color_mapper=color_mapper, dh=[1.0], dw=[1.0], x=[0], y=[0])
# these are a dummy glyphs to help draw the legend
dummy_for_legend = [plot.line(x=[1, 1], y=[1, 1], line_width=15, color=c, name='dummy_for_legend')
                    for c in base_colors]
legend_labels = [f'     < {bounds[1]}'] + \
                [('' if l < 0 else '     ' if l < 10 else '   ' if l < 100 else ' ')
                 + f'{l} ‒ {h}' for l, h in zip(bounds[1:], bounds[2:-1])] + \
                [f'     > {bounds[-2]}']
legend1 = Legend(title="NDVI", background_fill_color='gold',
                 items=[LegendItem(label=lab, renderers=[gly]) for lab, gly in zip(legend_labels, dummy_for_legend) ])
plot.add_layout(legend1)
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=12, border_line_color=None, location=(0, 0),
                     ticker=SingleIntervalTicker(interval=50))
plot.add_layout(color_bar)