Datenquellen und Transformationen#

Überblick#

Bokeh kann mit Python-Listen, NumPy-Arrays, pandas-Serien usw. arbeiten. Dabei werden diese Eingaben in eine Bokeh ColumnDataSource konvertiert. Obwohl Bokeh dies oft transparent macht, kann es gelegentlich sinnvoll sein, sie explizit zu erstellen.

[1]:
from bokeh.io import output_notebook, show
from bokeh.plotting import figure


output_notebook()
Loading BokehJS ...

Python Dicts#

Die ColumnDataSource kann aus bokeh.models importiert werden:

[2]:
from bokeh.models import ColumnDataSource

ColumnDataSource ist eine Zuordnung von Spaltennamen zu Wertsequenzen. Dabei müssen alle Spalten immer die gleiche Länge haben:

[3]:
source = ColumnDataSource(
    data={
        "x": [1, 2, 3, 4, 5],
        "y": [3, 7, 8, 5, 1],
    }
)

Bisher haben wir Funktionen wie p.circle aufgerufen, indem wir direkt Listen oder Datenarrays übergeben haben. Dann erstellt Bokeh automatisch eine ColumnDataSource für uns. Es ist jedoch auch möglich, eine ColumnDataSource explizit anzugeben, indem als Quellargument eine Glyph-Methode übergeben wird:

[4]:
p = figure(width=400, height=400)
p.circle("x", "y", size=20, source=source)
show(p)

pandas.DataFrame#

Es ist auch einfach, ColumnDataSource-Objekte direkt aus pandas-DataFrames zu erstellen:

[5]:
from bokeh.sampledata.iris import flowers as df


source = ColumnDataSource(df)
p = figure(width=400, height=400)
p.circle("petal_length", "petal_width", source=source)
show(p)

Transformationen#

Wenn Datenquellen nicht gemeinsam genutzt werden müssen, können Dicts, pandas.DataFrame- oder GroupBy-Objekte direkt an die Glyph-Methode übergeben werden ohne explizit eine ColumnDataSource zu erstellen. In diesem Fall erfolgt die Konvertierung automatisch.

Glyph-Eigenschaften können nicht nur mit Namen von Spalten aus Datenquellen konfiguriert werden, sondern auch mit Transformationsobjekten aus bokeh.transform. Dabei ist wichtig zu beachten, dass bei der Verwendung dieser Objekte die Transformationen im Browser und nicht in Python erfolgen.

cumsum#

Im Folgenden betrachten wir zunächst eine cumsum-Transformation, die aus einer Spalte eine neue Folge von Werten erzeugen kann indem die Werte kumulativ summiert werden. Dies kann für Kreisdiagramme oder Doughnut-Diagramme nützlich sein:

[6]:
from math import pi

import pandas as pd

from bokeh.palettes import Category20c
from bokeh.transform import cumsum


x = {
    "United States": 157,
    "United Kingdom": 93,
    "Japan": 89,
    "China": 63,
    "Germany": 44,
    "India": 42,
    "Italy": 40,
    "Australia": 35,
    "Brazil": 32,
    "France": 31,
    "Taiwan": 31,
    "Spain": 29,
}

data = (
    pd.Series(x).reset_index(name="value").rename(columns={"index": "country"})
)
data["color"] = Category20c[len(x)]

# represent each value as an angle = value / total * 2pi
data["angle"] = data["value"] / data["value"].sum() * 2 * pi

p = figure(
    height=350,
    title="Pie Chart",
    toolbar_location=None,
    tools="hover",
    tooltips="@country: @value",
)

p.wedge(
    x=0,
    y=1,
    radius=0.4,
    # use cumsum to cumulatively sum the values for start and end angles
    start_angle=cumsum("angle", include_zero=True),
    end_angle=cumsum("angle"),
    line_color="white",
    fill_color="color",
    legend_label="country",
    source=data,
)

p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

show(p)

linear_cmap#

Mit der linear_cmap-Transformation kann eine lineare Farbzuordnung zur Spalte einer Datenquelle eine neue Farbsequenz erzeugen:

[7]:
import numpy as np

from bokeh.transform import linear_cmap


N = 4000
data = dict(
    x=np.random.random(size=N) * 100,
    y=np.random.random(size=N) * 100,
    r=np.random.random(size=N) * 1.5,
)

p = figure()

p.circle(
    "x",
    "y",
    radius="r",
    source=data,
    fill_alpha=0.6,
    # color map based on the x-coordinate
    color=linear_cmap("x", "Viridis256", 0, 100),
)

show(p)