Annotations#
Überblick#
Wir können visuelle Hinweise (Begrenzungslinien, schattierte Bereiche, Beschriftungen und Pfeile usw.) zu unseren Plots hinzufügen, um bestimmte Merkmale hervorzuheben. Bokeh bietet hierfür mehrere Annotationstypen. Um Annotations hinzuzufügen, erstellen wir normalerweise ein Low-Level-Objekt und fügen es mit add_layout
unserem Diagramm hinzu. Schauen wir uns einige konkrete Beispiele an:
Spans#
Spans sind vertikale oder horizontale Linien, für die die Spannweiten zwischen den Bemaßung angegeben werden kann, z.B.:
[1]:
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
output_notebook()
[2]:
import numpy as np
from bokeh.models.annotations import Span
x = np.linspace(0, 20, 200)
y = np.sin(x)
p = figure(y_range=(-2, 2))
p.line(x, y)
upper = Span(location=1, dimension='width', line_color='olive', line_width=4)
p.add_layout(upper)
lower = Span(location=-1, dimension='width', line_color='firebrick', line_width=4)
p.add_layout(lower)
show(p)
Box Annotations#
Soll ein Bereich eines Diagramms hervorgehoben werden, so können diese mit BoxAnnotation
, den Koordinateneigenschaften
top
left
bottom
right
sowie Linien- und Fülleigenschaften das Erscheinungsbild konfiguriert werden.
Infinite Boxen können erstellt werden, indem die Koordinaten nicht angegeben werden. Wenn zum Beispiel top
nicht angegeben ist, wird die Box immer bis zum oberen Rand des Plotbereichs angezeigt, unabhängig davon, ob ein Verschieben oder Zoomen stattfindet, z.B.:
[3]:
import numpy as np
from bokeh.models.annotations import BoxAnnotation
x = np.linspace(0, 20, 200)
y = np.sin(x)
p = figure(y_range=(-2, 2))
p.line(x, y)
# region that always fills the top of the plot
upper = BoxAnnotation(bottom=1, fill_alpha=0.1, fill_color='olive')
p.add_layout(upper)
# region that always fills the bottom of the plot
lower = BoxAnnotation(top=-1, fill_alpha=0.1, fill_color='firebrick')
p.add_layout(lower)
# a finite region
center = BoxAnnotation(top=0.6, bottom=-0.3, left=7, right=12, fill_alpha=0.1, fill_color='navy')
p.add_layout(center)
show(p)
Label#
Mit der Annotation Label
können wir einzelne Beschriftungen einfach an Plots anbringen. Die anzuzeigende Position und der Text sind als x
, y
und text
konfiguriert:
Label(x=10, y=5, text="Some Label")
Standardmäßig befinden sich die Einheiten im data space, aber x_units
und y_units
können auf screen
gesetzt werden, um die Beschriftung relativ zur Zeichenfläche zu positionieren, und Labels können mit
x_offsetund
y_offset` positioniert werden.
Label
-Objekte haben auch Standardtext-, Zeilen- (border_line
) und Fülleigenschaften (background_fill
). Die Linien- und Fülleigenschaften gelten für einen Begrenzungsrahmen um den Text:
Label(x=10, y=5, text="Some Label", text_font_size="12pt",
border_line_color="red", background_fill_color="blue")
[4]:
from bokeh.models.annotations import Label
from bokeh.plotting import figure
p = figure(x_range=(0,10), y_range=(0,10))
p.circle([2, 5, 8], [4, 7, 6], color="olive", size=10)
label = Label(x=5, y=7, x_offset=12, text="Second Point", text_baseline="middle")
p.add_layout(label)
show(p)
LabelSet#
Mit der Annotation LabelSet
könnt ihr viele Beschriftungen gleichzeitig erstellen, z.B. wenn ihr einen ganzen Satz von Scatter Markers beschriften möchtet. Sie ähneln Label
, können aber auch eine ColumnDataSource
als source
-Eigenschaft nutzen, wobei sich x
und y
auf Spalten in der Datenquelle beziehen.
[5]:
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, LabelSet
source = ColumnDataSource(data=dict(
temp=[166, 171, 172, 168, 174, 162],
pressure=[165, 189, 220, 141, 260, 174],
names=['A', 'B', 'C', 'D', 'E', 'F']))
p = figure(x_range=(160, 175))
p.scatter(x='temp', y='pressure', size=8, source=source)
p.xaxis.axis_label = 'Temperature (C)'
p.yaxis.axis_label = 'Pressure (lbs)'
labels = LabelSet(x='temp', y='pressure', text='names', level='glyph',
x_offset=5, y_offset=5, source=source, render_mode='canvas')
p.add_layout(labels)
show(p)
Arrows#
Mit der Annotation Arrow
könnt ihr auf verschiedene Elemente in eurer Zeichnung *zeigen+. Dies kann besonders bei Beschriftungen hilfreich sein.
So könnt ihr beispielsweise einen Pfeil erstellen, der von (0,0)
bis (1,1)
zeigt:
p.add_layout(Arrow(x_start=0, y_start=0, x_end=1, y_end=0))
Dieser Pfeil hat die Standardspitze OpenHead. Andere Arten von Pfeilspitzen sind NormalHead und VeeHead. Der Typ des Pfeilkopfs kann durch die Eigenschaften
start
and end
von Arrow
-Objekten konfiguriert werden:
p.add_layout(Arrow(start=OpenHead(), end=VeeHead(),
x_start=0, y_start=0, x_end=1, y_end=0))
Dies erzeugt einen Doppelpfeil mit OpenHead
und VeeHead
. Pfeilspitzen haben darüberhinaus den Standardsatz von Linien- und Fülleigenschaften, um deren Aussehen zu konfigurieren, z.B.:
OpenHead(line_color="firebrick", line_width=4)
Der Code und das Diagramm unten zeigen mehrere dieser Konfigurationen zusammen.
[6]:
from bokeh.models.annotations import Arrow
from bokeh.models.arrow_heads import OpenHead, NormalHead, VeeHead
p = figure(plot_width=600, plot_height=600)
p.circle(x=[0, 1, 0.5], y=[0, 0, 0.7], radius=0.1,
color=["navy", "yellow", "red"], fill_alpha=0.1)
p.add_layout(Arrow(end=OpenHead(line_color="firebrick", line_width=4),
x_start=0, y_start=0, x_end=1, y_end=0))
p.add_layout(Arrow(end=NormalHead(fill_color="orange"),
x_start=1, y_start=0, x_end=0.5, y_end=0.7))
p.add_layout(Arrow(end=VeeHead(size=35), line_color="red",
x_start=0.5, y_start=0.7, x_end=0, y_end=0))
show(p)
Legenden#
Wenn Diagramme mehrere Glyphen enthalten, ist es wünschenswert, eine Legende hinzuzufügen, um Betrachtern die Interpretation zu erleichtern. Bokeh kann Legenden anhand der hinzugefügten Glyphen leicht generieren.
Einfache Legenden#
Im einfachsten Fall könnt ihr einen String als legend
an eine Glyph-Funktion übergeben:
p.circle(x, y, legend="sin(x)")
In diesem Fall erstellt Bokeh automatisch eine Legende, die eine Darstellung dieser Glyphe zeigt.
[7]:
import numpy as np
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure(height=400)
p.circle(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)
show(p)
Zusammengesetzte Legenden#
Im obigen Beispiel haben wir für jede Glyphenmethode ein anderes Etikett bereitgestellt. Manchmal werden zwei (oder mehr) verschiedene Glyphen mit einer einzigen Datenquelle verwendet. In diesem Fall können zusammengesetzte Legenden erstellt werden. Wenn ihr z.B. eine Sin-Kurve mit einer Linie und einer Markierung plottet, könnt ihr ihnen dieselbe Bezeichnung geben um sie dazu zu bringen, gemeinsam in der Legende zu erscheinen:
p.circle(x, y, legend="sin(x)")
p.line(x, y, legend="sin(x)", line_dash=[4, 4], line_color="orange", line_width=2)
Farbbalken#
Farbbalken sind besonders nützlich, wenn wir die Farbe einer Glyphe entsprechend der Farbzuordnung variiert. Bokeh-Farbbalken werden mit einer Farbzuordnung konfiguriert und mit der `add_layout‘-Methode zu Plots hinzugefügt:
color_mapper = LinearColorMapper(palette="Viridis256", low=data_low, high=data_high)
color_bar = ColorBar(color_mapper=color_mapper, location=(0,0))
p.add_layout(color_bar, 'right')
Das folgende Beispiel zeigt ein vollständiges Beispiel, in dem auch die Farbzuordnung zur Umwandlung der Glyphenfarbe verwendet wird.
[8]:
from bokeh.sampledata.autompg import autompg
from bokeh.models import LinearColorMapper, ColorBar
from bokeh.transform import transform
source = ColumnDataSource(autompg)
color_mapper = LinearColorMapper(palette="Viridis256", low=autompg.weight.min(), high=autompg.weight.max())
p = figure(x_axis_label='Horsepower', y_axis_label='MPG', tools='', toolbar_location=None)
p.circle(x='hp', y='mpg', color=transform('weight', color_mapper), size=20, alpha=0.6, source=autompg)
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=12, location=(0,0), title='Weight')
p.add_layout(color_bar, 'right')
show(p)