Ranges and axes#
Axis Ranges#
Default auto-ranging#
By default, Bokeh attempts to automatically set the data bounds of plots to fit
snugly around all the data available. This auto-ranging is performed by the
DataRange1d
models that are the default values for a plot’s x_range
and
y_range
properties.
Windowed auto-ranging#
Sometimes, you may want auto-ranging on one axis to be be based only on what is currently inside the viewport defined by the range of the other axis. For example, if you are panning through a long timeseries in the x-direction, and want the y-axis to adjust its range to fit only what is on the screen.
This can be accomplished by setting the window_axis
property on a plot.
In the above case, to have the x-axis define the window for auto-ranging on
the y-axis, you can set:
p.window_axis = "x"
See range_tool.py for a full example.
Setting ranges manually#
Other times, you may 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.
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:
from bokeh.models import Range1d
from bokeh.plotting import figure, show
# create a new plot with a range set with a tuple
p = figure(width=400, height=400, x_range=(0, 20))
# set a range using a Range1d
p.y_range = Range1d(0, 15)
p.scatter([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.
# set a range using a Range1d
p.y_range = Range1d(0, 15, bounds=(0, None))
Axis types#
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.
Categorical axes#
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:
from bokeh.plotting import figure, show
factors = ["a", "b", "c", "d", "e", "f", "g", "h"]
x = [50, 40, 65, 10, 25, 37, 80, 60]
p = figure(y_range=factors)
p.scatter(x, factors, size=15, fill_color="orange", line_color="green", line_width=3)
show(p)
Datetime axes#
Note
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.
import pandas as pd
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import AAPL
df = pd.DataFrame(AAPL)
df['date'] = pd.to_datetime(df['date'])
# create a new plot with a datetime axis type
p = figure(width=800, 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.
Log scale axes#
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"
.
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 manually.
from bokeh.plotting import figure, show
x = [0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
y = [10**xx for xx in x]
# create a new plot with a log axis type
p = figure(width=400, height=400, y_axis_type="log")
p.line(x, y, line_width=2)
p.scatter(x, y, fill_color="white", size=8)
show(p)
Mercator axes#
Mercator axes are useful for tile sources. You can use the same figure()
arguments, x_axis_type
and y_axis_type
,
to set one or both of the axes to "mercator"
.
from bokeh.plotting import figure, show
# range bounds supplied in web mercator coordinates
p = figure(x_range=(-2000000, 2000000), y_range=(1000000, 7000000),
x_axis_type="mercator", y_axis_type="mercator")
p.add_tile("CartoDB Positron", retina=True)
show(p)
Twin axes#
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:
from numpy import arange, linspace, pi, sin
from bokeh.layouts import column
from bokeh.models import (CustomJS, LinearAxis, Range1d, Select,
WheelZoomTool, ZoomInTool, ZoomOutTool)
from bokeh.palettes import Sunset6
from bokeh.plotting import figure, show
x = arange(-2*pi, 2*pi, 0.2)
y = sin(x)
y2 = linspace(0, 100, len(x))
blue, red = Sunset6[2], Sunset6[5]
p = figure(x_range=(-2*pi, 2*pi), y_range=(-1, 1), tools="pan,box_zoom,save,reset")
p.background_fill_color = "#fafafa"
blue_circles = p.scatter(x, y, line_color="black", fill_color=blue, size=12)
p.axis.axis_label = "light blue circles"
p.axis.axis_label_text_color = blue
p.extra_x_ranges['foo'] = Range1d(-2*pi, 2*pi)
p.extra_y_ranges['foo'] = Range1d(0, 100)
red_circles = p.scatter(x, y2, color=red, size=8,
x_range_name="foo",
y_range_name="foo",
)
ax2 = LinearAxis(
axis_label="red circles",
x_range_name="foo",
y_range_name="foo",
)
ax2.axis_label_text_color = red
p.add_layout(ax2, 'left')
ax3 = LinearAxis(
axis_label="red circles",
x_range_name="foo",
y_range_name="foo",
)
ax3.axis_label_text_color = red
p.add_layout(ax3, 'below')
wheel_zoom = WheelZoomTool()
p.add_tools(wheel_zoom)
p.toolbar.active_scroll = wheel_zoom
zoom_in_blue = ZoomInTool(renderers=[blue_circles], description="Zoom in blue circles")
zoom_out_blue = ZoomOutTool(renderers=[blue_circles], description="Zoom out blue circles")
p.add_tools(zoom_in_blue, zoom_out_blue)
zoom_in_red = ZoomInTool(renderers=[red_circles], description="Zoom in red circles")
zoom_out_red = ZoomOutTool(renderers=[red_circles], description="Zoom out red circles")
p.add_tools(zoom_in_red, zoom_out_red)
select = Select(title="Zoom together:", options=["none", "cross", "all"], value=wheel_zoom.zoom_together)
select.js_on_change("value", CustomJS(
args=dict(select=select, wheel_zoom=wheel_zoom),
code="""\
export default ({select, wheel_zoom}) => {
wheel_zoom.zoom_together = select.value
}
""",
))
show(column(select, p))
Fixed location axis#
By default Bokeh places axes on the sides of plots, but it is possible to
locate axes anywhere along a range by setting their fixed_location
property:
import numpy as np
from bokeh.plotting import figure, show
x = np.linspace(-6, 6, 500)
y = 8*np.sin(x)*np.sinc(x)
p = figure(width=800, height=300, title="", tools="",
toolbar_location=None, match_aspect=True)
p.line(x, y, color="navy", alpha=0.4, line_width=4)
p.background_fill_color = "#efefef"
p.xaxis.fixed_location = 0
p.yaxis.fixed_location = 0
show(p)