Styling plot elements#
Selecting plot objects#
If you want to customize the appearance of any element of your Bokeh plot, you first need to identify which object you want to modify. As described in Introduction, Bokeh plots are a combination of Python objects that represent all the different parts of your plot: its grids, axes, and glyphs, for example.
Some objects have convenience methods to help you identify the objects you want to address. See Styling axes, Styling grids, and Styling legends for examples.
To query for any Bokeh plot object, use the select()
method on Plot
. For
example, to find all PanTool objects in a plot:
>>> p.select(type=PanTool)
[<bokeh.models.tools.PanTool at 0x106608b90>]
You can also use the select()
method to query on other attributes as well:
>>> p.circle(0, 0, radius=1, name="mycircle")
<bokeh.plotting.figure at 0x106608810>
>>> p.select(name="mycircle")
[<bokeh.models.renderers.GlyphRenderer at 0x106a4c810>]
This query method can be especially useful when you want to style visual attributes of Styling glyphs.
Styling plots#
In addition to the individual plot elements, a Plot
object itself also has
several visual characteristics that you can customize: the dimensions of the
plot, its backgrounds, borders, or outlines, for example. This section describes
how to change these attributes of a Bokeh plot.
The example code primarily uses the bokeh.plotting interface to create plots. However, the instructions apply regardless of how a Bokeh plot was created.
Dimensions#
To change the width and height of a Plot
, use its width
and
height
attributes. Those two attributes use screen units. They
control the size of the entire canvas area, including any axes or titles (but
not the toolbar).
If you are using the bokeh.plotting interface, you can pass these values to
figure()
directly:
from bokeh.plotting import figure, show
# create a new plot with specific dimensions
p = figure(width=700)
p.height = 300
p.scatter([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)
Responsive sizes#
To automatically adjust the width or height of your plot in relation to the
available space in the browser, use the plot’s
sizing_mode
property.
To control how the plot scales to fill its container, see the documentation for
layouts, in particular the sizing_mode
property of
LayoutDOM
.
If you set sizing_mode
to anything different than fixed
, Bokeh adjusts
the width
and height
as soon as a plot is rendered. However,
Bokeh uses width
and height
to calculate the initial aspect
ratio of your plot.
Plots will only resize down to a minimum of 100px (height or width) to prevent problems in displaying your plot.
Title#
To style the title of your plot, use the Title
annotation, which is available
as the .title
property of the Plot
.
You can use most of the standard text properties. However, text_align
and
text_baseline
do not apply. To position the title relative to the entire
plot, use the properties align
and
offset
instead.
As an example, to set the color and font style of the title text, use
plot.title.text_color
:
from bokeh.plotting import figure, show
p = figure(width=400, height=400, title="Some Title")
p.title.text_color = "olive"
p.title.text_font = "times"
p.title.text_font_style = "italic"
p.scatter([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)
Background#
To change the background fill style, adjust the background_fill_color
and
background_fill_alpha
properties of the Plot
object:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.background_fill_color = "beige"
p.background_fill_alpha = 0.5
p.scatter([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)
Border#
To adjust the border fill style, use the border_fill_color
and
border_fill_alpha
properties of the Plot
object. You can also set the
minimum border on each side (in screen units) with these properties:
min_border_left
min_border_right
min_border_top
min_border_bottom
Additionally, if you set min_border
, Bokeh applies a minimum border setting
to all sides as a convenience. The min_border
default value is 40px.
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.border_fill_color = "whitesmoke"
p.min_border_left = 80
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
show(p)
Outline#
Bokeh Plot
objects have various line properties. To change the appearance of
outlines, use those line properties that are prefixed with outline_
.
For example, to set the color of the outline, use outline_line_color
:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.outline_line_width = 7
p.outline_line_alpha = 0.3
p.outline_line_color = "navy"
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
show(p)
Styling glyphs#
To style the fill, line, or text properties of a glyph, you first need to
identify which GlyphRenderer
you want to customize. If you are using the
bokeh.plotting interface, the glyph functions return the renderer:
>>> r = p.circle([1,2,3,4,5], [2,5,8,2,7], radius=1)
>>> r
<bokeh.models.renderers.GlyphRenderer at 0x106a4c810>
Next, obtain the glyph itself from the .glyph
attribute of a
GlyphRenderer
:
>>> r.glyph
<bokeh.models.glyphs.Circle at 0x10799ba10>
This is the object to set fill, line, or text property values for:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
r = p.scatter([1,2,3,4,5], [2,5,8,2,7])
glyph = r.glyph
glyph.size = 60
glyph.fill_alpha = 0.2
glyph.line_color = "firebrick"
glyph.line_dash = [6, 3]
glyph.line_width = 2
show(p)
Selected and unselected glyphs#
To customize the styling of selected and non-selected glyphs, set the
selection_glyph
and nonselection_glyph
attributes of the GlyphRenderer
.
You can either set them manually or by passing them to add_glyph()
.
The plot below uses the bokeh.plotting interface to set these attributes. Click or tap any of the circles on the plot to see the effect on the selected and non-selected glyphs. To clear the selection and restore the original state, click anywhere in the plot outside of a circle.
from bokeh.plotting import figure, show
plot = figure(width=400, height=400, tools="tap", title="Select a circle")
renderer = plot.scatter([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=50)
renderer.selection_glyph = renderer.glyph.clone(fill_alpha=1, fill_color="firebrick", line_color=None)
renderer.nonselection_glyph = renderer.glyph.clone(fill_alpha=0.2, fill_color="blue", line_color="firebrick")
show(plot)
If you just need to set the color or alpha parameters of the selected or
non-selected glyphs, provide color and alpha arguments to the glyph function,
prefixed by "selection_"
or "nonselection_"
:
from bokeh.plotting import figure, show
plot = figure(width=400, height=400, tools="tap", title="Select a circle")
renderer = plot.scatter(
x=[1, 2, 3, 4, 5],
y=[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="blue",
nonselection_line_color="firebrick",
nonselection_line_alpha=1.0,
)
show(plot)
If you use the bokeh.models interface, use the
add_glyph()
function:
p = Plot()
source = ColumnDataSource(dict(x=[1, 2, 3], y=[1, 2, 3]))
initial_circle = Circle(x='x', y='y', fill_color='blue', radius=1)
selected_circle = Circle(fill_alpha=1, fill_color="firebrick", line_color=None)
nonselected_circle = Circle(fill_alpha=0.2, fill_color="blue", line_color="firebrick")
p.add_glyph(source,
initial_circle,
selection_glyph=selected_circle,
nonselection_glyph=nonselected_circle)
Hover inspections#
To style the appearance of glyphs that are hovered over, pass color or alpha
parameters prefixed with "hover_"
to your renderer function.
Alternatively, set the selection_glyph
and nonselection_glyph
attributes of
the GlyphRenderer
, just like in
Selected and unselected glyphs above.
This example uses the first method of passing a color parameter with the
"hover_"
prefix:
from bokeh.models import RELATIVE_DATETIME_CONTEXT, HoverTool
from bokeh.plotting import figure, show
from bokeh.sampledata.glucose import data
x = data.loc['2010-10-06'].index.to_series()
y = data.loc['2010-10-06']['glucose']
# Basic plot setup
p = figure(width=800, height=400, x_axis_type="datetime",
tools="pan,wheel_zoom", title='Hover over points')
p.xaxis.formatter.context = RELATIVE_DATETIME_CONTEXT()
p.ygrid.grid_line_color = None
p.background_fill_color = "#fafafa"
p.line(x, y, line_dash="4 4", line_width=1, color='gray')
cr = p.scatter(
x, y, size=20,
fill_color="steelblue", alpha=0.1, line_color=None,
hover_fill_color="midnightblue", hover_alpha=0.5,
hover_line_color="white",
)
p.add_tools(HoverTool(tooltips=None, renderers=[cr], mode='hline'))
show(p)
Overriding non-visual properties#
Glyphs allow any data driven property to be overridden, not just visual
properties. This way the user can, for example, change the size of markers in
a scatter plot on hover or even offset a glyph from its original position. In
fact the user can override the primary glyph (GlyphRenderer.glyph
) with a
completely unrelated one (e.g. replace Circle
with a Rect
).
Note
Only the primary glyph is used for hit testing and other functions. Secondary
glyphs (selection_glyph
, hover_glyph
, etc.) are used for painting and
an only affect appearance of a glyph.
This examples shows how to override non-visual properties of a Circle
glyph,
(radius
on hover) and how to use a different glyph on selection:
import numpy as np
from bokeh.core.properties import field
from bokeh.io import show
from bokeh.models import BoxAnnotation, Indexed, Rect, Tooltip
from bokeh.palettes import Spectral11
from bokeh.plotting import figure
N = 50
x = np.random.random(size=N)*100
y = np.random.random(size=N)*100
radii = np.random.uniform(1, 5, size=N)
radii_big = radii*2
colors = np.random.choice(Spectral11, size=N)
p = figure(tools=["hover", "box_select"], active_drag="box_select")
cr = p.circle(
x, y, radius=radii,
fill_color=colors, fill_alpha=0.8, line_color=None,
hover_fill_alpha=0.5, # mix `hover_` attributes with manual setup below
)
# there is no `hover_radius` so we have set things manually
cr.data_source.data["radii_big"] = radii_big
cr.hover_glyph.radius = field("radii_big")
# make selection glyph unrelated while reusing existing data
cr.selection_glyph = Rect(
line_color=None,
fill_color=field("fill_color"),
width=field("radii_big"),
height=field("radius"),
)
p.hover.tooltips = None
tooltip = Tooltip(position=Indexed(renderer=cr, index=0), content="Hover over me!", visible=True)
p.elements.append(tooltip)
box = BoxAnnotation(left=40, right=80, top=80, bottom=40)
tooltip = Tooltip(position=box.nodes.top_center, content="Select me!", visible=True, attachment="above")
box.elements.append(tooltip)
p.renderers.append(box)
show(p)
Styling axes#
This section focuses on changing various visual properties of Bokeh plot axes.
To set style attributes on Axis objects, use the xaxis
, yaxis
, and
axis
methods on Plot
to first obtain a plot’s Axis objects. For example:
>>> p.xaxis
[<bokeh.models.axes.LinearAxis at 0x106fa2390>]
Because there may be more than one axis, this method returns a list of Axis objects. However, as a convenience, these lists are splattable. This means that you can set attributes directly on this result, and the attributes will be applied to all the axes in the list. For example:
p.xaxis.axis_label = "Temperature"
This changes the value of axis_label
for every x-axis of p
, however
many there may be.
The example below demonstrates the use of the xaxis
, yaxis
, and
axis
methods in more details:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
# change just some things about the x-axis
p.xaxis.axis_label = "Temp"
p.xaxis.axis_line_width = 3
p.xaxis.axis_line_color = "red"
# change just some things about the y-axis
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(p)
Labels#
To add or change the text of an axis’ overall label, use the axis_label
property. To add line breaks to the text in an axis label, include \n
in
your string.
To control the visual appearance of the label text, use any of the standard
text properties prefixed with axis_label_
. For instance, to set the text
color of the label, set axis_label_text_color
.
To change the distance between the axis label and the major tick labels, set the
axis_label_standoff
property.
For example:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis.axis_label = "Lot Number"
p.xaxis.axis_label_text_color = "#aa6666"
p.xaxis.axis_label_standoff = 30
p.yaxis.axis_label = "Bin Count"
p.yaxis.axis_label_text_font_style = "italic"
show(p)
Bounds#
To limit the bounds where axes are drawn, set the bounds
property of an axis
object to a 2-tuple of (start, end):
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis.bounds = (2, 4)
show(p)
Tick locations#
Bokeh uses several “ticker” models to decide where to display ticks on axes
(categorical, datetime, mercator, linear, or log scale). To configure the
placements of ticks, use the .ticker
property of an axis.
If you use the bokeh.plotting interface, Bokeh chooses an appropriate ticker placement model automatically.
In case you need to control which ticker placement model to use, you can also
explicitly define a list of tick locations. Assign
FixedTicker
with a list of tick locations to an
axis:
from bokeh.plotting import figure
from bokeh.models.tickers import FixedTicker
p = figure()
# no additional tick locations will be displayed on the x-axis
p.xaxis.ticker = FixedTicker(ticks=[10, 20, 37.4])
As a shortcut, you can also supply the list of ticks directly to an axis’
ticker
property:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis.ticker = [2, 3.5, 4]
show(p)
CustomJSTicker
#
To fully customize the location of axis ticks, use the CustomJSTicker
in
combination with a JavaScript snippet as its major_code
and minor_code
properties.
These code snippets should return lists of tick locations:
from bokeh.models import CustomJSTicker
from bokeh.plotting import figure, show
xticker = CustomJSTicker(
# always three equally spaced ticks
major_code="""
const {start, end} = cb_data.range
const interval = (end-start) / 4
return [start + interval, start + 2*interval, start + 3*interval]
""",
# minor ticks in between the major ticks
minor_code="""
const {start, end, major_ticks} = cb_data
return [
(start+major_ticks[0])/2,
(major_ticks[0]+major_ticks[1])/2,
(major_ticks[1]+major_ticks[2])/2,
(major_ticks[2]+end)/2,
]
""",
)
yticker = CustomJSTicker(major_code="return ['a', 'c', 'e', 'g']")
p = figure(y_range=list("abcdefg"))
p.scatter([1, 2, 3, 4, 5], ["a", "d", "b", "f", "c"], size=30)
p.xaxis.ticker = xticker
# keep the grid lines at all original tick locations
p.ygrid.ticker = p.yaxis.ticker
p.yaxis.ticker = yticker
show(p)
Tick lines#
To control the visual appearance of the major and minor ticks, set the
appropriate line properties, prefixed with major_tick_
and
minor_tick_
, respectively.
For instance, to set the color of the major ticks, use
major_tick_line_color
. To hide either set of ticks, set the color to
None
.
Additionally, to control how far in and out of the plotting area the ticks
extend, use the properties major_tick_in
/major_tick_out
and
minor_tick_in
/minor_tick_out
. These values are in screen units.
Therefore, you can use negative values.
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis.major_tick_line_color = "firebrick"
p.xaxis.major_tick_line_width = 3
p.xaxis.minor_tick_line_color = "orange"
p.yaxis.minor_tick_line_color = None
p.axis.major_tick_out = 10
p.axis.minor_tick_in = -3
p.axis.minor_tick_out = 8
show(p)
Tick label formats#
To style the text of axis labels, use the TickFormatter
object of the axis’
formatter
property. Bokeh uses a number of ticker formatters by default in
different situations:
BasicTickFormatter
— Default formatter for linear axes.CategoricalTickFormatter
— Default formatter for categorical axes.DatetimeTickFormatter
— Default formatter for datetime axes.LogTickFormatter
— Default formatter for log axes.
These default tick formatters do not expose many configurable properties.
To control tick formatting at a finer-grained level, use one of the
NumeralTickFormatter
or PrintfTickFormatter
described below.
Note
To replace a tick formatter on an axis, you must set the formatter
property on an actual Axis
object, not on a splattable list. This is
why the following examples use p.yaxis[0].formatter
, etc. (with the
subscript [0]
).
NumeralTickFormatter
#
The NumeralTickFormatter
has a format
property that can be used
to control the text formatting of axis ticks.
from bokeh.models import NumeralTickFormatter
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis[0].formatter = NumeralTickFormatter(format="0.0%")
p.yaxis[0].formatter = NumeralTickFormatter(format="$0.00")
show(p)
Many additional formats are available. See the full NumeralTickFormatter
documentation in the reference guide.
PrintfTickFormatter
#
The PrintfTickFormatter
has a format
property that can be used
to control the text formatting of axis ticks using printf
style
format strings.
from bokeh.models import PrintfTickFormatter
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis[0].formatter = PrintfTickFormatter(format="%4.1e")
p.yaxis[0].formatter = PrintfTickFormatter(format="%5.3f mu")
show(p)
For full details about formats, see the full PrintfTickFormatter
documentation in the reference guide.
CustomJSTickFormatter
#
To fully customize the format of axis ticks, use the CustomJSTickFormatter
in
combination with a JavaScript snippet as its code
property.
The variable tick
contains the unformatted tick value. It is accessible in
the snippet or function namespace at render time:
from bokeh.models import CustomJSTickFormatter
from bokeh.plotting import figure, show
p = figure(width=500, height=500)
p.scatter([0, 2, 4, 6, 8, 10], [6, 2, 4, 10, 8, 0], size=30)
p.yaxis.formatter = CustomJSTickFormatter(code="""
return Math.floor(tick) + " + " + (tick % 1).toFixed(2)
""")
show(p)
Datetime tick context#
Datetime tick formatters have additional properties for adding more context to ticks on datetime axes. For instance, a context format might show the year, month, and day on the first tick, while the regular ticks show an hour and minute.
This is especially useful in cases where an axis is zoomable. For example: when zooming in to a level of seconds, the tick formatter context can provide additional information about broader units of time, such as day or month.
The context options are:
context
A format for adding context to the tick or ticks specified by
context_which
. Values are:None, no context is added
A standard
DatetimeTickFormatter
format string, this single format is used across all scalesAnother
DatetimeTickFormatter
instance, to add scale-dependent context
context_which
Which tick or ticks to add a formatted context string to. Values are:
"start"
,"end"
,"center"
, and"all"
.context_location
Relative to the tick label text baseline, where the context should be rendered. Values are:
"below"
,"above"
,"left"
, and"right"
.
There is a pre-defined RELATIVE_DATETIME_CONTEXT
that adds context that
is more or less a single scale higher. The example below demonstrates these
options:
from bokeh.models import RELATIVE_DATETIME_CONTEXT
from bokeh.plotting import figure, show
from bokeh.sampledata.glucose import data
x = data.loc['2010-10-06'].index.to_series()
y = data.loc['2010-10-06']['glucose']
p = figure(sizing_mode="stretch_width", x_axis_type="datetime",
tools="xwheel_zoom")
p.xaxis.formatter.context = RELATIVE_DATETIME_CONTEXT()
p.line(x, y, line_dash="4 4", line_width=3, color='gray')
show(p)
It is possible to “chain” multiple DatetimeTickFormatter
instances together,
for as many levels of context as desired. For example:
p.xaxis.formatter.context = DatetimeTickFormatter(...)
p.xaxis.formatter.context.context = DatetimeTickFormatter(...)
Tick label orientation#
To control the orientation of major tick labels, use the
major_label_orientation
property. This property accepts the
values "horizontal"
or "vertical"
or a floating-point number
that gives the angle (in radians) to rotate from the horizontal:
from math import pi
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.xaxis.major_label_orientation = pi/4
p.yaxis.major_label_orientation = "vertical"
show(p)
Note
There are more properties that you can use to configure Bokeh axes. For a complete list of all the various attributes that you can set on different types of Bokeh axes, see the axes section of the reference guide.
Styling grids#
In this section, you will learn how to set the visual properties of grid lines and grid bands on Bokeh plots.
To obtain a plot’s Grid objects, use the xgrid
, ygrid
, and grid
methods on
Plot
. This works similar to the convenience methods for axes:
>>> p.grid
[<bokeh.models.grids.Grid at 0x106fa2278>,
<bokeh.models.grids.Grid at 0x106fa22e8>]
These methods also return splattable lists. You can set an attribute on the list as if it was a single object, and the attribute is changed for every element of the list:
p.grid.line_dash = [4 2]
Note
The xgrid
property provides the grid objects that intersect the
x-axis (meaning vertically oriented objects). Correspondingly, ygrid
provides the grid objects that intersect the y-axis (meaning horizontally
oriented objects).
Lines#
To configure the visual appearance of grid lines, use a collection of
line properties, prefixed with grid_
.
For instance, to set the color of grid lines, use grid_line_color
. To hide
grid lines, set their line color to None
:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([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(p)
Minor lines#
To configure the visual appearance of minor grid lines, use a collection of
line properties, prefixed with minor_grid_
.
For instance, to set the color of grid lines, use minor_grid_line_color
. By
default, minor grid lines are hidden (which means that their line color is set
to None
):
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
# change just some things about the y-grid
p.ygrid.minor_grid_line_color = 'navy'
p.ygrid.minor_grid_line_alpha = 0.1
show(p)
Bands#
Use “bands” to display filled, shaded bands between adjacent grid lines. To
control the visual appearance of these bands, use a collection of
fill properties and hatch properties that are prefixed with band_
.
For instance, to set the color of grid bands, use band_fill_color
. To hide
grid bands, set their fill color to None
(this is the default).
This example defines bands filled with a solid color:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([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(p)
This example uses bands filled with a hatch pattern:
from bokeh.plotting import figure, show
p = figure(height=250, width=600, x_range=(0, 10), tools="", toolbar_location=None)
p.line(x=[0,1,2,3,4,5,6,7,8,9,10],
y=[1,3,4,3,1,2,6,5,2,3,4])
p.ygrid.grid_line_color = None
ticks = [0, 2, 4, 6, 8, 10]
p.xaxis[0].ticker = ticks
p.xgrid[0].ticker = ticks
p.xgrid.band_hatch_pattern = "/"
p.xgrid.band_hatch_alpha = 0.6
p.xgrid.band_hatch_color = "lightgrey"
p.xgrid.band_hatch_weight = 0.5
p.xgrid.band_hatch_scale = 10
show(p)
Bounds#
To set explicit bounds that limit where grids are drawn, use a 2-tuple of (start, end). This is identical to setting bounds for axes:
from bokeh.plotting import figure, show
p = figure(width=400, height=400)
p.scatter([1,2,3,4,5], [2,5,8,2,7], size=10)
p.grid.bounds = (2, 4)
show(p)
Note
There are other properties that Bokeh grids support configuring. For a complete listing of all the various attributes that can be set on Bokeh plot grids, consult the grids section of the reference guide.
Styling legends#
Similar to the convenience methods for axes and grids, there is a
legend()
method on Plot
that you can use to
obtain a plot’s Legend
objects:
bokeh.models.plots.Plot.legend
>>> p.legend
[<bokeh.models.annotations.Legend at 0x106fa2278>]
This method also returns a splattable list. Therefore, you can set an attribute on the list as if it was a single object, and the attribute is changed for every element of the list:
p.legend.label_text_font = "times"
Location#
To control the location of the legend labels, use the location
property.
Inside the plot area#
For legends in the central layout area, such as those created
automatically by bokeh.plotting, set location
to one of the following
values:
"top_left"
"top_center"
"top_right"
(the default)
"center_right"
"bottom_right"
"bottom_center"
"bottom_left"
"center_left"
"center"
or a (x, y)
tuple indicating an absolute location in screen coordinates
(pixels from the bottom-left corner).
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
p.legend.location = "bottom_left"
show(p)
Outside the plot area#
To position a legend outside the central area, use the add_layout
method of
a plot. This requires creating the Legend
object directly:
import numpy as np
from bokeh.models import Legend
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure(toolbar_location="above")
r0 = p.scatter(x, y)
r1 = p.line(x, y)
r2 = p.line(x, 2*y, line_dash=[4, 4], line_color="orange", line_width=2)
r3 = p.scatter(x, 3*y, marker="square", fill_color=None, line_color="green")
r4 = p.line(x, 3*y, line_color="green")
legend = Legend(items=[
("sin(x)" , [r0, r1]),
("2*sin(x)" , [r2]),
("3*sin(x)" , [r3, r4]),
], location="center")
p.add_layout(legend, 'right')
show(p)
In this use-case, you need to specify the legend’s location in absolute terms. Future releases will add additional options to customize legend positions.
Title#
To add or change a legend’s title, use its title
property:
plot.legend.title = "Division"
To control the visual appearance of the legend title, use any of the standard
text properties prefixed with title_
. For instance, to set the font
style of the legend, use title_text_font_style
.
To set the distance between the title and the rest of the legend (in pixels),
use the title_standoff
property.
import pandas as pd
from bokeh.palettes import Spectral4
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import AAPL, GOOG, IBM, MSFT
p = figure(width=800, height=250, x_axis_type="datetime")
for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])
p.line(df['date'], df['close'], line_width=2, color=color, legend_label=name)
p.legend.location = "top_left"
p.legend.title = 'Stock'
p.legend.title_text_font_style = "bold"
p.legend.title_text_font_size = "20px"
show(p)
Orientation#
To control the orientation of the legend, use the orientation
property.
Valid values for this property are:
"vertical"
"horizontal"
The default orientation is "vertical"
.
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
p.legend.orientation = "horizontal"
show(p)
Two dimensional layout#
It is possible to activate a two dimensional layout for the legend by setting a positive
integer to the properties nrows
or ncols
. This enables the opportunity to avoid
truncated legends.
The default for nrows
and ncols
is "auto"
, which leads to one column if
the orientation
property is "vertical"
and one row if the orientation
property
is "horizontal"
.
import numpy as np
from bokeh.layouts import column
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
sinx = np.sin(x)
p1 = figure(title='Default legend layout', width=500, height=300)
[p1.line(x, (1 + i/20)*sinx, legend_label=f"{1+i/20:.2f}*sin(x)") for i in range(7)]
p2 = figure(title='Legend layout with 2 columns', width=500, height=300)
[p2.line(x, (1 + i/20)*sinx, legend_label=f"{1+i/20:.2f}*sin(x)") for i in range(7)]
p2.legend.ncols=2
p3 = figure(title='Legend layout with 3 rows', width=500, height=300)
[p3.line(x, (1 + i/20)*sinx, legend_label=f"{1+i/20:.2f}*sin(x)") for i in range(7)]
p3.legend.nrows=3
show(column(p1, p2, p3))
Label text#
To control the visual appearance of the legend labels, use any of the standard
text properties prefixed with label_
. For instance, to set the font
style of the labels, use label_text_font_style
.
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
p.legend.label_text_font = "times"
p.legend.label_text_font_style = "italic"
p.legend.label_text_color = "navy"
show(p)
Border#
To control the visual appearance of the legend border, use a collection of
line properties, prefixed with border_
. For instance, to set the color
of the border, use border_line_color
. To make the border invisible, set
the border line color to None
.
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
p.legend.border_line_width = 3
p.legend.border_line_color = "navy"
p.legend.border_line_alpha = 0.5
show(p)
Background#
To control the visual appearance of the legend background, use a collection
of fill properties, prefixed with background_
. For instance, to set the
color of the background, use background_fill_color
. To make the background
transparent, set the background_fill_alpha
to 0
.
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
# 3*sin(x) curve should be under this legend at initial viewing, so
# we can see that the legend is transparent
p.legend.location = "bottom_right"
p.legend.background_fill_color = "navy"
p.legend.background_fill_alpha = 0.5
show(p)
Dimensions#
To control dimensions such as the layout or spacing of label components, use the following properties:
There are several properties that can be used to control the layout, spacing, etc. of the legend components:
- label_standoff = 5#
- Type:
The distance (in pixels) to separate the label from its associated glyph.
- label_width = 20#
- Type:
The minimum width (in pixels) of the area that legend labels should occupy.
- label_height = 20#
- Type:
The minimum height (in pixels) of the area that legend labels should occupy.
- padding = 10#
- Type:
Amount of padding around the contents of the legend. Only applicable when border is visible, otherwise collapses to 0.
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure()
p.scatter(x, y, legend_label="sin(x)")
p.line(x, y, legend_label="sin(x)")
p.line(x, 2*y, legend_label="2*sin(x)",
line_dash=[4, 4], line_color="orange", line_width=2)
p.scatter(x, 3*y, marker="square", legend_label="3*sin(x)", fill_color=None, line_color="green")
p.line(x, 3*y, legend_label="3*sin(x)", line_color="green")
p.legend.label_standoff = 5
p.legend.glyph_width = 50
p.legend.spacing = 10
p.legend.padding = 50
p.legend.margin = 50
show(p)
Setting render levels#
To specify the order in which things are drawn, use one of the following render levels:
- image:
“lowest” render level, drawn before anything else
- underlay:
default render level for grids
- glyph:
default render level for all glyphs (which means they are drawn above grids)
- annotation:
default render level for annotation renderers
- overlay:
“highest” render level, for tool overlays
Within a given level, renderers are drawn in the order that they were added.
To specify a render level explicitly, use the level
parameter on the
renderer.
For example, to make sure an image is rendered under the grid lines, assign
the render level "image"
to the level
argument when calling your
image
renderer:
p.image(..., level="image")
You can see a complete example with output in the section Color mapped images.