Plotting with Basic Glyphs¶
Creating Figures¶
Note that Bokeh plots created using the bokeh.plotting interface come with a default set of tools, and default visual styles. See Styling Visual Attributes for information about how to customize the visual style of plots, and Configuring Plot Tools for information about changing or specifying tools.
Scatter Markers¶
To scatter circle markers on a plot, use the circle()
method of 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, to scatter square markers, use the square()
method of Figure
:
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)
There are lots of marker types available in Bokeh, you can see details and example plots for all of them by clicking on entries in the list below:
All the markers have the same set of properties: x
, y
, size
(in
screen units), and angle
(radians by
default). Additionally, circle()
has a radius
property that can be used to
specify data-space units.
Line Glyphs¶
Single Lines¶
Below is an example that shows how to generate a single line glyph from
one dimensional sequences of x and y points using the line()
glyph
method:
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)
Step Lines¶
For some kinds of data, it may be more appropriate to draw discrete steps
between data points, instead of connecting points with linear segments. The
step()
glyph method can be used to accomplish this:
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)
Step levels can be drawn before, after, or centered on the x-coordinates,
as condfigured by the mode
parameter.
Multiple Lines¶
Sometimes it is useful to plot multiple lines all at once. This can be
accomplished with the multi_line()
glyph method:
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
This glyph is unlike most other glyphs. Instead of accepting a one dimensional list or array of scalar values, it accepts a “list of lists” for x and y positions of each line, parameters xs and ys. multi_line also expects a scalar value or a list of scalers per each line for parameters such as color, alpha, linewidth, etc. Similarily, a ColumnDataSource may be used consisting of a “list of lists” and a lists of scalars where the length of the list of scalars and length of lists must match.
Missing Points¶
NaN
values can be passed to line()
and multi_line()
glyphs. In this case,
you end up with single logical line objects, that have multiple disjoint
components when rendered:
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)
Bars and Rectangles¶
Rectangles¶
To draw axis aligned rectangles (“quads”) by specifying the left
,
right
, top
, and bottom
positions, use the quad()
glyph function:
from bokeh.plotting import figure, show, output_file
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 a center point, width, height,
and angle, use the rect()
glyph function:
from math import pi
from bokeh.plotting import figure, show, output_file
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)
Bars¶
When drawing rectangular bars (often representing intervals) it is often
more convenient to have coordinates that are a hybrid of the two systems
above. Bokeh provides the hbar()
and vbar()
glyphs function for this
purpose.
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, show, output_file
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, show, output_file
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)
Hex Tiles¶
Bokeh can plot hexagonal tiles, which are often used for showing binned
aggregations. The hex_tile()
method
takes a size parameter to define the size of the hex grid, and
axial coordinates to specify which tiles are present.
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.py")
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 realistic example below computes counts per bin using the
hexbin()
funtion and plots the colormapped counts:
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)
The above code can be made even simpler by calling the hexbin()
method of Figure
.
Patch Glyphs¶
Single Patches¶
Below is an example that shows how to generate a single polygonal patch
glyph from one dimensional sequences of x and y points using the
patch()
glyph method:
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 an line width
p.patch([1, 2, 3, 4, 5], [6, 7, 8, 7, 3], alpha=0.5, line_width=2)
show(p)
Multiple Patches¶
Sometimes it is useful to plot multiple polygonal patches all at once.
This can be accomplished with the patches()
glyph method:
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)
Note
This glyph is unlike most other glyphs. Instead of accepting a one dimensional list or array of scalar values, it accepts a “list of lists” for x and y positions of each patch, parameters xs and ys. patches also expects a scalar value or a list of scalers per each patch for parameters such as color, alpha, linewidth, etc. Similarily, a ColumnDataSource may be used consisting of a “list of lists” and a lists of scalars where the length of the list of scalars and length of lists must match.
Missing Points¶
Just as with line()
and multi_line()
, NaN
values can be passed to
patch()
and patches()
glyphs. In this case, you end up with single logical
patch objects, that have multiple disjoint components when rendered:
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
Hit testing on patch objects with NaN
values is not currently
supported.
Ovals and Ellipses¶
The oval()
glyph method accepts the same properties as rect()
, but renders
oval shapes:
from math import pi
from bokeh.plotting import figure, show, output_file
output_file('ovals.html')
p = figure(plot_width=400, plot_height=400)
p.oval(x=[1, 2, 3], y=[1, 2, 3], width=0.2, height=40, color="#CAB2D6",
angle=pi/3, height_units="screen")
show(p)
The ellipse()
glyph accepts the same properties as oval()
and rect()
but
renders ellipse shapes, which are different from oval ones. In particular,
the same value for width and height will render a circle using the ellipse()
glyph but not the oval()
one:
from math import pi
from bokeh.plotting import figure, show, output_file
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)
Images¶
You can display images on Bokeh plots using the image()
, image_rgba()
, and
image_url()
glyph methods.
The first example here shows how to display images in Bokeh plots from
raw RGBA data using image_rgba()
:
Note
This example depends on the open source NumPy library in order to more easily generate an array of RGBA data.
from __future__ import division
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)
Segments and Rays¶
Sometimes it is useful to be able to draw many individual line segments at
once. Bokeh provides the segment()
and ray()
glyph methods to render these.
The segment()
function accepts start points x0
, y0
and end points
x1
and y1
and renders segments between these:
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()
function accepts start points x
, y
with a length
(in screen units) and an angle
. The default
angle_units
are "rad"
but can also be changed to "deg"
. To have an
“infinite” ray, that always extends to the edge of the plot, specify 0
for
the length:
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)
Wedges and Arcs¶
To draw a simple line arc, Bokeh provides 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.
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:
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 arc()
, but draws a filled area.
It accepts a inner_radius
and outer_radius
instead of just 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 methods, which accepts inner_radius
and
outer_radius
, can be used to draw filled rings:
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)
Specialized Curves¶
Bokeh also provides quadratic()
and bezier()
glyph methods for drawing
parameterized quadratic and cubic curves. These are somewhat uncommon;
please refer to the reference documentation for details.
Combining Multiple Glyphs¶
Combining multiple glyphs on a single plot is a matter of calling more than
one glyph method 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 holds in general for all the glyph methods in bokeh.plotting. Any number of glyphs may be added to a Bokeh plot.
Setting Ranges¶
By default, Bokeh will attempt to automatically set the data bounds
of plots to fit snugly around the data. Sometimes you may need to
set a plot’s range explicitly. This can be accomplished by setting the
x_range
or y_range
properties using a Range1d
object that
gives the start and end points of the range you want:
p.x_range = Range1d(0, 100)
As a convenience, the figure()
function can also accept tuples of
(start, end) as values for the x_range
or y_range
parameters.
Below is a an example that shows both methods of setting the range:
from bokeh.plotting import figure, output_file, show
from bokeh.models import Range1d
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 can also accept a min and max property that allow you to specify the edges of the plot that you do not want the user to be able to pan/zoom beyond.
Specifying Axis Types¶
All the examples above use the default linear axis. This axis is suitable for many plots that need to show numerical data on a linear scale. In other cases you may have categorical data, or need to display numerical data on a datetime or log scale. This section shows how to specify the axis type when using bokeh.plotting interface.
Categorical Axes¶
Categorical axes are created by specifying a
FactorRange
for one of the plot ranges (or a
lists of factors to be converted to one). Below is a simple example, for
complete details see Handling Categorical Data.
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)
Datetime Axes¶
When dealing with timeseries data, or any data that involves dates or times, it is desirable to have an axis that can display labels that are appropriate to different date and time scales.
Note
This example requires a network connection, and depends on the open source Pandas library in order to more easily present realistic timeseries data.
We have seen how to use the figure()
function to create plots using the
bokeh.plotting interface. This 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.
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)
Note
Future versions of Bokeh will attempt to auto-detect situations when datetime axes are appropriate, and add them automatically by default.
Log Scale Axes¶
When dealing with data that grows exponentially or is of many orders of magnitude, it is often necessary to have one axis on a log scale. Another scenario involves plotting data that has a power law relationship, when it is desirable to use log scales on both axes.
As we saw above, the figure()
function accepts x_axis_type
and
y_axis_type
as arguments. To specify a log axis, pass "log"
for
the value of either of these parameters.
By default, log axis ranges are calculated to fit around positive valued data. To set your own ranges, see the section on 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)
Twin Axes¶
It is possible to 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. Then these named ranges
can be referred to when adding new glyph methods, and also to add new axes
objects using the add_layout
method on Plot
. An example is given
below:
from numpy import pi, arange, sin, linspace
from bokeh.plotting import output_file, figure, show
from bokeh.models import LinearAxis, Range1d
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)
Adding Annotations¶
The section on adding annotations to plots has moved. Please see Adding Annotations