2. Styles and Themes

In this chapter you learn how to configure various visual aspects of our plots, and how to find out more about what an be configured.

from bokeh.io import output_notebook, show
from bokeh.plotting import figure
#nbi:hide_in
import bokeh.sampledata

#nbi:hide_out
bokeh.sampledata.download()

# Make all outputs INLINE for default (why a hell this is needed !!!)
output_notebook()
Using data directory: C:\Users\jadams\.bokeh\data
Skipping 'CGM.csv' (checksum match)
Skipping 'US_Counties.zip' (checksum match)
Skipping 'us_cities.json' (checksum match)
Skipping 'unemployment09.csv' (checksum match)
Skipping 'AAPL.csv' (checksum match)
Skipping 'FB.csv' (checksum match)
Skipping 'GOOG.csv' (checksum match)
Skipping 'IBM.csv' (checksum match)
Skipping 'MSFT.csv' (checksum match)
Skipping 'WPP2012_SA_DB03_POPULATION_QUINQUENNIAL.zip' (checksum match)
Skipping 'gapminder_fertility.csv' (checksum match)
Skipping 'gapminder_population.csv' (checksum match)
Skipping 'gapminder_life_expectancy.csv' (checksum match)
Skipping 'gapminder_regions.csv' (checksum match)
Skipping 'world_cities.zip' (checksum match)
Skipping 'airports.json' (checksum match)
Skipping 'movies.db.zip' (checksum match)
Skipping 'airports.csv' (checksum match)
Skipping 'routes.csv' (checksum match)
Skipping 'haarcascade_frontalface_default.xml' (checksum match)
Loading BokehJS ...

Colors

Before getting started, it's useful to describe how colors and properties are specified in Bokeh. There are many places where you may specify colors. Bokeh can accept colors in a variety of different ways:

  • any of the 140 named HTML/CSS colors, e.g 'green', 'indigo'
  • an RGB(A) hex value, e.g., '#FF0000', '#44444444'
  • a 3-tuple of integers (r,g,b) between 0 and 255
  • a 4-tuple of (r,g,b,a) where r, g, b are integers between 0 and 255 and a is a floating point value between 0 and 1

Properties

Regardless of how a Bokeh plot is created, styling the visual aspects of the plot can always be accomplished by setting attributes on the Bokeh objects that comprise the resulting plot. Visual properties come in three kinds: line, fill, and text properties. For full information with code and examples see the Styling Visual Properties section of the user guide.

Line Properties

Set the visual appearance of lines. The most common are line_color, line_alpha, line_width and line_dash.

Fill Properties

Set the visual appearance of filled areas: fill_color and fill_alpha.

Text Properties

Set the visual appearance of lines of text. The most common are text_font, text_font_size, text_color, and text_alpha.

Sometimes a prefix is used with property names, e.g. to distinguish between different line properties on the same object, or to give a more meaningful name. For example, to set the line width of the plot outline, you would say myplot.outline_line_width = 2.

Plots

Many top-level attributes of plots (outline, border, etc.) can be configured. See the Plots section of the styling guide for full information.

Here is an example that tweaks the plot outline:

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)

p.outline_line_width = 7
p.outline_line_alpha = 0.3
p.outline_line_color = "navy"

p.circle([1,2,3,4,5], [2,5,8,2,7], size=10)

# show the results
show(p)

Glyphs

It's also possible to style the visual properties of glyphs (see the Glyphs section of the styling guide for more information). When using bokeh.plotting this is often done when calling the glyph methods:

p.circle(line_color="red", fill_alpha=0.2, ...)

But it is also possible to set these properties directly on glyph objects. Glyph objects are found on GlyphRenderer objects, which are returned by the Plot.add_glyph and bokeh.plotting glyph methods like circle, rect, etc. Let's look at an example:

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)

# keep a reference to the returned GlyphRenderer
r = p.circle(
    [1,2,3,4,5],
    [2,5,8,2,7]
)

r.glyph.size = 50
r.glyph.fill_alpha = 0.2
r.glyph.line_color = "firebrick"
r.glyph.line_dash = [5, 1]
r.glyph.line_width = 2

# show the results
show(p)

Selection and non-selection visuals

You can also control how glyphs look when there are selections involved. The set of "selected" points is displayed according to the optional .selection_glyph property of a GlyphRenderer:

r.selection_glyph = Circle(fill_alpha=1, fill_color="firebrick", line_color=None)

When there is a non-empty selection, the set of "unselected" points is displayed according to the optional .nonselection_glyph property of a GlyphRenderer:

r.nonselection_glyph = Circle(fill_alpha=0.2, fill_color="grey", line_color=None)

When using the bokeh.plotting interface, it is easier to pass these visual properties to the glyph methods as shown below. The glyph method will create the selection or nonselection glyphs and attach them to the renderer for you.

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
    tools="tap",
    title="Select a circle"
)

renderer = p.circle(
    [1, 2, 3, 4, 5],
    [2, 5, 8, 2, 7],
    size=50,
    # set visual properties for selected glyphs
        selection_color="firebrick",
    # set visual properties for non-selected glyphs
        nonselection_fill_alpha=0.2,
        nonselection_fill_color="grey",
        nonselection_line_color="firebrick",
        nonselection_line_alpha=1.0
)

show(p)

It is also possible to specify the visual appearance of glyphs when they are "inspected", e.g. by a hover tool. This is accomplished by setting an optional hover_glyph on the glyph renderer:

r.hover_glyph = Circle(fill_alpha=1, fill_color="firebrick", line_color=None)

Or if using bokeh.plotting glyph methods, by passing hover_fill_alpha, etc. to the glyph method. Lets look at an example that works together with a HoverTool configured for "hline" hit-testing.

from bokeh.models.tools import HoverTool
from bokeh.sampledata.glucose import data

subset = data.loc['2010-10-06']

x, y = subset.index.to_series(), subset['glucose']

# Basic plot setup
p = figure(
    plot_height=400,
    plot_width=800,
    x_axis_type="datetime",
    title='Hover over points'
)

p.line(x, y, line_dash="4 4", line_width=1, color='gray')

cr = p.circle(
    x,
    y,
    size=20,
    fill_color="grey", hover_fill_color="firebrick",
    fill_alpha=0.05, hover_alpha=0.3,
    line_color=None, hover_line_color="white"
)

p.add_tools(
    HoverTool(tooltips=None, renderers=[cr], mode='hline')
)

# show the results
show(p)

Axes

Next we will take a look at stlying of Axes.

To style axes, you first must get ahold of Axis objects. The simplest way is to use some convenience methods on Plot: axis, xaxis, and yaxis. These methods return lists of axis objects:

>>> p.xaxis
[<bokeh.models.axes.LinearAxis at 0x106fa2390>]

However, you can set properties on all the elements of the list as if it was a single object:

p.xaxis.axis_label = "Temperature"
p.axis.major_label_text_color = "orange"

These are referred to as "splattable" lists, and tab completion works on them as well.

Axis properties

Axes objects have many configurable properties that afford control over most visual aspects of an axis. These can be grouped by function according to prefix:

  • axis line properties e.g axis_line_width

  • axis_label text properties e.g. axis_label_text_color, as well as axis_label_standoff

  • major_label text properties e.g. major_label_text_font_size, as well as major_label_orientation

  • major_tick line_properties e.g. major_tick_line_dash, as well as major_tick_in and major_tick_out

  • minor_tick line properties e.g. minor_tick_line_width, as well as minor_tick_in and minor_tick_out

As a simple first case, let's change the orientation of the major tick labels on both axes of a plot:

from math import pi

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)

p.x(
    [1,2,3,4,5],
    [2,5,8,2,7],
    size=10,
    line_width=2
)

p.xaxis.major_label_orientation = pi/4
p.yaxis.major_label_orientation = "vertical"

# show the results
show(p)

The next example shows customizations on several of the different Axis properties at once:

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)

p.asterisk(
    [1,2,3,4,5],
    [2,5,8,2,7],
    size=12,
    color="olive"
)

# change just some things about the x-axes
p.xaxis.axis_label = "Temp"
p.xaxis.axis_line_width = 3
p.xaxis.axis_line_color = "red"

# change just some things about the y-axes
p.yaxis.axis_label = "Pressure"
p.yaxis.major_label_text_color = "orange"
p.yaxis.major_label_orientation = "vertical"

# change things on all axes
p.axis.minor_tick_in = -3
p.axis.minor_tick_out = 6

# show the results
show(p)

Configuring tick labels

All Bokeh axes have a formatter property, whose value is a TickFormatter object that Bokeh uses to format the ticks displayed by that axis. Bokeh will configure default tick formatters for numeric, datetime, or categotical axes. But often we would like to customize the appearance of tick labels. This can be accomplished by changing properties on the default formatter that Bokeh chooses, or by replacing the formatter with a new type entirely.

Let's first look at changing the properties of a default formatter. The default datetime formatter is configured to show month/day when the axis is on the scale of days. If would like the also always show the year, we can change the days property to a format that includes the year, as done below.

from math import pi
from bokeh.sampledata.glucose import data

week = data.loc['2010-10-01':'2010-10-08']

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
    x_axis_type="datetime",
    title="Glocose Range"
)


p.xaxis.formatter.days = '%m/%d/%Y'
p.xaxis.major_label_orientation = pi/3

p.line(week.index, week.glucose)

# show the results
show(p)

See the reference guide entry for DatetimeTickFormatter to see other properties that can be updated.

In addition to the tick formatters that Bokeh will use by default, there are others such as the NumeralTickFormatter that we can configure explicitly. The example below shows how to set a formatter on each axis.

from bokeh.models import NumeralTickFormatter

p = figure(plot_height=300, plot_width=800)
p.circle([1,2,3,4,5], [2,5,8,2,7], size=10)

p.xaxis.formatter = NumeralTickFormatter(format="0.0%")
p.yaxis.formatter = NumeralTickFormatter(format="$0.00")

# show the results
show(p)

Try experimenting with the format argument and re-execute the cell above.

There are many other possibilities for controlling tick formatting, including the possibility of supplying a JavaScript snippet to perform arbitrary formatting in the browser. See the Tick Label Formats for more details.

It is also possible to customize where ticks will be drawn. See the Tick Locations section of the User's Guide for more information.

Grids

It is also possible to control the styling of Grids

Grids properties in Bokeh have two possible prefixes:

  • grid properties (which are line properties) control the "grid lines"
  • band properties (which are fill properties) control shaded bands between grid lines

In this first example we turn off the vertical grid lines (by setting the line color to None) and set the horizontal grid to be light and dashed.

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)

p.circle(
    [1,2,3,4,5],
    [2,5,8,2,7],
    size=10
)

# change just some things about the x-grid
p.xgrid.grid_line_color = None

# change just some things about the y-grid
p.ygrid.grid_line_alpha = 0.5
p.ygrid.grid_line_dash = [6, 4]

# show the results
show(p)

The next example shows how the "band" properties of a plot can be specified

# create a new plot using figure
p = figure(
    plot_height=400,
    plot_width=800,
)


p.circle(
    [1,2,3,4,5],
    [2,5,8,2,7],
    size=10
)

# change just some things about the x-grid
p.xgrid.grid_line_color = None

# change just some things about the y-grid
p.ygrid.band_fill_alpha = 0.1
p.ygrid.band_fill_color = "navy"

# show the results
show(p)