A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://bokeh.pydata.org/en/latest/docs/user_guide/basic/annotations.html below:

Annotations — Bokeh 3.7.3 Documentation

Annotations#

Bokeh includes several different types of annotations you can use to add supplemental information to your visualizations.

Titles#

Use Title annotations to add descriptive text which is rendered around the edges of a plot.

If you use the bokeh.plotting interface, the quickest way to add a basic title is to pass the text as the title parameter to figure():

from bokeh.plotting import figure, show

p = figure(title="Basic Title", width=300, height=300)

p.scatter([1, 2], [3, 4])

show(p)

The default title is generally located above a plot, aligned to the left.

The title text may value contain newline characters which will result in a multi-line title.

p = figure(title="A longer title\nwith a second line underneath")

To define the placement of the title in relation to the plot, use the title_location parameter. A title can be located above, below, left, or right of a plot. For example:

from bokeh.plotting import figure, show

p = figure(title="Left Title", title_location="left",
           width=300, height=300)

p.scatter([1, 2], [3, 4])

show(p)

Use your plot’s .title property to customize the default Title. Use the standard text properties to define visual properties such as font, border, and background.

This example uses the .title property to set the font and background properties as well as the title text and title alignment:

from bokeh.plotting import figure, show

p = figure(width=300, height=300)

p.scatter([1, 2], [3, 4])

# configure visual properties on a plot's title attribute
p.title.text = "Title With Options"
p.title.align = "right"
p.title.text_color = "orange"
p.title.text_font_size = "25px"
p.title.background_fill_color = "#aaaaee"

show(p)

Note that the align property is relative to the direction of the text. For example: If you have placed your title on the left side of your plot, setting the align property to "left" means your text is rendered in the lower left corner.

To add more titles to your document, you need to create additional Title objects. Use the add_layout() method of your plot to include those additional Title objects in your document:

from bokeh.models import Title
from bokeh.plotting import figure, show

p = figure(title="Left Title", title_location="left",
           width=300, height=300)

p.scatter([1, 2], [3, 4])

# add extra titles with add_layout(...)
p.add_layout(Title(text="Bottom Centered Title", align="center"), "below")

show(p)

If a title and a toolbar are placed on the same side of a plot, they will occupy the same space:

from bokeh.plotting import figure, show

p = figure(title="Top Title with Toolbar", toolbar_location="above",
           width=600, height=300)

p.scatter([1, 2], [3, 4])

show(p)

If the plot size is large enough, this can result in a more compact plot. However, if the plot size is not large enough, the title and toolbar may visually overlap.

Color bars#

To create a ColorBar, you can pass an instance of ColorMapper containing a color palette, for example:

color_bar = ColorBar(color_mapper=color_mapper, padding=5)

However, for many glyphs, you can call construct_color_bar on the renderer returned by the glyph method to create a color bar automatically, if the glyph already has a color mapping configured:

color_bar = r.construct_color_bar(padding=5)

Color bars can be located inside as well as left, right, below, or above the plot. Specify the location of a color bar when adding the ColorBar object to the plot using the add_layout() method.

import numpy as np

from bokeh.models import LogColorMapper
from bokeh.plotting import figure, show


def normal2d(X, Y, sigx=1.0, sigy=1.0, mux=0.0, muy=0.0):
    z = (X-mux)**2 / sigx**2 + (Y-muy)**2 / sigy**2
    return np.exp(-z/2) / (2 * np.pi * sigx * sigy)

X, Y = np.mgrid[-3:3:200j, -2:2:200j]
Z = normal2d(X, Y, 0.1, 0.2, 1.0, 1.0) + 0.1*normal2d(X, Y, 1.0, 1.0)
image = Z * 1e6

color_mapper = LogColorMapper(palette="Viridis256", low=1, high=1e7)

plot = figure(x_range=(0,1), y_range=(0,1), toolbar_location=None)
r = plot.image(image=[image], color_mapper=color_mapper,
               dh=1.0, dw=1.0, x=0, y=0)

color_bar = r.construct_color_bar(padding=1)

plot.add_layout(color_bar, "right")

show(plot)
Scale bars#

ScaleBar is a visual indicator that allows to gauge the size of features on a plot. This is particularly useful with maps or images like CT or MRI scans, and in situations where using axes would be otherwise inappropriate or too verbose.

To create a ScaleBar the user needs at least to provide a Range, either an explicit or an implicit one.

from bokeh.models import Range1d, ScaleBar

scale_bar = ScaleBar(range=Range1d(start=0, end=1000))
plot.add_layout(scale_bar)

The range can also be shared with a plot:

from bokeh.models import Range1d, ScaleBar

scale_bar = ScaleBar(range=plot.y_range)
plot.add_layout(scale_bar)

The default range for a ScaleBar is "auto", which uses the default x or y range of a plot the scale bar is associated with, depending on the orientation of the scale bar (Plot.x_range for "horizontal" and Plot.y_range for "vertical" orientation).

Additionally the user can provide units of measurement (ScaleBar.dimensional, which takes an instance of Dimensional model) and the unit of the data range (ScaleBar.unit). The default units of measurement is metric length represented by MetricLength model and the default unit of data range is meter ("m"), the same as the base unit of the default measurement system.

If the unit of the data range is different from the base unit, then the user can indicate this by changing ScaleBar.unit appropriately. For example, if the range is in kilometers, then the user would indicate this with:

from bokeh.models import ScaleBar, Metric

scale_bar = ScaleBar(
    range=plot.y_range,
    unit="km",
)
plot.add_layout(scale_bar)

Other units of measurement can be provided by configuring ScaleBar.dimensional property. This can be other predefined units of measurement like imperial length (ImperialLength) or angular units (Angular). The user can also define custom units of measurement. To define custom metric units, for example for a plot involving electron volts (eV), the user would use Metric(base_unit="eV") as the basis:

from bokeh.models import ScaleBar, Metric

scale_bar = ScaleBar(
    range=plot.y_range,
    unit="MeV",
    dimensional=Metric(base_unit="eV"),
)
plot.add_layout(scale_bar)

Non-metric units of measurement can be constructed with CustomDimensional model. For example, angular units of measurements can be defined as follows:

from bokeh.models import ScaleBar
from bokeh.models.annotations.dimensional import CustomDimensional

units = CustomDimensional(
    basis={
        "°":  (1,      "^\\circ",           "degree"),
        "'":  (1/60,   "^\\prime",          "minute"),
        "''": (1/3600, "^{\\prime\\prime}", "second"),
    }
    ticks=[1, 3, 6, 12, 60, 120, 240, 360]
)

scale_bar = ScaleBar(
    range=plot.y_range,
    unit="''",
    dimensional=units,
)
plot.add_layout(scale_bar)

A complete example of a scale bar with custom units of measurement:

import numpy as np

from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Metric, RangeTool, ScaleBar
from bokeh.plotting import figure, show

n_points = 3000
x_values = np.linspace(0, 100, n_points)
y_values = np.random.randn(n_points).cumsum()

source = ColumnDataSource(data=dict(x=x_values, y=y_values))

detailed_plot = figure(
    width=800,
    height=300,
    tools=["xpan", "xzoom_in", "xzoom_out", "reset", "wheel_zoom"],
    toolbar_location="above",
    active_scroll="wheel_zoom",
    background_fill_color="#efefef",
    x_range=(22, 30),
    y_axis_location=None,
)

detailed_plot.line("x", "y", source=source)

scale_bar = ScaleBar(
    range=detailed_plot.y_range,
    unit="MeV",
    dimensional=Metric(base_unit="eV"),
    orientation="vertical",
    location="top_left",
    background_fill_color=None,
    border_line_color=None,
)
detailed_plot.add_layout(scale_bar)

select_plot = figure(
    width=detailed_plot.width,
    height=150,
    y_range=detailed_plot.y_range,
    y_axis_location=None,
    tools="",
    toolbar_location=None,
    background_fill_color=detailed_plot.background_fill_color,
)

select_plot.line("x", "y", source=source)
select_plot.x_range.range_padding = 0
select_plot.ygrid.grid_line_color = None

range_tool = RangeTool(x_range=detailed_plot.x_range)
range_tool.overlay.fill_color = "navy"
range_tool.overlay.fill_alpha = 0.2
select_plot.add_tools(range_tool)

show(column(detailed_plot, select_plot))
Arrows#

You can use Arrow annotations to connect glyphs and label annotations. Arrows can also help highlight plot regions.

Arrows are compound annotations. This means that they use additional ArrowHead objects as their start and end. By default, the Arrow annotation is a one-sided arrow: The end property is set to an OpenHead-type arrowhead (looking like an open-backed wedge style) and the start property is set to None. If you want to create double-sided arrows, set both the start and end properties to one of the available arrowheads.

The available arrowheads are:

Control the appearance of an arrowhead with these properties:

Arrow objects themselves have the standard line properties. Set those properties to control the color and appearance of the arrow shaft. For example:

my_arrow.line_color = "blue"
my_arrow.line_alpha = 0.6

Optionally, you can set the x_range and y_range properties to make an arrow annotation refer to additional non-default x- or y-ranges. This works the same as Twin axes.

from bokeh.models import Arrow, NormalHead, OpenHead, VeeHead
from bokeh.palettes import Muted3 as color
from bokeh.plotting import figure, show

p = figure(tools="", toolbar_location=None, background_fill_color="#efefef")
p.grid.grid_line_color = None

p.circle(x=(0, 1, 0.5), y=(0, 0, 0.7), radius=0.1, color="#fafafa")

vh = VeeHead(size=35, fill_color=color[0])
p.add_layout(Arrow(end=vh, x_start=0.5, y_start=0.7, x_end=0, y_end=0))

nh = NormalHead(fill_color=color[1], fill_alpha=0.5, line_color=color[1])
p.add_layout(Arrow(end=nh, line_color=color[1], line_dash=[15, 5],
                   x_start=1, y_start=0, x_end=0.5, y_end=0.7))

oh = OpenHead(line_color=color[2], line_width=5)
p.add_layout(Arrow(end=oh, line_color=color[2], line_width=5,
                   x_start=0, y_start=0, x_end=1, y_end=0))

show(p)
Bands#

A Band annotation is a colored stripe that is dimensionally linked to the data in a plot. One common use for the band annotation is to indicate uncertainty related to a series of measurements.

To define a band, use either screen units or data units.

import numpy as np
import pandas as pd

from bokeh.models import Band, ColumnDataSource
from bokeh.plotting import figure, show

# Create some random data
x = np.random.random(2500) * 140 +20
y = np.random.normal(size=2500) * 2 + 6 * np.log(x)

df = pd.DataFrame(data=dict(x=x, y=y)).sort_values(by="x")

df2 = df.y.rolling(window=300).agg({"y_mean": "mean", "y_std": "std"})

df = pd.concat([df, df2], axis=1)
df["lower"] = df.y_mean - df.y_std
df["upper"] = df.y_mean + df.y_std

source = ColumnDataSource(df.reset_index())

p = figure(tools="", toolbar_location=None, x_range=(40, 160))
p.title.text = "Rolling Standard Deviation"
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5

p.scatter(x="x", y="y", color="blue", marker="dot", size=10, alpha=0.4, source=source)

p.line("x", "y_mean", line_dash=(10, 7), line_width=2, source=source)

band = Band(base="x", lower="lower", upper="upper", source=source,
            fill_alpha=0.3, fill_color="yellow", line_color="black")
p.add_layout(band)

show(p)
Box annotations#

A BoxAnnotation is a rectangular box that you can use to highlight specific plot regions. Use either screen units or data units to position a box annotation.

To define the bounds of these boxes, use the left/right or top/ bottom properties. If you provide only one bound (for example, a left value but no right value), the box will extend to the edge of the available plot area for the dimension you did not specify.

from bokeh.models import BoxAnnotation
from bokeh.plotting import figure, show
from bokeh.sampledata.glucose import data

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"

#reduce data size
data = data.loc['2010-10-06':'2010-10-13'].reset_index()

p = figure(x_axis_type="datetime", tools=TOOLS)

p.line("datetime", "glucose", source=data, color="gray", legend_label="glucose")

low_box = BoxAnnotation(top=80, fill_alpha=0.2, fill_color='#D55E00')
mid_box = BoxAnnotation(bottom=80, top=180, fill_alpha=0.2, fill_color='#0072B2')
high_box = BoxAnnotation(bottom=180, fill_alpha=0.2, fill_color='#D55E00')

p.add_layout(low_box)
p.add_layout(mid_box)
p.add_layout(high_box)

p.title.text = "Glucose Range"
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5
p.xaxis.axis_label = 'Time'
p.yaxis.axis_label = 'Value'
p.legend.level = "overlay"
p.legend.location = "top_left"

show(p)
Polygon annotations#

A PolyAnnotation is a polygon with vertices in either screen units or data units.

To define the polygon’s vertices, supply a series of coordinates to the xs and ys properties. Bokeh automatically connects the last vertex to the first to create a closed shape.

from datetime import datetime as dt

import pandas as pd

from bokeh.models import PolyAnnotation
from bokeh.plotting import figure, show
from bokeh.sampledata.stocks import GOOG

p = figure(height=200, x_axis_type="datetime",
           background_fill_color="#efefef", title="Google stock")

df = pd.DataFrame(GOOG)
df["date"] = pd.to_datetime(df["date"])

p.line(df["date"], df["close"], line_width=1.5, color="grey")

start_date = dt(2008, 11, 24)
start_y = df.loc[df["date"] == start_date]["close"].values[0]

end_date = dt(2010, 1, 4)
end_y = df.loc[df["date"] == end_date]["close"].values[0]

polygon = PolyAnnotation(
    fill_color="blue", fill_alpha=0.2,
    xs=[start_date, start_date, end_date, end_date],
    ys=[start_y - 100, start_y + 100, end_y + 100, end_y - 100],
)
p.add_layout(polygon)

show(p)
Labels#

Labels are rectangular boxes with additional information about glyphs or plot regions.

To create a single text label, use the Label annotation. Those are the most important properties for this annotation:

Label(x=100, y=5, x_units='screen', text='Some Stuff',
      border_line_color='black', border_line_alpha=1.0,
      background_fill_color='white', background_fill_alpha=1.0)

The text may value contain newline characters which will result in a multi-line label.

Label(x=100, y=5, text='A very long label\nwith multiple lines')

To create several labels at once, use the LabelSet annotation. To configure the labels of a label set, use a data source that contains columns with data for the labels’ properties such as text, x and y. If you assign a value to a property such as x_offset and y_offset directly instead of a column name, this value is used for all labels of the label set.

LabelSet(x='x', y='y', text='names',
         x_offset=5, y_offset=5, source=source)

The following example illustrates the use of Label and LabelSet:

from bokeh.models import ColumnDataSource, Label, Node
from bokeh.plotting import figure, show

source = ColumnDataSource(data=dict(
    height=[66, 71, 72, 68, 58, 62],
    weight=[165, 189, 220, 141, 260, 174],
    names=["Mark", "Amir", "Matt", "Greg", "Owen", "Juan"],
))

p = figure(title="Dist. of 10th Grade Students", x_range=(140, 275))
p.xaxis.axis_label = "Weight (lbs)"
p.yaxis.axis_label = "Height (in)"

p.scatter(x="weight", y="height", size=8, source=source)

p.text(x="weight", y="height", text="names",
       x_offset=5, y_offset=5, anchor="bottom_left", source=source)

frame_left = Node(target="frame", symbol="left", offset=5)
frame_bottom = Node(target="frame", symbol="bottom", offset=-5)

citation = Label(
    x=frame_left,
    y=frame_bottom,
    anchor="bottom_left",
    text="Collected by Luke C. 2016-04-01",
    padding=10,
    border_radius=5,
    border_line_color="black", background_fill_color="white",
)

p.add_layout(citation)

show(p)

The text values for LabelSet may value contain newline characters which will result in multi-line labels.

Slopes#

Slope annotations are lines that can go from one edge of the plot to another at a specific angle.

These are the most commonly used properties for this annotation:

import numpy as np

from bokeh.models import Slope
from bokeh.palettes import Sunset10
from bokeh.plotting import figure, show

# linear equation parameters
slope, intercept = 2, 10

x = np.arange(0, 20, 0.2)
y = slope * x + intercept + np.random.normal(0, 4, 100)

blue, yellow = Sunset10[0], Sunset10[5]

p = figure(width=600, height=600, x_axis_label='x', y_axis_label='y',
           background_fill_color="#fafafa")
p.y_range.start = 0

p.scatter(x, y, size=8, alpha=0.8, fill_color=yellow, line_color="black")

slope = Slope(gradient=slope, y_intercept=intercept,
              line_color=blue, line_dash='dashed', line_width=4)

p.add_layout(slope)

show(p)
Spans#

Span annotations are lines that are orthogonal to the x or y axis of a plot. They have a single dimension (width or height) and go from one edge of the plot area to the opposite edge.

These are the most commonly used properties for this annotation:

from datetime import datetime as dt

from bokeh.models import Span
from bokeh.plotting import figure, show
from bokeh.sampledata.daylight import daylight_warsaw_2013

p = figure(height=350, x_axis_type="datetime", y_axis_type="datetime",
           title="2013 Sunrise and Sunset in Warsaw with DST dates marked",
           y_axis_label="Time of Day", background_fill_color="#fafafa")
p.y_range.start = 0
p.y_range.end = 24 * 60 * 60 * 1000

p.line("Date", "Sunset", source=daylight_warsaw_2013,
       color='navy', line_dash="dotted", line_width=2, legend_label="Sunset")
p.line("Date", "Sunrise", source=daylight_warsaw_2013,
       color='orange', line_dash="dashed", line_width=2, legend_label="Sunrise")

dst_start = Span(location=dt(2013, 3, 31, 2, 0, 0), dimension='height',
                 line_color='#009E73', line_width=5)
p.add_layout(dst_start)

dst_end = Span(location=dt(2013, 10, 27, 3, 0, 0), dimension='height',
               line_color='#009E73', line_width=5)
p.add_layout(dst_end)

p.yaxis.formatter.context = None
p.xgrid.grid_line_color = None

show(p)
Whiskers#

A Whisker annotation is a “stem” that is dimensionally linked to the data in the plot. You can define this annotation using data units or screen units.

A common use for whisker annotations is to indicate error margins or uncertainty for measurements at a single point.

These are the most commonly used properties for this annotation:

from bokeh.models import ColumnDataSource, Whisker
from bokeh.plotting import figure, show
from bokeh.sampledata.autompg2 import autompg2 as df
from bokeh.transform import factor_cmap, jitter

classes = list(sorted(df["class"].unique()))

p = figure(height=400, x_range=classes, background_fill_color="#efefef",
           title="Car class vs HWY mpg with quantile ranges")
p.xgrid.grid_line_color = None

g = df.groupby("class")
upper = g.hwy.quantile(0.80)
lower = g.hwy.quantile(0.20)
source = ColumnDataSource(data=dict(base=classes, upper=upper, lower=lower))

error = Whisker(base="base", upper="upper", lower="lower", source=source,
                level="annotation", line_width=2)
error.upper_head.size=20
error.lower_head.size=20
p.add_layout(error)

p.scatter(jitter("class", 0.3, range=p.x_range), "hwy", source=df,
          alpha=0.5, size=13, line_color="white",
          color=factor_cmap("class", "Light7", classes))

show(p)

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4