Bokeh plots you create with the bokeh.plotting interface come with a default set of tools and visual styles. For information on how to customize the visual style of plots, see Styling visual attributes. For information about changing or specifying tools, see Configuring plot tools.
Bokeh includes a large variety of markers for creating scatter plots. For example, to render circle scatter markers on a plot, use the circle() method of Figure:
circle()
Figure
from bokeh.plotting import figure, output_file, show # output to static HTML file output_file("line.html") p = figure(plot_width=400, plot_height=400) # add a circle renderer with a size, color, and alpha p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5) # show the results show(p)
Similarly, use the square() method of Figure to scatter square markers on a plot:
square()
from bokeh.plotting import figure, output_file, show # output to static HTML file output_file("square.html") p = figure(plot_width=400, plot_height=400) # add a square renderer with a size, color, and alpha p.square([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="olive", alpha=0.5) # show the results show(p)
Bokeh’s built-in scatter markers consist of a set of base markers, most of which can be combined with different kinds of additional visual features. This is an overview of all available scatter markers:
To see details and example plots for any of the available scatter markers, click on the corresponding glyph method in the following list:
asterisk()
circle_cross()
circle_dot()
circle_x()
circle_y()
cross()
dash()
dot()
diamond()
diamond_cross()
diamond_dot()
hex()
hex_dot()
inverted_triangle()
plus()
square_cross()
square_dot()
square_pin()
square_x()
star()
star_dot()
triangle()
triangle_dot()
triangle_pin()
x()
y()
All the markers have the same set of properties: x, y, size (in screen units), and angle (in radians by default). The circle() marker is an exception: this method accepts an additional radius property that you can use with data-space units.
x
y
size
angle
radius
The example below shows how to generate a single line glyph from one-dimensional sequences of x and y points using the line() glyph method:
line()
from bokeh.plotting import figure, output_file, show output_file("line.html") p = figure(plot_width=400, plot_height=400) # add a line renderer p.line([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=2) show(p)
For some kinds of data, discrete steps between data points may work better than linear segments. To produce this type of data representation, use the step() glyph method.
step()
from bokeh.plotting import figure, output_file, show output_file("line.html") p = figure(plot_width=400, plot_height=400) # add a steps renderer p.step([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], line_width=2, mode="center") show(p)
Adjust the mode parameter to draw step levels with the x-coordinates before, after, or in the middle of each step.
mode
If you want to draw multiple lines in one go, use the multi_line() glyph method as follows:
multi_line()
from bokeh.plotting import figure, output_file, show output_file("patch.html") p = figure(plot_width=400, plot_height=400) p.multi_line([[1, 3, 2], [3, 4, 6, 6]], [[2, 1, 4], [4, 7, 8, 5]], color=["firebrick", "navy"], alpha=[0.8, 0.3], line_width=4) show(p)
Note
Unlike many other glyph methods, multi_line() accepts a list of lists of x and y positions for each line. The multi_line() method also expects a scalar value or a list of scalars for each line for parameters such as color, alpha, and line width. You can similarly use a ColumnDataSource consisting of a list of lists of point coordinates and a list of scalar values of matching length.
ColumnDataSource
You can pass NaN values to line() and multi_line() glyphs. This produces disjointed lines with gaps for NaN values.
NaN
from bokeh.plotting import figure, output_file, show output_file("line.html") p = figure(plot_width=400, plot_height=400) # add a line renderer with a NaN nan = float('nan') p.line([1, 2, 3, nan, 4, 5], [6, 7, 2, 4, 4, 5], line_width=2) show(p)
You may wish to stack lines with a common index when working with time series of percentages and other similar data. To do so, you can use the vline_stack() and hline_stack() convenience methods.
vline_stack()
hline_stack()
from bokeh.models import ColumnDataSource from bokeh.plotting import figure, output_file, show output_file("vline_stack.html") source = ColumnDataSource(data=dict( x=[1, 2, 3, 4, 5], y1=[1, 2, 4, 3, 4], y2=[1, 4, 2, 2, 3], )) p = figure(plot_width=400, plot_height=400) p.vline_stack(['y1', 'y2'], x='x', source=source) show(p)
These and other convenience methods in this chapter rely on ColumnDataSource for data structuring. For information on how to work with this data structure, see Providing data.
To make drawing rectangular bars more convenient, Bokeh provides hbar() and vbar() glyph functions that combine the coordinate systems above.
hbar()
vbar()
To draw vertical bars by specifying a center x-coordinate, width, and top and bottom endpoints, use the vbar() glyph function:
from bokeh.plotting import figure, output_file, show output_file('vbar.html') p = figure(plot_width=400, plot_height=400) p.vbar(x=[1, 2, 3], width=0.5, bottom=0, top=[1.2, 2.5, 3.7], color="firebrick") show(p)
To draw horizontal bars by specifying a center y-coordinate, height, and left and right endpoints, use the hbar() glyph function:
from bokeh.plotting import figure, output_file, show output_file('hbar.html') p = figure(plot_width=400, plot_height=400) p.hbar(y=[1, 2, 3], height=0.5, left=0, right=[1.2, 2.5, 3.7], color="navy") show(p)
To stack the bars, you can use the vbar_stack() and hbar_stack() convenience methods.
vbar_stack()
hbar_stack()
from bokeh.models import ColumnDataSource from bokeh.plotting import figure, output_file, show output_file("hbar_stack.html") source = ColumnDataSource(data=dict( y=[1, 2, 3, 4, 5], x1=[1, 2, 4, 3, 4], x2=[1, 4, 2, 2, 3], )) p = figure(plot_width=400, plot_height=400) p.hbar_stack(['x1', 'x2'], y='y', height=0.8, color=("grey", "lightgrey"), source=source) show(p)
For more examples of stacked bars, see Handling categorical data.
To draw axis aligned rectangles by specifying the left, right, top, and bottom positions, use the quad() glyph function:
left
right
top
bottom
quad()
from bokeh.plotting import figure, output_file, show output_file('rectangles.html') p = figure(plot_width=400, plot_height=400) p.quad(top=[2, 3, 4], bottom=[1, 2, 3], left=[1, 2, 3], right=[1.2, 2.5, 3.7], color="#B3DE69") show(p)
To draw arbitrary rectangles by specifying center coordinates, width, height, and angle, use the rect() glyph function:
width
height
rect()
from math import pi from bokeh.plotting import figure, output_file, show output_file('rectangles_rotated.html') p = figure(plot_width=400, plot_height=400) p.rect(x=[1, 2, 3], y=[1, 2, 3], width=0.2, height=40, color="#CAB2D6", angle=pi/3, height_units="screen") show(p)
Bokeh can plot hexagonal tiles, which you can use to show binned aggregations and more. The hex_tile() method takes a size parameter to define the size of the hex grid and axial coordinates to specify the tiles.
hex_tile()
import numpy as np from bokeh.io import output_file, show from bokeh.plotting import figure from bokeh.util.hex import axial_to_cartesian output_file("hex_coords.html") q = np.array([0, 0, 0, -1, -1, 1, 1]) r = np.array([0, -1, 1, 0, 1, -1, 0]) p = figure(plot_width=400, plot_height=400, toolbar_location=None) p.grid.visible = False p.hex_tile(q, r, size=1, fill_color=["firebrick"]*3 + ["navy"]*4, line_color="white", alpha=0.5) x, y = axial_to_cartesian(q, r, 1, "pointytop") p.text(x, y, text=["(%d, %d)" % (q,r) for (q, r) in zip(q, r)], text_baseline="middle", text_align="center") show(p)
A more practical example below computes counts per bin using the hexbin() function and plots the color mapped counts.
hexbin()
import numpy as np from bokeh.io import output_file, show from bokeh.plotting import figure from bokeh.transform import linear_cmap from bokeh.util.hex import hexbin n = 50000 x = np.random.standard_normal(n) y = np.random.standard_normal(n) bins = hexbin(x, y, 0.1) p = figure(tools="wheel_zoom,reset", match_aspect=True, background_fill_color='#440154') p.grid.visible = False p.hex_tile(q="q", r="r", size=0.1, line_color=None, source=bins, fill_color=linear_cmap('counts', 'Viridis256', 0, max(bins.counts))) output_file("hex_tile.html") show(p)
You can simplify this code by calling the hexbin() method of Figure.
Directed areas are filled regions between two series that share a common index. For instance, a vertical directed area has one x coordinate array and two y coordinate arrays, y1 and y2, defining the space for Bokeh to fill.
y1
y2
To fill an area in vertical direction, use the varea() method. You can do the same in horizontal direction with harea().
varea()
harea()
from bokeh.plotting import figure, output_file, show output_file("varea.html") p = figure(plot_width=400, plot_height=400) p.varea(x=[1, 2, 3, 4, 5], y1=[2, 6, 4, 3, 5], y2=[1, 4, 2, 2, 3]) show(p)
To stack directed areas, use the varea_stack() and harea_stack() convenience methods.
varea_stack()
harea_stack()
from bokeh.models import ColumnDataSource from bokeh.plotting import figure, output_file, show output_file("varea_stack.html") source = ColumnDataSource(data=dict( x=[1, 2, 3, 4, 5], y1=[1, 2, 4, 3, 4], y2=[1, 4, 2, 2, 3], )) p = figure(plot_width=400, plot_height=400) p.varea_stack(['y1', 'y2'], x='x', color=("grey", "lightgrey"), source=source) show(p)
The following example generates a single polygonal patch from one-dimensional sequences of x and y points using the patch() glyph method:
patch()
from bokeh.plotting import figure, output_file, show output_file("patch.html") p = figure(plot_width=400, plot_height=400) # add a patch renderer with an alpha and line width p.patch([1, 2, 3, 4, 5], [6, 7, 8, 7, 3], alpha=0.5, line_width=2) show(p)
To plot several polygonal patches, use the patches() glyph method:
patches()
from bokeh.plotting import figure, output_file, show output_file("patch.html") p = figure(plot_width=400, plot_height=400) p.patches([[1, 3, 2], [3, 4, 6, 6]], [[2, 1, 4], [4, 7, 8, 5]], color=["firebrick", "navy"], alpha=[0.8, 0.3], line_width=2) show(p)
Unlike many other glyph methods, patches() accepts a list of lists of x and y positions for each line. The patches() method also expects a scalar value or a list of scalars for each patch for parameters such as color, alpha, and line width. You can similarly use a ColumnDataSource consisting of a list of lists of point coordinates and a list of scalar values of matching length.
Just as with the line() and multi_line() methods, you can pass NaN values to patch() and patches() glyphs. This produces disjointed patches with gaps for NaN values.
from bokeh.plotting import figure, output_file, show output_file("patch.html") p = figure(plot_width=400, plot_height=400) # add a patch renderer with a NaN value nan = float('nan') p.patch([1, 2, 3, nan, 4, 5, 6], [6, 7, 5, nan, 7, 3, 6], alpha=0.5, line_width=2) show(p)
Warning
Bokeh doesn’t currently support hit testing on patch objects with NaN values.
The multi_polygons() glyph uses nesting to accept a variety of information relevant to polygons. The method duplicates the functionality of patches() but you can also use it to render holes inside polygons.
multi_polygons()
Unlike many other glyph methods, multi_polygons() accepts a triple-nested lists of x and y positions for the exterior and holes composing each polygon. The multi_polygons() method also expects a scalar value or a list of scalars for each item for parameters such as color, alpha, and line width. You can similarly use a ColumnDataSource consisting of a triple- nested list of point coordinates and a list of scalars, with the top-level list of point coordinates being of equal length with the list of scalars.
The following example generates a single polygon from a triple-nested list of one-dimensional sequences of x and y points using the multi_polygons() glyph method.
from bokeh.plotting import figure, output_file, show output_file('multipolygon_simple.html') p = figure(plot_width=400, plot_height=400) p.multi_polygons(xs=[[[[1, 1, 2, 2]]]], ys=[[[[3, 4, 4, 3]]]]) show(p)
The following example generates a single polygon with holes from three sequences of x and y points. The first sequence represents the exterior of the polygon and the following sequences represent the holes.
from bokeh.plotting import figure, output_file, show output_file('multipolygon_with_holes.html') p = figure(plot_width=400, plot_height=400) p.multi_polygons(xs=[[[ [1, 2, 2, 1], [1.2, 1.6, 1.6], [1.8, 1.8, 1.6] ]]], ys=[[[ [3, 3, 4, 4], [3.2, 3.6, 3.2], [3.4, 3.8, 3.8] ]]]) show(p)
A single polygon concept can comprise multiple polygon geometries. The following example generates a multi-polygon glyph from several sequences of x and y points. Each item in the sequence represents a part of the glyph.
from bokeh.plotting import figure, output_file, show output_file('multipolygon_with_separate_parts.html') p = figure(plot_width=400, plot_height=400) p.multi_polygons(xs=[[[ [1, 1, 2, 2], [1.2, 1.6, 1.6], [1.8, 1.8, 1.6] ], [ [3, 4, 3] ]]], ys=[[[ [4, 3, 3, 4], [3.2, 3.2, 3.6], [3.4, 3.8, 3.8] ], [ [1, 1, 3] ]]]) show(p)
The top-level of nesting separates each multi-polygon from the rest. You can think of each multi-polygon as a row in the data source, potentially with a corresponding label or color.
from bokeh.plotting import figure, output_file, show output_file('multipolygons.html') p = figure(plot_width=400, plot_height=400) p.multi_polygons( xs=[ [[ [1, 1, 2, 2], [1.2, 1.6, 1.6], [1.8, 1.8, 1.6] ], [ [3, 3, 4] ]], [[ [1, 2, 2, 1], [1.3, 1.3, 1.7, 1.7] ]]], ys=[ [[ [4, 3, 3, 4], [3.2, 3.2, 3.6], [3.4, 3.8, 3.8] ], [ [1, 3, 1] ]], [[ [1, 1, 2, 2], [1.3, 1.7, 1.7, 1.3] ]]], color=['blue', 'red']) show(p)
The ellipse() glyph method accepts the same properties as rect(), but renders ellipse shapes.
ellipse()
from math import pi from bokeh.plotting import figure, output_file, show output_file('ellipses.html') p = figure(plot_width=400, plot_height=400) p.ellipse(x=[1, 2, 3], y=[1, 2, 3], width=[0.2, 0.3, 0.1], height=0.3, angle=pi/3, color="#CAB2D6") show(p)
You can display images on Bokeh plots using the image(), image_rgba(), and image_url() glyph methods. You can use hovering tooltips with image glyphs to let the user see the values of each pixel. For more information on how to enable hovering tooltips for images, see Image hover.
image()
image_rgba()
image_url()
The following example shows how to display images using raw RGBA data with the image_rgba() method.
import numpy as np from bokeh.plotting import figure, output_file, show # create an array of RGBA data N = 20 img = np.empty((N, N), dtype=np.uint32) view = img.view(dtype=np.uint8).reshape((N, N, 4)) for i in range(N): for j in range(N): view[i, j, 0] = int(255 * i / N) view[i, j, 1] = 158 view[i, j, 2] = int(255 * j / N) view[i, j, 3] = 255 output_file("image_rgba.html") p = figure(plot_width=400, plot_height=400, x_range=(0, 10), y_range=(0, 10)) p.image_rgba(image=[img], x=[0], y=[0], dw=[10], dh=[10]) show(p)
The following example shows how to supply an array of scalar values and have Bokeh automatically color map the data in the browser with the image() glyph method.
import numpy as np from bokeh.plotting import figure, output_file, show output_file("image.html", title="image.py example") x = np.linspace(0, 10, 250) y = np.linspace(0, 10, 250) xx, yy = np.meshgrid(x, y) d = np.sin(xx)*np.cos(yy) p = figure(plot_width=400, plot_height=400) p.x_range.range_padding = p.y_range.range_padding = 0 p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", level="image") p.grid.grid_line_width = 0.5 show(p)
Note that this example sets the render level to "image". Normally, Bokeh draws all glyphs above grid lines, but with this render level they appear below the grid lines.
"image"
To draw multiple individual line segments use the segment() and ray() glyph methods.
segment()
ray()
The segment() method accepts start points x0 and y0 and end points x1 and y1 and renders segments between them.
x0
y0
x1
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.segment(x0=[1, 2, 3], y0=[1, 2, 3], x1=[1.2, 2.4, 3.1], y1=[1.2, 2.5, 3.7], color="#F4A582", line_width=3) show(p)
The ray() method accepts start points x and y with a length (in screen units) and an angle. The angle_units parameter defaults to "rad" but can you can also set it to "deg" to have the angle measured in degrees instead of radians. To have an “infinite” ray that always extends to the edge of the plot, set length to 0.
length
angle_units
"rad"
"deg"
0
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.ray(x=[1, 2, 3], y=[1, 2, 3], length=45, angle=[30, 45, 60], angle_units="deg", color="#FB8072", line_width=2) show(p)
To draw a simple line arc, use the arc() glyph method, which accepts radius, start_angle, and end_angle to determine position. Additionally, the direction property determines whether to render clockwise ("clock") or anti-clockwise ("anticlock") between the start and end angles.
arc()
start_angle
end_angle
direction
"clock"
"anticlock"
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.arc(x=[1, 2, 3], y=[1, 2, 3], radius=0.1, start_angle=0.4, end_angle=4.8, color="navy") show(p)
The wedge() glyph method accepts the same properties as arc() but renders a filled wedge instead:
wedge()
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.wedge(x=[1, 2, 3], y=[1, 2, 3], radius=0.2, start_angle=0.4, end_angle=4.8, color="firebrick", alpha=0.6, direction="clock") show(p)
The annular_wedge() glyph method is similar to wedge() but leaves an inner portion of the wedge hollow. It accepts an inner_radius and outer_radius instead of just radius.
annular_wedge()
inner_radius
outer_radius
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.annular_wedge(x=[1, 2, 3], y=[1, 2, 3], inner_radius=0.1, outer_radius=0.25, start_angle=0.4, end_angle=4.8, color="green", alpha=0.6) show(p)
Finally, the annulus() glyph method also accepts inner_radius and outer_radius to produce hollow circles.
annulus()
from bokeh.plotting import figure, show p = figure(plot_width=400, plot_height=400) p.annulus(x=[1, 2, 3], y=[1, 2, 3], inner_radius=0.1, outer_radius=0.25, color="orange", alpha=0.6) show(p)
To draw parameterized quadratic and cubic curves, use the quadratic() and bezier() glyph methods. For more detail on these curves, see reference documentation.
quadratic()
bezier()
You can combine multiple glyphs on a single plot by calling their methods on a single Figure.
from bokeh.plotting import figure, output_file, show x = [1, 2, 3, 4, 5] y = [6, 7, 8, 7, 3] output_file("multiple.html") p = figure(plot_width=400, plot_height=400) # add both a line and circles on the same plot p.line(x, y, line_width=2) p.circle(x, y, fill_color="white", size=8) show(p)
This principle applies to all bokeh.plotting glyph methods. You can add as many glyphs to a Bokeh plot as you want.
By default, Bokeh attempts to automatically set the data bounds of plots to fit snugly around the data. You may, however, need to set a plot’s range explicitly. To do so, set the x_range and/or y_range properties using a Range1d object that lets you set the start and end points of the range you want.
x_range
y_range
Range1d
p.x_range = Range1d(0, 100)
For convenience, the figure() function can also accept (start, end) tuples as values for the x_range or y_range parameters. Here’s how you can use both methods to set a range:
figure()
from bokeh.models import Range1d from bokeh.plotting import figure, output_file, show output_file("title.html") # create a new plot with a range set with a tuple p = figure(plot_width=400, plot_height=400, x_range=(0, 20)) # set a range using a Range1d p.y_range = Range1d(0, 15) p.circle([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10) show(p)
Ranges also have a bounds property that lets you specify the limits of the plot beyond which the user cannot pan or zoom.
bounds
# set a range using a Range1d p.y_range = Range1d(0, 15, bounds=(0, None))
All the examples above use the default linear axis. This axis is suitable for plots that need to show numerical data on a linear scale. However, you may have categorical data or need to display numerical data on a datetime or log scale. This section shows you how to specify the axis type when using the bokeh.plotting interface.
To create a categorical axis, specify a FactorRange for one of the plot’s ranges or a list of factors to be converted to one. Here’s an example:
FactorRange
from bokeh.plotting import figure, output_file, show factors = ["a", "b", "c", "d", "e", "f", "g", "h"] x = [50, 40, 65, 10, 25, 37, 80, 60] output_file("categorical.html") p = figure(y_range=factors) p.circle(x, factors, size=15, fill_color="orange", line_color="green", line_width=3) show(p)
For complete details, see Handling categorical data.
The example in this section requires a network connection and depends on the open source Pandas library to present realistic time series data.
For time series, or any data that involves dates or time, you may want to use axes with labels suitable for different date and time scales.
The figure() function accepts x_axis_type and y_axis_type as arguments. To specify a datetime axis, pass "datetime" for the value of either of these parameters.
x_axis_type
y_axis_type
"datetime"
import pandas as pd from bokeh.plotting import figure, output_file, show from bokeh.sampledata.stocks import AAPL df = pd.DataFrame(AAPL) df['date'] = pd.to_datetime(df['date']) output_file("datetime.html") # create a new plot with a datetime axis type p = figure(plot_width=800, plot_height=250, x_axis_type="datetime") p.line(df['date'], df['close'], color='navy', alpha=0.5) show(p)
Future versions of Bokeh will attempt to auto-detect situations when datetime axes are appropriate and add them automatically.
Data that grows exponentially or covers many orders of magnitude often requires one axis to be on a log scale. For data that has a power law relationship, you may want to use log scales on both axes.
You can use the same figure() arguments, x_axis_type and y_axis_type, to set one or both of the axes to "log".
"log"
By default, Bokeh calculates log axis ranges to fit around positive value data. For information on how to set your own ranges, see Setting ranges.
from bokeh.plotting import figure, output_file, show x = [0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0] y = [10**xx for xx in x] output_file("log.html") # create a new plot with a log axis type p = figure(plot_width=400, plot_height=400, y_axis_type="log") p.line(x, y, line_width=2) p.circle(x, y, fill_color="white", size=8) show(p)
You can add multiple axes representing different ranges to a single plot. To do this, configure the plot with “extra” named ranges in the extra_x_range and extra_y_range properties. You can then refer to these named ranges when adding new glyph methods as well as when adding new axis objects with the add_layout method of the Plot. Here’s an example:
extra_x_range
extra_y_range
add_layout
Plot
from numpy import arange, linspace, pi, sin from bokeh.models import LinearAxis, Range1d from bokeh.plotting import figure, output_file, show x = arange(-2*pi, 2*pi, 0.1) y = sin(x) y2 = linspace(0, 100, len(y)) output_file("twin_axis.html") p = figure(x_range=(-6.5, 6.5), y_range=(-1.1, 1.1)) p.circle(x, y, color="red") p.extra_y_ranges = {"foo": Range1d(start=0, end=100)} p.circle(x, y2, color="blue", y_range_name="foo") p.add_layout(LinearAxis(y_range_name="foo"), 'left') show(p)