Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add data labels to a bar chart in Bokeh?

Tags:

python

bokeh

In the Bokeh guide there are examples of various bar charts that can be created. http://docs.bokeh.org/en/0.10.0/docs/user_guide/charts.html#id4

This code will create one:

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)

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.

like image 704
sparrow Avatar asked Sep 08 '16 23:09

sparrow


People also ask

How do you add labels to a bar graph?

Add data labelsClick the chart, and then click the Chart Design tab. Click Add Chart Element and select Data Labels, and then select a location for the data label option. Note: The options will differ depending on your chart type. If you want to show your data label inside a text bubble shape, click Data Callout.

How do you make a bar graph on Bokeh?

Basic. To create a basic bar chart, use the hbar() (horizontal bars) or vbar() (vertical bars) glyph methods. The example below shows a sequence of simple 1-level categories. To assign these categories to the x-axis, pass this list as the x_range argument to figure() .

How do you add data labels to a bar chart in Python?

To add value labels on a Matplotlib bar chart, we can use the pyplot. text() function. The pyplot. text() function from the Matplotlib module is used to add text values to any location in the graph.


2 Answers

Use Labelset

Use Labelset to create a label over each individual bar

In my example I'm using vbar with the plotting interface, it is a little bit more low level then the Charts interface, but there might be a way to add it into the Bar chart.

from bokeh.palettes import PuBu
from bokeh.io import show, output_notebook
from bokeh.models import ColumnDataSource, ranges, LabelSet
from bokeh.plotting import figure
output_notebook()

source = ColumnDataSource(dict(x=['Áætlaðir','Unnir'],y=[576,608]))

x_label = ""
y_label = "Tímar (klst)"
title = "Tímar; núllti til þriðji sprettur."
plot = figure(plot_width=600, plot_height=300, tools="save",
        x_axis_label = x_label,
        y_axis_label = y_label,
        title=title,
        x_minor_ticks=2,
        x_range = source.data["x"],
        y_range= ranges.Range1d(start=0,end=700))


labels = LabelSet(x='x', y='y', text='y', level='glyph',
        x_offset=-13.5, y_offset=0, source=source, render_mode='canvas')

plot.vbar(source=source,x='x',top='y',bottom=0,width=0.3,color=PuBu[7][2])

plot.add_layout(labels)
show(plot)

Bar chart with labels on top of each bar

You can find more about labelset here: Bokeh annotations

like image 51
sigurdb Avatar answered Oct 03 '22 06:10

sigurdb


NOTE FROM BOKEH MAINTAINERS The portions of the answer below that refer to the bokeh.charts are of historical interest only. The bokeh.charts API was deprecated and subsequently removed from Bokeh. See the answers here and above for information on the stable bokeh.plotting API


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:

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.
"""

Sample data (new labels):

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

# 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

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

# 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)

Now the bar chart:

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.

# 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")

Another way:

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

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

# 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)"

A fourth way to add specific labels:

Here I'm using the hover plot tool. Hover over each bar to display your specified label.

# 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"

Show all four charts in a grid:

grid = gridplot([[p1, p2], [p3, p4]])
show(grid)

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):

bokeh bar specify labels bokeh bar specify labels

like image 30
Ben Love Avatar answered Oct 03 '22 06:10

Ben Love