Blog der Heimetli Software AG

Ein Diagramm mit Stacked Bars in Bokeh

Bokeh ist weniger bekannt als Plotly, macht aber einen guten Eindruck. Um mir einen besseren Eindruck zu verschaffen habe ich es mal ausprobiert.

Die Daten für diese Darstellung kommen von der Webseite des BAG. Dort finden Sie ZIPs mit allen möglichen Informationen zur COVID-Pandemie. Das verwendete File hat Angaben die bis zum letzten Dezember zurückreichen, und einige überflüssige Spalten. Deshalb sind einige Filterstufen nötig bis es als Grundlage für die Darstellung dienen kann.

Mit Bokeh kommt man recht schnell zu einem brauchbaren Diagramm, aber es braucht einige Optionen bis es so aussieht wie man es haben will. Da dies meine erste Erfahrung mit dem Tool war, musste ich recht lange in der Dokumentation und bei StackOverflow herumsuchen. Mit etwas Uebung kriegt man das sicher schneller hin, denn die Library ist recht logisch aufgebaut.

Per Default erzeugt Bokeh eine HTML-Seite mit dem Plot. Wenn man die richtigen Optionen setzt bekommt man sogar eine responsive Darstellung.

Wie Sie hier sehen können, ist es aber auch möglich eine Darstellung zu erzeugen die Sie in Ihre Webseite einbetten können. Das folgende Script erzeugt ein JSON-File das auf dem Server abgelegt ist. Von dort wird es geladen und an bokeh.js weitergegeben. Die Bokeh-Library erstellt das Diagramm aus diesem JSON-File.

Das Python-Script

import pandas as pd
import json

from bokeh.plotting import figure
from bokeh.models import NumeralTickFormatter, Legend, LegendItem
from bokeh.embed import json_item

# Read the CSV
df = pd.read_csv( "COVID19VaccPersons.csv" )

# Delete rows which are not used
df = df[df["date"] == "2021-06-16"]
df = df[df["type"] != "COVID19AtLeastOneDosePersons"]
df = df[df["geoRegion"] != "CH"]
df = df[df["geoRegion"] != "FL"]
df = df[df["geoRegion"] != "CHFL"]

# Add a column with percentages
df["percent"] = df["sumTotal"] / df["pop"]

# Delete superfluous columns
df = df[["geoRegion","type","percent"]]

# Transform the data frame
df = df.pivot( index="geoRegion", columns="type", values="percent" )
df.reset_index( inplace=True )

# Set the column titles
df.columns = ["Kanton","Vollständig geimpft","Einmal geimpft"]

# Sort the data frame
df.sort_values( "Vollständig geimpft", ascending=False, inplace=True )

# Define the colors for the bars
colors = ["#004586","#FF420E"]

# Start the plot
plot = figure( x_range=df["Kanton"], plot_height=250,
               title="COVID-Impfungen, Stand 16. Juni 2021",
               toolbar_location=None, tools="hover",
               tooltips="$name @$name{0%}" )


# Draw the bars
plot.vbar_stack( ["Vollständig geimpft","Einmal geimpft"],
                 x="Kanton", width=0.7, color=colors,
                 source=df, legend_label=["Vollständig geimpft","Einmal geimpft"] )

# Set the options for axes, number format, ticks, ...
plot.y_range.start = 0
plot.y_range.end = 0.6000001
plot.yaxis.formatter=NumeralTickFormatter(format="0%")
plot.axis.minor_tick_line_color = None
plot.xaxis.major_tick_line_color = None
plot.xgrid.grid_line_color = None
plot.sizing_mode = "scale_width"
plot.title.text_font_size = "2em"
plot.axis.major_label_text_font_size = "0.9em"
plot.legend.orientation = "horizontal"
plot.legend.background_fill_alpha = 0.5

# Print the plot in JSON format
print( json.dumps(json_item(plot,"plot")) )

Per Redirect wurde die Ausgabe des Programms in covid.json abgelegt. Dieses File wird unverändert wieder geladen und der Library übergeben.