dravid07
dravid07

Reputation: 467

How can I add label to a Bokeh barchart?

I have a dataframe as

df = pd.DataFrame(data = {'Country':'Spain','Japan','Brazil'],'Number':[10,20,30]})

I wanted to plot a bar chart with labels (that is value of 'Number') annotated on the top for each bar and proceeded accordingly.

    from bokeh.charts import Bar, output_file,output_notebook, show
    from bokeh.models import Label
    p = Bar(df,'Country', values='Number',title="Analysis", color = "navy")
    label = Label(x='Country', y='Number', text='Number', level='glyph',x_offset=5, y_offset=-5)
    p.add_annotation(label)    
    output_notebook()
    show(p)

But I got an error as ValueError: expected a value of type Real, got COuntry of type str.

How do I solve this issue ?

Upvotes: 1

Views: 2422

Answers (1)

DuCorey
DuCorey

Reputation: 895

Label produces a single label at position x and y. In you example, you are trying to add multiple labels using the data from your DataFrame as coordinates. Which is why you are getting your error message x and y need to be real coordinate values that map to the figure's x_range and y_range. You should look into using LabelSet (link) which can take a Bokeh ColumnDataSource as an argument and build multiple labels.

Unforutnately, you are also using a Bokeh Bar chart which is a high level chart which creates a categorical y_range. Bokeh cannot put labels on categorical y_ranges for now. You can circumvent this problem by creating a lower level vbar chart using placeholder x values and then styling it to give it the same look as your original chart. Here it is in action.

import pandas as pd
from bokeh.plotting import output_file, show, figure
from bokeh.models import LabelSet, ColumnDataSource, FixedTicker

# arbitrary placeholders which depends on the length and number of labels
x = [1,2,3]
 # This is offset is based on the length of the string and the placeholder size
offset = -0.05 
x_label = [x + offset for x in x]

df = pd.DataFrame(data={'Country': ['Spain', 'Japan', 'Brazil'],
                        'Number': [10, 20, 30],
                        'x': x,
                        'y_label': [-1.25, -1.25, -1.25],
                        'x_label': x_label})

source = ColumnDataSource(df)

p = figure(title="Analysis", x_axis_label='Country', y_axis_label='Number')
p.vbar(x='x', width=0.5, top='Number', color="navy", source=source)
p.xaxis.ticker = FixedTicker(ticks=x)  # Create custom ticks for each country
p.xaxis.major_label_text_font_size = '0pt'  # turn off x-axis tick labels
p.xaxis.minor_tick_line_color = None  # turn off x-axis minor ticks
label = LabelSet(x='x_label', y='y_label', text='Number',
                 level='glyph', source=source)
p.add_layout(label)
show(p)

Upvotes: 1

Related Questions