我可以为散热图绘制颜色条吗?

时间:2015-09-16 17:23:38

标签: visualization heatmap bokeh colorbar

散景是否有简单的方法来绘制热图的颜色条?

In this example它将是一个条带,说明颜色如何与值对应。

在matlab中,它被称为' colorbar'看起来像这样: enter image description here

6 个答案:

答案 0 :(得分:8)

更新:现在很多更容易:见

http://bokeh.pydata.org/en/latest/docs/user_guide/annotations.html#color-bars

我害怕我没有一个好的答案,这在Bokeh中应该更容易。但我之前手动完成了这样的事情。

因为我经常希望这些不在我的情节中,所以我会制作一个新的情节,然后将它与hplotgridplot一起组合。

这里有一个例子:https://github.com/birdsarah/pycon_2015_bokeh_talk/blob/master/washmap/washmap/water_map.py#L179

在你的情况下,情节应该非常简单。如果您创建了这样的数据源:

| value | color
| 1     | blue
.....
| 9     | red

然后你可以这样做:

legend = figure(tools=None)
legend.toolbar_location=None
legend.rect(x=0.5, y='value', fill_color='color', width=1, height=1, source=source)
layout = hplot(main, legend)
show(legend)

但是,这确实依赖于您知道值对应的颜色。您可以将调色板传递给热图图表调用 - 如下所示:http://bokeh.pydata.org/en/latest/docs/gallery/cat_heatmap_chart.html,这样您就可以使用它来构建新的数据源。

我非常确定彩色地图周围至少有一个未解决的问题。我知道我刚添加一个用于场外传说。

答案 1 :(得分:5)

由于0.12.3版本的Bokeh有ColorBar。

此文档对我非常有用: http://bokeh.pydata.org/en/dev/docs/user_guide/annotations.html#color-bars

答案 2 :(得分:3)

以下是一些代码松散地基于Birdsarah生成颜色条的响应:

AccountCreationVC

另外,如果您对模拟matplot lib色彩图感兴趣,请尝试使用:

def generate_colorbar(palette, low=0, high=15, plot_height = 100, plot_width = 500, orientation = 'h'):

    y = np.linspace(low,high,len(palette))
    dy = y[1]-y[0]
    if orientation.lower()=='v':
        fig = bp.figure(tools="", x_range = [0, 1], y_range = [low, high], plot_width = plot_width, plot_height=plot_height)
        fig.toolbar_location=None
        fig.xaxis.visible = None
        fig.rect(x=0.5, y=y, color=palette, width=1, height = dy)
    elif orientation.lower()=='h':
        fig = bp.figure(tools="", y_range = [0, 1], x_range = [low, high],plot_width = plot_width, plot_height=plot_height)
        fig.toolbar_location=None
        fig.yaxis.visible = None
        fig.rect(x=y, y=0.5, color=palette, width=dy, height = 1)
    return fig

答案 3 :(得分:3)

由于此处的其他答案看起来非常复杂,这里有一段容易理解的代码,可以在散热图上生成颜色条。

import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import LinearColorMapper, BasicTicker, ColorBar


data = np.random.rand(10,10)

color_mapper = LinearColorMapper(palette="Viridis256", low=0, high=1)

plot = figure(x_range=(0,1), y_range=(0,1))
plot.image(image=[data], color_mapper=color_mapper,
           dh=[1.0], dw=[1.0], x=[0], y=[0])

color_bar = ColorBar(color_mapper=color_mapper, ticker= BasicTicker(),
                     location=(0,0))

plot.add_layout(color_bar, 'right')

show(plot)

enter image description here

答案 4 :(得分:2)

要做到这一点,我做了同样的@birdsarah。作为额外提示,如果您使用rect方法作为颜色贴图,则在颜色栏中再次使用rect方法并使用相同的源。最终结果是您可以选择颜色条的各个部分,并在图中选择。

尝试一下:

http://simonbiggs.github.io/electronfactors

答案 5 :(得分:0)

这也是我的愿望清单。如果绘制的数据改变(例如,移动通过3D数据集的一个维度),则还需要自动调整范围。下面的代码做了一些人们可能会觉得有用的东西。诀窍是在颜色栏中添加一个额外的轴,当数据发生变化时,你可以通过数据源控制它。

import numpy

from bokeh.plotting import Figure

from bokeh.models import ColumnDataSource, Plot, LinearAxis
from bokeh.models.mappers import LinearColorMapper
from bokeh.models.ranges import Range1d
from bokeh.models.widgets import Slider
from bokeh.models.widgets.layouts import VBox

from bokeh.core.properties import Instance

from bokeh.palettes import RdYlBu11

from bokeh.io import curdoc

class Colourbar(VBox):

    plot = Instance(Plot)
    cbar = Instance(Plot)

    power = Instance(Slider)

    datasrc = Instance(ColumnDataSource)
    cbarrange = Instance(ColumnDataSource)

    cmap = Instance(LinearColorMapper)

    def __init__(self):

        self.__view_model__ = "VBox"
        self.__subtype__ = "MyApp"

        super(Colourbar,self).__init__()

        numslices = 6
        x = numpy.linspace(1,2,11)
        y = numpy.linspace(2,4,21)
        Z = numpy.ndarray([numslices,y.size,x.size])
        for i in range(numslices):
            for j in range(y.size):
                for k in range(x.size):
                    Z[i,j,k] = (y[j]*x[k])**(i+1) + y[j]*x[k]

        self.power = Slider(title = 'Power',name = 'Power',start = 1,end = numslices,step = 1,
                            value = round(numslices/2))
        self.power.on_change('value',self.inputchange)

        z = Z[self.power.value]
        self.datasrc = ColumnDataSource(data={'x':x,'y':y,'z':[z],'Z':Z})

        self.cmap = LinearColorMapper(palette = RdYlBu11)

        r = Range1d(start = z.min(),end = z.max())        
        self.cbarrange = ColumnDataSource(data = {'range':[r]})

        self.plot = Figure(title="Colourmap plot",x_axis_label = 'x',y_axis_label = 'y',
                           x_range = [x[0],x[-1]],y_range=[y[0],y[-1]],
                           plot_height = 500,plot_width = 500)

        dx = x[1] - x[0]
        dy = y[1] - y[0]

        self.plot.image('z',source = self.datasrc,x = x[0]-dx/2, y = y[0]-dy/2,
                        dw = [x[-1]-x[0]+dx],dh = [y[-1]-y[0]+dy],
                        color_mapper = self.cmap)

        self.generate_colorbar()

        self.children.append(self.power)
        self.children.append(self.plot)
        self.children.append(self.cbar)

    def generate_colorbar(self,cbarlength = 500,cbarwidth = 50):

        pal = RdYlBu11

        minVal = self.datasrc.data['z'][0].min()
        maxVal = self.datasrc.data['z'][0].max()
        vals = numpy.linspace(minVal,maxVal,len(pal))

        self.cbar = Figure(tools = "",x_range = [minVal,maxVal],y_range = [0,1],
                           plot_width = cbarlength,plot_height = cbarwidth)

        self.cbar.toolbar_location = None 
        self.cbar.min_border_left = 10
        self.cbar.min_border_right = 10
        self.cbar.min_border_top = 0
        self.cbar.min_border_bottom = 0
        self.cbar.xaxis.visible = None
        self.cbar.yaxis.visible = None
        self.cbar.extra_x_ranges = {'xrange':self.cbarrange.data['range'][0]}
        self.cbar.add_layout(LinearAxis(x_range_name = 'xrange'),'below')

        for r in self.cbar.renderers:
            if type(r).__name__ == 'Grid':
                r.grid_line_color = None

        self.cbar.rect(x = vals,y = 0.5,color = pal,width = vals[1]-vals[0],height = 1)

    def updatez(self):

        data = self.datasrc.data
        newdata = data
        z = data['z']
        z[0] = data['Z'][self.power.value - 1]
        newdata['z'] = z
        self.datasrc.trigger('data',data,newdata)

    def updatecbar(self):

        minVal = self.datasrc.data['z'][0].min()
        maxVal = self.datasrc.data['z'][0].max()
        self.cbarrange.data['range'][0].start = minVal
        self.cbarrange.data['range'][0].end = maxVal

    def inputchange(self,attrname,old,new):

        self.updatez()
        self.updatecbar()

curdoc().add_root(Colourbar())