How to add data labels to a bar chart in Bokeh?
<p>In the Bokeh guide there are examples of various bar charts that can be created. <a href="http://bokeh.pydata.org/en/0.10.0/docs/user_guide/charts.html#id4" rel="nofollow">http://bokeh.pydata.org/en/0.10.0/docs/user_guide/charts.html#id4</a></p>

<p>This code will create one:</p>

<pre><code>from bokeh.charts import Bar, output_file, show
from bokeh.sampledata.autompg import autompg as df

p = Bar(df, 'cyl', values='mpg', title="Total MPG by CYL")

output_file("bar.html")

show(p)
</code></pre>

<p>My question is if it's possible to add data labels to each individual bar of the chart? I searched online but could not find a clear answer.</p>

<p>Yes, you can add labels to each bar of the chart.  There are a few ways to do this.  By default, your labels are tied to your data.  But you can change what is displayed.  Here are a few ways to do that using your example:</p>

<pre><code>from bokeh.charts import Bar, output_file, show
from bokeh.sampledata.autompg import autompg as df
from bokeh.layouts import gridplot

from pandas import DataFrame
from bokeh.plotting import figure, ColumnDataSource
from bokeh.models import Range1d, HoverTool

# output_file("bar.html")

""" Adding some sample labels a few different ways.
    Play with the sample data and code to get an idea what does what.
    See below for output.
"""
</code></pre>

<p><strong>Sample data (new labels):</strong></p>

<p>I used some logic to determine the new dataframe column.  Of course you could use another column already in <code>df</code> (it all depends on what data you're working). All you really need here is to supply a new column to the dataframe.</p>

<pre><code># One method
labels = []
for number in df['cyl']:
    if number == 3:
        labels.append("three")
    if number == 4:
        labels.append("four")
    if number == 5:
        labels.append("five")
    if number == 6:
        labels.append("six")
    if number == 8:
        labels.append("eight")

df['labels'] = labels
</code></pre>

<p>Another way to get a new dataframe column.  Again, we just need to supply <code>df</code> a new column to use on our bar plot.</p>

<pre><code># Another method
def new_labels(x):
    if x % 2 != 0 or x == 6:
        y = "Inline"
    elif x % 2 == 0:
        y = "V"
    else:
        y = "nan"
    return y

df["more_labels"] = df["cyl"].map(new_labels)
</code></pre>

<p><strong>Now the bar chart:</strong></p>

<p>I've done it two ways.  p1 just specifies the new labels.  Note that because I used strings it put them in alphabetical order on the chart.  p2 uses the original labels, plus adds my new labels on the same bar.</p>

<pre><code># Specifying your labels
p1 = Bar(df, label='labels', values='mpg',
         title="Total MPG by CYL, remapped labels, p1",
         width=400, height=400, legend="top_right")
p2 = Bar(df, label=['cyl', 'more_labels'], values='mpg',
         title="Total MPG by CYL, multiple labels, p2", width=400, height=400,
         legend="top_right")
</code></pre>

<p><strong>Another way:</strong></p>

<p>Bokeh has three main "interface levels".  High level <code>charts</code> provides quick easy access but limited functionality; <code>plotting</code> which gives more options; <code>models</code> gives even more options.</p>

<p>Here I'm using the plotting interface and the <code>Figure</code> class that contains a <code>rect</code> method.  This gives you more detailed control of your chart.    </p>

<pre><code># Plot with "intermediate-level" bokeh.plotting interface
new_df = DataFrame(df.groupby(['cyl'])['mpg'].sum())
factors = ["three", "four", "five", "six", "eight"]
ordinate = new_df['mpg'].tolist()
mpg = [x * 0.5 for x in ordinate]

p3 = figure(x_range=factors, width=400, height=400,
            title="Total MPG by CYL, using 'rect' instead of 'bar', p3")
p3.rect(factors, y=mpg, width=0.75, height=ordinate)
p3.y_range = Range1d(0, 6000)
p3.xaxis.axis_label = "x axis name"
p3.yaxis.axis_label = "Sum(Mpg)"
</code></pre>

<p><strong>A fourth way to add specific labels:</strong></p>

<p>Here I'm using the <code>hover</code> plot tool.  Hover over each bar to display your specified label.</p>

<pre><code># With HoverTool, using 'quad' instead of 'rect'
top = [int(x) for x in ordinate]
bottom = [0] * len(top)
left = []
[left.append(x-0.2) for x in range(1, len(top)+1)]
right = []
[right.append(x+0.2) for x in range(1, len(top)+1)]
cyl = ["three", "four", "five", "six", "eight"]
source = ColumnDataSource(
    data=dict(
        top=[int(x) for x in ordinate],
        bottom=[0] * len(top),
        left=left,
        right=right,
        cyl=["three", "four", "five", "six", "eight"],
    )
)

hover = HoverTool(
    tooltips=[
        ("cyl", "@cyl"),
        ("sum", "@top")
    ]
)

p4 = figure(width=400, height=400,
            title="Total MPG by CYL, with HoverTool and 'quad', p4")
p4.add_tools(hover)
p4.quad(top=[int(x) for x in ordinate], bottom=[0] * len(top),
        left=left, right=right, color="green", source=source)
p4.xaxis.axis_label = "x axis name"
</code></pre>

<p>Show all four charts in a grid:</p>

<pre><code>grid = gridplot([[p1, p2], [p3, p4]])
show(grid)
</code></pre>

<p>These are the ways I am aware of.  There may be others.  Change whatever you like to fit your needs.  Here is what running all of this will output (you'll have to run it or serve it to get the hovertool):</p>

<p><a href="http://i.stack.imgur.com/rydJP.png" rel="nofollow"><img src="http://i.stack.imgur.com/rydJP.png" alt="bokeh bar specify labels"></a>
<a href="http://i.stack.imgur.com/y78Fv.png" rel="nofollow"><img src="http://i.stack.imgur.com/y78Fv.png" alt="bokeh bar specify labels"></a></p>

python bokeh