Jorge Leitao
Jorge Leitao

Reputation: 20113

How to plot a vertical line on a bar plot in Bokeh?

Based on the first example of the user-guide of Bokeh,

from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models import Span

output_file("bars.html")

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
counts = [5, 3, 4, 2, 4, 6]

p = figure(x_range=fruits, plot_height=250, title="Fruit Counts",
           toolbar_location=None, tools="")

p.vbar(x=fruits, top=counts, width=0.9)

# these two lines
vline = Span(location='Apples', dimension='height', line_color='blue', line_width=4)
p.renderers.extend([vline])

p.xgrid.grid_line_color = None
p.y_range.start = 0

show(p)

I am trying to add a vertical line to a bar plot whose x-range are categories. However, this does not seem to be possible, as this raises an error "ValueError: expected a value of type Real, got Apples of type str".

location='Apples' does not work as intended as it expected a number.

Upvotes: 0

Views: 2610

Answers (1)

Jorge Leitao
Jorge Leitao

Reputation: 20113

One solution is to convert the categorical value to the corresponding numeric value on the plot:

index = p.x_range.factors.index("Apples")
delta = (p.x_range.end - p.x_range.start)/p.x_range.factors.length;
location = delta/2 + index;

If the plot is dynamic (e.g. values are not known when the plot is built), then use an auxiliary JS function to do the conversion:

function _value_to_location(x_range, value) {
    var index = x_range.factors.findIndex(x => x == value)
    var delta = (x_range.end - x_range.start)/x_range.factors.length;
    return delta/2 + index;
};

...

vline.location = _value_to_location(figure.x_range, "Apples");

Upvotes: 2

Related Questions