Search code examples
pythonbokeh

Labels not appearing in python bokeh bar plot with groups


I want to add labels with the values above the bars like here: How to add data labels to a bar chart in Bokeh? but don't know how to do it. My code looks different then other examples, the code is working but maybe it is not the right way.

My code:

from bokeh.io import export_png
from bokeh.io import output_file, show
from bokeh.palettes import Spectral5
from bokeh.plotting import figure
from bokeh.sampledata.autompg import autompg_clean as df
from bokeh.transform import factor_cmap
from bokeh.models import ColumnDataSource, ranges, LabelSet, Label
import pandas as pd

d = {'lvl': ["lvl1", "lvl2", "lvl2", "lvl3"],
   'feature': ["test1", "test2","test3","test4"],
     'count': ["5", "20","8", "90"]}
dfn = pd.DataFrame(data=d)
sourceframe = ColumnDataSource(data=dfn)

groupn = dfn.groupby(by=['lvl', 'feature'])
index_cmapn = factor_cmap('lvl_feature', palette=Spectral5, factors=sorted(dfn.lvl.unique()), end=1)


pn = figure(plot_width=800, plot_height=300, title="Count",x_range=groupn, toolbar_location=None)

labels = LabelSet(x='feature', y='count', text='count', level='glyph',x_offset=0, y_offset=5, source=sourceframe, render_mode='canvas',)


pn.vbar(x='lvl_feature', top="count_top" ,width=1, source=groupn,line_color="white", fill_color=index_cmapn, )

pn.y_range.start = 0
pn.x_range.range_padding = 0.05
pn.xgrid.grid_line_color = None
pn.xaxis.axis_label = "levels"
pn.xaxis.major_label_orientation = 1.2
pn.outline_line_color = None
pn.add_layout(labels)
export_png(pn, filename="color.png")

I think it has something to do with my dfn.groupby(by=['lvl', 'feature']) and the (probably wrong) sourceframe = ColumnDataSource(data=dfn).

The plot at this moment: enter image description here


Solution

  • You can add the groups names in the initial dictionary like this:

    d = {'lvl': ["lvl1", "lvl2", "lvl2", "lvl3"],
         'feature': ["test1", "test2","test3","test4"],
         'count': ["5", "20","8", "90"],
         'groups': [('lvl1', 'test1'), ('lvl2', 'test2'), ('lvl2', 'test3'), ('lvl3', 'test4')]}
    

    And then call LabelSet using as x values the groups.

    labels = LabelSet(x='groups', y='count', text='count', level='glyph',x_offset=20, y_offset=0, source=sourceframe, render_mode='canvas',)
    

    In this way the labels appear. Note that I played a bit with the offset to check if that was the problem, you can fix that manually.

    enter image description here