Search code examples
bokehlegend-properties

Bokeh legend color properties


I have a problem with the color of the legend dots. All of them are red while it should switch from red to green in 7.

enter image description here

The code that produces the last image is:

from bokeh.models import ColumnDataSource, Label, LabelSet, Range1d, Legend
from bokeh.plotting import figure, output_file, show
from bokeh.models import HoverTool

df = pd.DataFrame({'pc1': range(11),
                   'pc2': range(10,-1,-1),
                   'Muestra': ['A']*6+['B']*5,
                  'color':['#cf0c0c']*6+['#0dab51']*5},
                  index=range(1,12))

ID = ['{} {}'.format(i+1,j) for i,j in enumerate(df.Muestra)]


source = ColumnDataSource(data=dict(pc1=df.pc1,
                                    pc2=df.pc2, 
                                    color=df.color,
                                    ID=ID,
                                    names=df.index))


p = figure(title='Principal Component Analysis')

p.scatter(x='pc1', y='pc2', size=15, fill_color='color', fill_alpha=0.6, line_color=None, source=source)

labels = LabelSet(x='pc1', y='pc2', text='names',
              x_offset=5, y_offset=5, source=source, render_mode='canvas')

legend=Legend(items=[(ID[i-1],[p.renderers[0]]) for i in df.index])

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

I think it should be a renderers property but I am not sure.


Solution

  • Instead of manually creating the legend, you can also specify "ID" to be the legend_field of the scatter renderer. This will automatically generate a legend for you where each entry corresponds to each unique value in the "ID" column:

    import pandas as pd
    
    from bokeh.models import ColumnDataSource, Label, LabelSet, Range1d, Legend
    from bokeh.plotting import figure, output_file, show
    from bokeh.models import HoverTool
    
    df = pd.DataFrame(
        {
            "pc1": range(11),
            "pc2": range(10, -1, -1),
            "Muestra": ["A"] * 6 + ["B"] * 5,
            "color": ["#cf0c0c"] * 6 + ["#0dab51"] * 5,
        },
        index=range(1, 12),
    )
    
    ID = ["{} {}".format(i + 1, j) for i, j in enumerate(df.Muestra)]
    
    
    source = ColumnDataSource(
        data=dict(pc1=df.pc1, pc2=df.pc2, color=df.color, ID=ID, names=df.index)
    )
    
    
    p = figure(title="Principal Component Analysis")
    
    p.scatter(
        x="pc1",
        y="pc2",
        size=15,
        fill_color="color",
        fill_alpha=0.6,
        line_color=None,
        source=source,
        legend_field="ID"   # New kwarg added here
    )
    
    labels = LabelSet(
        x="pc1",
        y="pc2",
        text="names",
        x_offset=5,
        y_offset=5,
        source=source,
        render_mode="canvas",
    )
    
    # Removed these 2 lines
    # legend=Legend(items=[(ID[i-1],[p.renderers[0]]) for i in df.index])
    # p.add_layout(legend,'right')
    
    p.add_layout(labels)
    
    show(p)
    

    I end up with this plot: enter image description here