Hlavní navigace

Knihovna Bokeh: dokončení seriálu o vykreslování grafů

14. 7. 2022
Doba čtení: 35 minut

Sdílet

Ilustrační snímek Autor: Depositphotos
Ve třetím a současně i posledním článku o knihovně Bokeh si ukážeme použití témat, vykreslení dat reprezentovaných jako matice nebo rastrové obrázky i kooperaci mezi částí psanou v Pythonu a částí psanou v JavaScriptu.

Obsah

1. Knihovna Bokeh: dokončení

2. Témata ovlivňující barvy i styl vykreslení grafů

3. Ukázky podporovaných témat stylů grafů

4. Graf obsahující data ve formě rastrového obrázku

5. Rastrová data s proměnným počtem sloupců a řádků

6. Textura – moiré

7. Použití externí barvové palety (LUT)

8. Rastrové obrázky a interní barvové palety Bokehu

9. Zobrazení obrázku s interní barvovou paletou Bokehu

10. Popisky na x-ové ose sloupcového grafu

11. Seřazení hodnot podle zadaného kritéria

12. Použití struktury ColumnDataSource

13. Zvýraznění hodnot ve sloupcovém grafu s využitím různých barev sloupců

14. Interaktivní přepočet grafů

15. Přidání posuvníku pro interaktivní změnu amplitudy jednoho průběhu v grafu

16. Data pro vykreslení grafu dostupná ve formě ColumnDataSource

17. Temná strana Bokehu – přepočet dat v JavaScriptu

18. Závěrečné shrnutí

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Knihovna Bokeh: dokončení

Ve třetím a současně i posledním článku o knihovně Bokeh, který navazuje na články [1] a [2] si ukážeme způsob výběru a použití témat (ovlivňujících barvy, fonty apod. zobrazených grafů), vykreslení dat reprezentovaných formou matic (N-dimenzionální pole knihovny NumPy) nebo formou rastrových obrázků, seřazení hodnot podle zvolených kritérií i kooperaci mezi částí psanou v Pythonu a částí naprogramovanou v JavaScriptu. Na závěr si řekneme, kde je vhodné Bokeh použít a v jakých oblastech naopak tato knihovna neposkytuje požadovanou funkcionalitu a je lepší ji nahradit odlišnou technologií (Jupyter Notebook, Plotly atd.).

2. Témata ovlivňující barvy i styl vykreslení grafů

Všechny grafy, které jsme si až doposud ukazovali, byly zobrazeny s využitím standardního tématu, které ovlivňuje především barvy použité nejenom v samotném grafu, ale i všemi dalšími ovládacími prvky. Kromě toho téma ovlivňuje i použité fonty – a teoreticky všechny vizuální atributy, které lze nastavit přes kaskádní styly (CSS). Bokeh kromě standardního tématu obsahuje i několik témat dalších. Samotný výběr tématu je až triviálně jednoduchý. Nejdříve je nutné naimportovat další dva balíčky:

from bokeh.themes import built_in_themes
from bokeh.io import curdoc

Zvolené téma (resp. jeho jméno – řetězec) se následně pouze uloží do atributu pojmenovaného theme objektu, jenž je získán zavoláním tovární metody curdoc() (current document):

# nastavení tématu
curdoc().theme = 'caliber'
Poznámka: nastavení tématu lze teoreticky provést kdykoli, ovšem nejlepší je provést tuto velmi důležitou volbu před zavoláním metody show, protože chování nových verzí knihovny Bokeh může být odlišné.

3. Ukázky podporovaných témata stylů grafů

Pojďme si nyní ukázat, jak budou po vizuální stránce vypadat grafy, které sice zobrazují stejná data, ovšem pokaždé s využitím odlišného tématu. Začneme tématem nazvaným „caliber“:

Obrázek 1: Graf zobrazený s využitím tématu „caliber“.

Úplný zdrojový kód dnešního prvního demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_caliber.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, show
from bokeh.themes import built_in_themes
from bokeh.io import curdoc
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# nastavení tématu
curdoc().theme = 'caliber'
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#0aa")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#aa0")
 
# vykreslení grafu do plochy webové stránky
show(p)

Další dostupné téma se jmenuje „dark_minimal“:

Obrázek 2: Graf zobrazený s využitím tématu „dark_minimal“.

Úplný zdrojový kód dnešního druhého demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_dark_minimal.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, show
from bokeh.themes import built_in_themes
from bokeh.io import curdoc
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# nastavení tématu
curdoc().theme = 'dark_minimal'
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#0aa")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#aa0")
 
# vykreslení grafu do plochy webové stránky
show(p)

Třetí téma, které si ukážeme, se jmenuje „light_minimal“:

Obrázek 3: Graf zobrazený s využitím tématu „light_minimal“.

Úplný zdrojový kód dnešního třetího demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_light_minimal.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, show
from bokeh.themes import built_in_themes
from bokeh.io import curdoc
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# nastavení tématu
curdoc().theme = 'light_minimal'
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#0aa")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#aa0")
 
# vykreslení grafu do plochy webové stránky
show(p)

A konečně čtvrté dostupné téma nese název „night_sky“:

Obrázek 4: Graf zobrazený s využitím tématu „night_sky“.

Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_night_sky.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, show
from bokeh.themes import built_in_themes
from bokeh.io import curdoc
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# nastavení tématu
curdoc().theme = 'night_sky'
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#0aa")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#aa0")
 
# vykreslení grafu do plochy webové stránky
show(p)

4. Graf obsahující data ve formě rastrového obrázku

Knihovna Bokeh dokáže v případě potřeby vizualizovat i data dostupná ve formě 2D matice popř. ve formě rastrového obrázku, který je možné interaktivně zvětšovat, zmenšovat a posouvat, stejně jako jakýkoli jiný typ grafu. Podívejme se nyní na způsob reprezentace takového obrázku i na postup pro jeho vykreslení.

Poznámka: budeme do značné míry využívat schopností knihovny NumPy, která je ostatně pro manipulaci s podobně strukturovanými daty (vektory, matice, vícerozměrná pole) navržena.

V prvním kroku si připravíme dvourozměrnou (prázdnou) matici o rozměrech IMAGE_HEIGHT×IMAGE_WIDTH, tedy matici s IMAGE_HEIGHT řádky a IMAGE_WIDTH sloupci (IMAGE_WIDTH a IMAGE_HEIGHT jsou pochopitelně celá kladná čísla). Povšimněte si, že typ prvků je nastaven na uint32, protože každá hodnota bude reprezentována 32bitovým celým číslem bez znaménka (používáme NumPy, kde se s datovými typy pracuje podobně jako v C a Fortranu):

image = np.empty((IMAGE_HEIGHT, IMAGE_WIDTH), dtype=np.uint32)

Následně si vytvoříme pohled (view) na tuto matici. Tento pohled bude matici zvnějšku reprezentovat jako trojrozměrné pole IMAGE_HEIGHT×IMAGE_WIDTH×4 bajtů (typ uint8). Důvod je jednoduchý – každý pixel původní matice je logicky rozložen na tři barvové složky + hodnoty průhlednosti:

view = image.view(dtype=np.uint8).reshape((IMAGE_HEIGHT, IMAGE_WIDTH, 4))

Matici naplníme vhodnými daty, například kombinovaným gradientním přechodem černá-červená v horizontálním směru a černá-modrá ve směru vertikálním. Zelená složka je nastavena na nulu a průhlednost na zcela neprůhlednou barvu:

for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        view[j, i, 0] = int(255 * j / IMAGE_HEIGHT) # red
        view[j, i, 1] = 0                           # green
        view[j, i, 2] = int(255 * i / IMAGE_WIDTH)  # blue
        view[j, i, 3] = 255                         # alpha

Nyní již postačuje obsah matice vykreslit ve formě rastrového obrázku. Povšimněte si, že rozměry obrázku v ploše prohlížeče mohou být odlišné od původního (nativního) rozlišení. Zde konkrétně použijeme desetinásobné zvětšení v obou osách:

# plocha pro graf
p = figure(width=IMAGE_WIDTH*10, height=IMAGE_HEIGHT*10, x_range=(0, 10), y_range=(0, 10))
 
# vykreslení rastrového obrázku typu RGBA
p.image_rgba(image=[image], x=[0], y=[0], dw=[10], dh=[10])
 
# vykreslení grafu do plochy webové stránky
show(p)

Výsledek bude vypadat následovně:

Obrázek 5: Rastrový obrázek zobrazený knihovnou Bokeh v ploše prohlížeče.

Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster1.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
 
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# velikost rastrového obrázku
IMAGE_WIDTH = 32
IMAGE_HEIGHT = 32
 
# matice představující bázi rastrového obrázku
image = np.empty((IMAGE_HEIGHT, IMAGE_WIDTH), dtype=np.uint32)
 
# "pohled" na matici jako na trojrozměrné pole
view = image.view(dtype=np.uint8).reshape((IMAGE_HEIGHT, IMAGE_WIDTH, 4))
 
# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        view[j, i, 0] = int(255 * j / IMAGE_HEIGHT) # red
        view[j, i, 1] = 0                           # green
        view[j, i, 2] = int(255 * i / IMAGE_WIDTH)  # blue
        view[j, i, 3] = 255                         # alpha
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH*10, height=IMAGE_HEIGHT*10, x_range=(0, 10), y_range=(0, 10))
 
# vykreslení rastrového obrázku typu RGBA
p.image_rgba(image=[image], x=[0], y=[0], dw=[10], dh=[10])
 
# vykreslení grafu do plochy webové stránky
show(p)

5. Rastrová data s proměnným počtem sloupců a řádků

V předchozím příkladu byl rastrový obrázek čtvercový, konkrétně měl rozměry 32×32 pixelů:

# velikost rastrového obrázku
IMAGE_WIDTH = 32
IMAGE_HEIGHT = 32

Nic nám však nebrání v používání obrázků, v nichž je horizontální a vertikální rozlišení odlišné, tj. kde počet sloupců neodpovídá počtu řádků:

# velikost rastrového obrázku
IMAGE_WIDTH = 16
IMAGE_HEIGHT = 10

Při vykreslení jednotlivé pixely zvětšíme 30×:

# plocha pro graf
p = figure(width=IMAGE_WIDTH*30, height=IMAGE_HEIGHT*30, x_range=(0, 10), y_range=(0, 10))

S následujícím výsledkem:

Obrázek 6: Rastrová data v původním rozlišení 16×10 pixelů.

Úplný zdrojový kód tohoto pozměněného demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster2.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# velikost rastrového obrázku
IMAGE_WIDTH = 16
IMAGE_HEIGHT = 10
 
# matice představující bázi rastrového obrázku
image = np.empty((IMAGE_HEIGHT, IMAGE_WIDTH), dtype=np.uint32)
 
# "pohled" na matici jako na trojrozměrné pole
view = image.view(dtype=np.uint8).reshape((IMAGE_HEIGHT, IMAGE_WIDTH, 4))
 
# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        view[j, i, 0] = int(255 * j / IMAGE_HEIGHT) # red
        view[j, i, 1] = 0                           # green
        view[j, i, 2] = int(255 * i / IMAGE_WIDTH)  # blue
        view[j, i, 3] = 255                         # alpha
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH*30, height=IMAGE_HEIGHT*30, x_range=(0, 10), y_range=(0, 10))
 
# vykreslení rastrového obrázku typu RGBA
p.image_rgba(image=[image], x=[0], y=[0], dw=[10], dh=[10])
 
# vykreslení grafu do plochy webové stránky
show(p)

6. Textura – moiré

Můžeme se pokusit i o programové vytvoření složitějších vzorků (textury). Bude se konkrétně jednat o procedurální texturu založenou na efektu takzvaného moaré. Tuto procedurální texturu (či možná lépe řečeno rastrový vzorek) vytvořil John Connett z Minnesotské univerzity. O tomto vzorku, který v podstatě názorně ukazuje vliv aliasu při tvorbě rastrových obrázků, později pojednal i A. K. Dewdney v časopise Scientific American. Popisovaný vzorek je generovaný velmi jednoduchým a taktéž dostatečně rychlým způsobem: každému pixelu ve vytvářeném rastrovém obrázku (bitmapě) je přiřazena dvojice souřadnic [x, y]. Tyto souřadnice obecně neodpovídají celočíselným indexům pixelu, které můžeme například označit [i, j] (záleží totiž na zvoleném faktoru zvětšení popř. zmenšení vzorku). Posléze je pro každý pixel vypočtena hodnota k na základě jednoduchého vztahu k=i2+j2. Důležité je, že tato hodnota (typicky) přeteče přes 255, takže výsledkem je zajímavý vzorek.

Implementace výpočtu i s přetečením

# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        k = i*i + j*j
        val = int(k) & 255
        view[i, j, 0] = val  # red
        view[i, j, 1] = val  # green
        view[i, j, 2] = val  # blue
        view[i, j, 3] = 255  # alpha

Výsledek může po zobrazení v ploše prohlížeče vypadat takto:

Obrázek 7: Kruhové moaré vytvořené předchozím algoritmem.

Teprve po zvětšení se ukáže, jakým způsobem je vlastně vzorek vytvořen:

Obrázek 8: Zvětšená část předchozího obrázku.

Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster3.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# textura by měla být čtvercová a její šířka i výška by měla být
# mocninou čísla 2
IMAGE_WIDTH = 512
IMAGE_HEIGHT = 512
 
# matice představující bázi rastrového obrázku
image = np.empty((IMAGE_HEIGHT, IMAGE_WIDTH), dtype=np.uint32)
 
# "pohled" na matici jako na trojrozměrné pole
view = image.view(dtype=np.uint8).reshape((IMAGE_HEIGHT, IMAGE_WIDTH, 4))
 
# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        k = i*i + j*j
        val = int(k) & 255
        view[i, j, 0] = val  # red
        view[i, j, 1] = val  # green
        view[i, j, 2] = val  # blue
        view[i, j, 3] = 255  # alpha
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH, height=IMAGE_HEIGHT, x_range=(0, 10), y_range=(0, 10))
 
# vykreslení rastrového obrázku typu RGBA
p.image_rgba(image=[image], x=[0], y=[0], dw=[10], dh=[10])
 
# vykreslení grafu do plochy webové stránky
show(p)

7. Použití externí barvové palety (LUT)

K výše popsanému algoritmu ještě přidáme část, která na základě vypočtené hodnoty k vybere vhodnou barvu z barvové palety a pixel následně touto barvou vyplní. Tímto přímočarým, rychlým a současně i jednoduchým způsobem je možné vytvářet mnohdy fantastické vzorky; pouze stačí měnit barvovou paletu (ideální jsou plynulé přechody mezi barvami – gradient) a měřítko, pomocí kterého se převádí celočíselné pozice pixelů v rastru [i, j] na souřadnice [x, y].

Obrázek 9: Moaré s kružnicovým vzorkem.

Poznámka: LUT je zkratka vzniklá ze sousloví „LookUp Table“.

Obrázek 10: Mez zvětšení, při kterém již kružnicový vzorek začíná mizet.

Přidání barvové palety:

# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        k = i*i + j*j
        val = int(k) & 255
        # aplikace barvové palety
        view[i, j, 0] = palette[val][0]  # red
        view[i, j, 1] = palette[val][1]  # green
        view[i, j, 2] = palette[val][2]  # blue
        view[i, j, 3] = 255              # alpha

Přičemž barvová paleta je reprezentována polem s 256 trojicemi:

palette = (
    (000, 000, 0),
    (000, 000, 0),
    (000, 000, 8),
    (000, 000, 16),
    (000, 000, 24),
    ...
    ...
    ...
)

Výsledek bude po zobrazení knihovnou Bokeh vypadat následovně:

Obrázek 11: Moaré s aplikací barev z palety (LUTu).

Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster4.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# barvová paleta
import palette_ice
 
# textura by měla být čtvercová a její šířka i výška by měla být
# mocninou čísla 2
IMAGE_WIDTH = 512
IMAGE_HEIGHT = 512
 
# matice představující bázi rastrového obrázku
image = np.empty((IMAGE_HEIGHT, IMAGE_WIDTH), dtype=np.uint32)
 
# "pohled" na matici jako na trojrozměrné pole
view = image.view(dtype=np.uint8).reshape((IMAGE_HEIGHT, IMAGE_WIDTH, 4))
 
# výběr barvové palety
palette = palette_ice.palette
 
# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        k = i*i + j*j
        val = int(k) & 255
        # aplikace barvové palety
        view[i, j, 0] = palette[val][0]  # red
        view[i, j, 1] = palette[val][1]  # green
        view[i, j, 2] = palette[val][2]  # blue
        view[i, j, 3] = 255              # alpha
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH, height=IMAGE_HEIGHT, x_range=(0, 10), y_range=(0, 10))
 
# vykreslení rastrového obrázku typu RGBA
p.image_rgba(image=[image], x=[0], y=[0], dw=[10], dh=[10])
 
# vykreslení grafu do plochy webové stránky
show(p)

8. Rastrové obrázky a interní barvové palety Bokehu

Ve skutečnosti nemusíme ve všech případech používat vlastní barvové palety, protože knihovna Bokeh nám nabízí již předpřipravené palety, které jsou popsány na stránce https://docs.bokeh.org/en/la­test/docs/reference/palet­tes.html. Podívejme se nyní na způsob použití těchto palet. Postupovat budeme odlišným způsobem, protože nebudeme rastrový obrázek vyplňovat s využitím dvou vnořených programových smyček. Namísto toho využijeme dvojici velmi užitečných funkcí knihovny NumPy – jedná se o funkce linspace a meshgrid. Vhodnou kombinací těchto funkcí můžeme vytvořit „mřížku souřadnic“, s nimiž dokáže knihovna NumPy velmi dobře pracovat.

Nejprve si necháme vygenerovat dva vektory, z nichž každý obsahuje souřadnice mřížky na x-ové resp. na y-ové ose:

# souřadnice mřížky na x-ové a y-ové ose
x = np.linspace(-300, 300, IMAGE_WIDTH)
y = np.linspace(-300, 300, IMAGE_HEIGHT)

Na základě těchto dvou vektorů si necháme vygenerovat matice se všemi kombinacemi souřadnic:

# matice s x-ovými a y-ovými souřadnicemi tvořícími mřížku
xx, yy = np.meshgrid(x, y)

Podívejme se, jaké výsledky získáme pro vektory s pouhými čtyřmi resp. pěti prvky:

>>> import numpy as np
 
>>> x = np.linspace(1, 5, 5)
>>> x
array([1., 2., 3., 4., 5.])
 
>>> y = np.linspace(1, 6, 6)
>>> y
array([1., 2., 3., 4., 5., 6.])
 
>>> xx, yy = np.meshgrid(x, y)
>>> xx
array([[1., 2., 3., 4., 5.],
       [1., 2., 3., 4., 5.],
       [1., 2., 3., 4., 5.],
       [1., 2., 3., 4., 5.],
       [1., 2., 3., 4., 5.],
       [1., 2., 3., 4., 5.]])
 
>>> yy
array([[1., 1., 1., 1., 1.],
       [2., 2., 2., 2., 2.],
       [3., 3., 3., 3., 3.],
       [4., 4., 4., 4., 4.],
       [5., 5., 5., 5., 5.],
       [6., 6., 6., 6., 6.]])

Vidíme, že korespondující prvky matic skutečně tvoří dvojice souřadnic určujících jeden průsečík mřížky. A právě s těmito dvojici hodnot můžeme provádět různé operace:

>>> xx*yy
array([[ 1.,  2.,  3.,  4.,  5.],
       [ 2.,  4.,  6.,  8., 10.],
       [ 3.,  6.,  9., 12., 15.],
       [ 4.,  8., 12., 16., 20.],
       [ 5., 10., 15., 20., 25.],
       [ 6., 12., 18., 24., 30.]])

9. Zobrazení obrázku s interní barvovou paletou Bokehu

Ve chvíli, kdy máme k dispozici dvojici matic s x-ovými a y-ovými souřadnicemi mřížky, můžeme výpočet textury založený na použití programových smyček:

# vyplnění obrázku vzorkem
for j in range(IMAGE_HEIGHT):
    for i in range(IMAGE_WIDTH):
        k = i*i + j*j
        val = int(k) & 255
        view[i, j, 0] = val  # red
        view[i, j, 1] = val  # green
        view[i, j, 2] = val  # blue
        view[i, j, 3] = 255  # alpha

Nahradit za maticové operace (součin prvek po prvku, součet matic, převod hodnot na zvolený datový typ, výpočet zbytku po dělení pro všechny prvky matice):

# výpočet vzorku, který se má zobrazit
d = np.mod((xx*xx + yy*yy).astype(int), 255)

Následně již „pouze“ výslednou matici d zobrazíme metodou image (nikoli image_rgba) se specifikací barvové palety, kterou nám knihovna Bokeh nabízí:

# plocha pro graf
p = figure(width=IMAGE_WIDTH, height=IMAGE_HEIGHT)
 
# vykreslení rastrového obrázku do grafu
p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", level="image")

Výsledek by měl vypadat následovně:

Obrázek 12: Hodnoty z matice vykreslené metodou image s využitím zvolené barvové palety.

Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster5.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
 
# textura by měla být čtvercová a její šířka i výška by měla být
# mocninou čísla 2
IMAGE_WIDTH = 512
IMAGE_HEIGHT = 512
 
# souřadnice mřížky na x-ové a y-ové ose
x = np.linspace(-300, 300, IMAGE_WIDTH)
y = np.linspace(-300, 300, IMAGE_HEIGHT)
 
# matice s x-ovými a y-ovými souřadnicemi tvořícími mřížku
xx, yy = np.meshgrid(x, y)
 
# výpočet vzorku, který se má zobrazit
d = np.mod((xx*xx + yy*yy).astype(int), 255)
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH, height=IMAGE_HEIGHT)
p.x_range.range_padding = p.y_range.range_padding = 0
 
# vykreslení rastrového obrázku do grafu
p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", level="image")
p.grid.grid_line_width = 0.5
 
 
# vykreslení grafu do plochy webové stránky
show(p)

Pochopitelně je možné si zvolit i jinou barvovou paletu nabízenou knihovnou Bokeh, například:

p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="RdGy11", level="image")

S výsledkem:

Obrázek 13: Hodnoty z matice vykreslené metodou image s využitím zvolené barvové palety.

Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster6.py:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.plotting import figure, output_file, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
 
# textura by měla být čtvercová a její šířka i výška by měla být
# mocninou čísla 2
IMAGE_WIDTH = 512
IMAGE_HEIGHT = 512
 
# souřadnice mřížky na x-ové a y-ové ose
x = np.linspace(-500, 500, IMAGE_WIDTH)
y = np.linspace(-500, 500, IMAGE_HEIGHT)
 
# matice s x-ovými a y-ovými souřadnicemi tvořícími mřížku
xx, yy = np.meshgrid(x, y)
 
# výpočet vzorku, který se má zobrazit
d = np.mod((xx*xx + yy*yy).astype(int), 255)
 
# plocha pro graf
p = figure(width=IMAGE_WIDTH, height=IMAGE_HEIGHT)
p.x_range.range_padding = p.y_range.range_padding = 0
 
# vykreslení rastrového obrázku do grafu
p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="RdGy11", level="image")
p.grid.grid_line_width = 0.5
 
 
# vykreslení grafu do plochy webové stránky
show(p)

10. Popisky na x-ové ose sloupcového grafu

Vraťme se ještě jednou k problematice zobrazení sloupcových grafů, které se používají ve dvou oblastech:

  1. Hodnoty na x-ové ose tvoří například časovou řadu (tedy jedná se o seřazené hodnoty)
  2. Hodnoty na x-ové ose spolu sice souvisí, ale nemusí být nutně ve vstupních datech správně seřazeny

Podívejme se na druhý případ. Budeme chtít zobrazit formou sloupcového grafu údaje získané ze stránky https://www.tiobe.com/tiobe-index/:

# jména na X-ové ose
languages = ("Python", "C", "Java", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Swift")
 
# hodnoty na Y-ové ose
ratings = (12.20, 11.91, 10.47, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 1.55)

To znamená, že na x-ové ose budou zobrazena jména jazyků a na y-ové ose jejich hodnocení. Při definici plochy pro graf použijeme parametr x_range:

p = figure(x_range=languages, height=250, title="TIOBE index",
           toolbar_location=None, tools="")

A sloupcový graf následně vykreslíme:

p.vbar(x=languages, top=ratings, width=0.9)

S výsledkem:

Obrázek 14: Sloupcový graf se zobrazenými popularitami programovacích jazyků.

Úplný zdrojový kód tohoto příkladu vypadá následovně:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
 
# jména na X-ové ose
languages = ("Python", "C", "Java", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Swift")
 
# hodnoty na Y-ové ose
ratings = (12.20, 11.91, 10.47, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 1.55)
 
# plocha pro graf
p = figure(x_range=languages, height=250, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x=languages, top=ratings, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)
Poznámka: pochopitelně můžeme namísto neměnných n-tic použít seznamy (viz kód níže) nebo vektory knihovny NumPy. Výsledek bude totožný:
# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
 
# jména na X-ové ose
languages = ["Python", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Java", "C", "Swift"]
 
# hodnoty na Y-ové ose
ratings = [12.20, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 10.47, 11.91, 1.55]
 
# plocha pro graf
p = figure(x_range=languages, height=250, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x=languages, top=ratings, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)

11. Seřazení hodnot podle zadaného kritéria

Jazyky lze ještě před zobrazením grafu seřadit podle jejich popularity. Použijeme přitom následující trik, který zajistí i korektní prohození názvů sloupců:

sorted_ratings = sorted(languages, key=lambda x: ratings[languages.index(x)])

Výsledek nyní bude vypadat takto:

Obrázek 15: Sloupcový graf se zobrazenými popularitami programovacích jazyků; jazyky jsou seřazeny podle popularity.

Kód takto upraveného příkladu se zvýrazněnými rozdíly:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
 
# jména na X-ové ose
languages = ["Python", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Java", "C", "Swift"]
 
# hodnoty na Y-ové ose
ratings = [12.20, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 10.47, 11.91, 1.55]
 
sorted_ratings = sorted(languages, key=lambda x: ratings[languages.index(x)])
 
# plocha pro graf
p = figure(x_range=sorted_ratings, height=350, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x=languages, top=ratings, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)

Opačné seřazení (nejprve jazyky s vyšší popularitou) je stejně snadné:

sorted_ratings = (sorted(languages, key=lambda x: ratings[languages.index(x)]))[::-1]

Obrázek 16: Sloupcový graf se zobrazenými popularitami programovacích jazyků; jazyky jsou seřazeny podle popularity – první je jazyk s nejvyšší popularitou.

Kód takto upraveného příkladu se zvýrazněnými rozdíly:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
 
# jména na X-ové ose
languages = ["Python", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Java", "C", "Swift"]
 
# hodnoty na Y-ové ose
ratings = [12.20, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 10.47, 11.91, 1.55]
 
sorted_ratings = (sorted(languages, key=lambda x: ratings[languages.index(x)]))[::-1]
 
# plocha pro graf
p = figure(x_range=sorted_ratings, height=350, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x=languages, top=ratings, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)

12. Použití struktury ColumnDataSource

Prozatím byla data pro graf reprezentována formou sekvencí hodnot, n-tic, seznamů nebo vektorů a matic (NumPy). Ve skutečnosti je to však polovičaté řešení, protože knihovna Bokeh umožňuje vstupní data „obalit“ strukturou ColumnDataSource, která nám umožňuje specifikaci barev pro každou hodnotu zvlášť atd. Podívejme se, jak taková struktura vznikne. Je to jednoduché:

# definice zdroje dat
source = ColumnDataSource(data=dict(languages=languages, ratings=ratings))

Specifikovali jsme tedy jak hodnoty na x-ové ose (názvy jazyků), tak i na ose y-ové (jejich popularita).

Takto použitý zdroj dat lze snadno vykreslit do sloupcového grafu:

# vykreslení průběhu hodnot
p.vbar(x='languages', top='ratings', source=source, width=0.9)

Výsledek bude vypadat následovně:

Obrázek 17: Sloupcový graf se zobrazenými popularitami programovacích jazyků.

Opět se pochopitelně podíváme na úplný zdrojový kód příkladu:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
 
# jména na X-ové ose
languages = ["Python", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Java", "C", "Swift"]
 
# hodnoty na Y-ové ose
ratings = [12.20, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 10.47, 11.91, 1.55]
 
# definice zdroje dat
source = ColumnDataSource(data=dict(languages=languages, ratings=ratings))
 
# plocha pro graf
p = figure(x_range=languages, height=250, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x='languages', top='ratings', source=source, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)

13. Zvýraznění hodnot ve sloupcovém grafu s využitím různých barev sloupců

Díky umístění dat, která se mají vykreslit v grafu, do datové struktury ColumnDataSource je možné specifikovat barvy hodnot. Použít můžeme například již předpřipravenou barvovou paletu, což je koncept, který jsme viděli v souvislosti s rastrovými obrázky a s maticovými daty. Tentokrát však budeme obarvovat jednotlivé sloupce v grafu:

# definice zdroje dat
source = ColumnDataSource(data=dict(languages=languages, ratings=ratings, color=Spectral10))

Výsledek by měl vypadat takto:

Obrázek 18: Sloupcový graf se sloupci vybarvenými na základě hodnot a zvolené barvové palety.

Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.palettes import Spectral10
 
# jména na X-ové ose
languages = ["Python", "C++", "C#", "Visual Basic", "JavaScript", "SQL", "Assembly", "Java", "C", "Swift"]
 
# hodnoty na Y-ové ose
ratings = [12.20, 9.63, 6.12, 5.42, 2.09, 1.94, 1.85, 10.47, 11.91, 1.55]
 
# definice zdroje dat
source = ColumnDataSource(data=dict(languages=languages, ratings=ratings, color=Spectral10))
 
# plocha pro graf
p = figure(x_range=languages, height=250, title="TIOBE index",
           toolbar_location=None, tools="")
 
# vykreslení průběhu hodnot
p.vbar(x='languages', top='ratings', color='color', source=source, width=0.9)
 
# styl vykreslení
p.xgrid.grid_line_color = None
p.y_range.start = 0
 
# vykreslení grafu do plochy webové stránky
show(p)

14. Interaktivní přepočet grafů

Další požadavek, s nímž se velmi často setkáme, a který – nutno zdůraznit – není v knihovně Bokeh (prozatím) možné rozumně vyřešit, je interaktivní přepočet grafů po změně nějaké hodnoty či vstupní podmínky. Zkusme si tento problém alespoň částečně vyřešit. Začneme velmi jednoduchým příkladem, který pouze vykreslí sinusovku a kosinusovku:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
 
from bokeh.plotting import figure, show
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#00a0a0")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#a0a000")
 
# vykreslení grafu do plochy webové stránky
show(p)

Obrázek 19: Graf se sinusovkou a kosinusovkou.

15. Přidání posuvníku pro interaktivní změnu amplitudy jednoho průběhu v grafu

Nyní do grafu přidáme posuvník, kterým budeme posléze měnit amplitudu jedné z funkcí:

# posuvník pro změnu amplitudy
amplitude_slider = Slider(start=-1, end=1, value=1, step=0.05, title="Amplitude")

Při vykreslení nesmíme zapomenout na to, že se kromě grafu má vykreslit i onen posuvník:

# vykreslení grafu do plochy webové stránky
show(row(p, amplitude_slider))

Výsledek by měl vypadat takto:

Obrázek 20: Graf se sinusovkou a kosinusovkou, přidán je i posuvník.

Opět si ukažme úplný zdrojový kód tohoto příkladu:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
 
from bokeh.plotting import figure, show
from bokeh.layouts import row
from bokeh.models import Slider
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(x, y1, legend_label="sin(x)", line_width=2, color="#00a0a0")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#a0a000")
 
# posuvník pro změnu amplitudy
amplitude_slider = Slider(start=-1, end=1, value=1, step=0.05, title="Amplitude")
 
# vykreslení grafu do plochy webové stránky
show(row(p, amplitude_slider))

16. Data pro vykreslení grafu dostupná ve formě ColumnDataSource

V dalším kroku budeme muset data zabalit do nám již známé struktury ColumnDataSource. Je to nutné z toho důvodu, že s daty (hodnotami) budeme později manipulovat v JavaScriptu:

# zdroj dat
source = ColumnDataSource(data=dict(x=x, y=y1))

Nepatrně se změní i způsob vykreslení:

p.line(source=source, line_width=2, color="#00a0a0")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#a0a000")
Poznámka: povšimněte si, že jsme „obalili“ pouze hodnoty použité pro vykreslení sinusovky. Kosinusovka je stále vykreslena původním způsobem (a nebude ji tedy možné v JavaScriptu modifikovat).

Zdrojový kód příkladu se změní pouze nepatrně:

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
 
from bokeh.plotting import figure, show
from bokeh.layouts import row
from bokeh.models import Slider, ColumnDataSource, CustomJS
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# zdroj dat
source = ColumnDataSource(data=dict(x=x, y=y1))
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(source=source, line_width=2, color="#00a0a0")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#a0a000")
 
# posuvník pro změnu amplitudy
amplitude_slider = Slider(start=-1, end=1, value=1, step=0.05, title="Amplitude")
 
# vykreslení grafu do plochy webové stránky
show(row(p, amplitude_slider))

17. Temná strana Bokehu – přepočet dat v JavaScriptu

Nyní se ovšem ocitáme ve složité situaci, protože budeme chtít, aby se graf (a v něm zobrazené hodnoty) přepočetl po změně posuvníku. Vzhledem k tomu, že Bokeh vytváří statické HTML stránky a neběží jako webový server, nemá možnost nijak do zobrazených dat zasahovat. Musíme si pomoci oklikou a způsobem, který není obecně použitelný – necháme si data přepočítat přímo na straně webového klienta, tj. kódem napsaným v JavaScriptu. Tento kód propojíme s posuvníkem:

amplitude_slider = Slider(start=-1, end=1, value=1, step=0.05, title="Amplitude")
amplitude_slider.js_on_change("value", on_amplitude_change)

Po změně posuvníku se zavolá callback funkce on_amplitude_change. Tato funkce dokáže získat data „zabalená“ do webové stránky a modifikuje je. Zde tedy vlastně opakujeme výpočet, který již jednou proběhl na straně Pythonu. Původní data jsou uložena v source:

# callback zavolaný po změně souřadnic posuvníku
on_amplitude_change = CustomJS(args=dict(source=source), code="""
    const data = source.data;
    const a = cb_obj.value
    const x = data['x']
    const y = data['y']
    for (let i = 0; i < x.length; i++) {
        y[i] = a*Math.sin(x[i])
    }
    source.change.emit();
""")
Poznámka: problém jsme sice vyřešili, ale jen za tu cenu, že jsme nakonec museli použít JavaScript (čímž se koncept Bokehu hroutí) a navíc jsme museli celý výpočet zopakovat. Nejedná se tedy v žádném případě o doporučeníhodné řešení; jen jde o ukázku toho, jak lze některé koncepční problémy Bokehu alespoň částečně odstranit.

Obrázek 21: Změna amplitudy sinusovky.

Obrázek 22: Změna amplitudy i fáze sinusovky.

Zdrojový kód dnešního posledního demonstračního příkladu vypadá takto:

CS24 tip temata

# naimportujeme vybrané funkce z knihovny `bokeh.plotting`
 
from bokeh.plotting import figure, show
from bokeh.layouts import row
from bokeh.models import Slider, ColumnDataSource, CustomJS
 
# taktéž budeme potřebovat některé funkce z knihovny `numpy`
import numpy as np
 
# vykreslení průběhu funkce sin
 
# hodnoty na x-ové ose
x = np.linspace(0, 2 * np.pi, 100)
 
# hodnoty na y-ové ose
y1 = np.sin(x)
 
# hodnoty na y-ové ose
y2 = np.cos(x)
 
# zdroj dat
source = ColumnDataSource(data=dict(x=x, y=y1))
 
# plocha pro graf
p = figure(title="sin(x) a cos(x)", x_axis_label="x", y_axis_label="sin(x) a cos(x)")
 
# vykreslení průběhu
p.line(source=source, line_width=2, color="#00a0a0")
p.line(x, y2, legend_label="cos(x)", line_width=2, color="#a0a000")
 
# callback zavolaný po změně souřadnic posuvníku
on_amplitude_change = CustomJS(args=dict(source=source), code="""
    const data = source.data;
    const a = cb_obj.value
    const x = data['x']
    const y = data['y']
    for (let i = 0; i < x.length; i++) {
        y[i] = a*Math.sin(x[i])
    }
    source.change.emit();
""")
 
 
# posuvník pro změnu amplitudy
amplitude_slider = Slider(start=-1, end=1, value=1, step=0.05, title="Amplitude")
amplitude_slider.js_on_change("value", on_amplitude_change)
 
# vykreslení grafu do plochy webové stránky
show(row(p, amplitude_slider))

18. Závěrečné shrnutí

Knihovna Bokeh je dobře využitelná především těmi vývojáři, kteří pracují v Pythonu (simulace, datové analýzy atd.) a potřebují zobrazit výsledky měření nebo výpočtů pomocí grafů zobrazených formou statických (resp. „statických“ HTML stránek). Tyto stránky mohou být součástí prezentace, mohou být uloženy v systému pro správu dokumentů, ve Wiki, na GitHub pages atd. Předností Bokehu je, že generované HTML stránky obsahují jak data, tak i automaticky generovaný kód psaný v JavaScriptu, takže jsou grafy do určité míry interaktivní – a to bez toho, aby vývojář musel aktivně používat či vůbec znát webové (frontend) technologie. Taktéž je možné, aby uživatel, který stránku používá, graf zvětšil/zmenšil/posunul a posléze si nechal uložit výsledek ve formě rastrového obrázku (PNG). Musíme však znát i některá zásadní omezení Bokehu, především fakt, že není jednoduché interaktivně měnit zobrazená data. Nejedná se tedy (a ani to není plánováno) o náhradu interaktivních ovládacích prvků použitých například v Jupyter Notebooku.

19. Repositář s demonstračními příklady

Zdrojové kódy všech prozatím popsaných demonstračních příkladů určených pro programovací jazyk Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis příkladu Cesta
1 01_linear_plot.py nejjednodušší typ grafu poskytovaný knihovnou Bokeh https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/01_li­near_plot.py
2 02_linear_plot.py zobrazení titulku a legendy https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/02_li­near_plot.py
3 03_sinus_plot.py kooperace s knihovnou NumPy https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/03_si­nus_plot.py
4 04_sin_cos_plot.py vykreslení průběhu dvou funkcí https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/04_sin_cos_plot­.py
5 05_sin_cos_plot.py alternativní způsob specifikace barev https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/05_sin_cos_plot­.py
6 06_sin_cos_circles.py alternativní značky pro vykreslení grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/06_sin_cos_cir­cles.py
7 07_bars.py jednoduchý sloupcový graf https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/07_bars.py
8 08_bars.py korektní způsob předávání hodnot pro sloupcový graf https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/08_bars.py
9 09_bars.py šířka jednotlivých sloupců ve sloupcovém grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/09_bars.py
10 10_sin_cos_bars.py sloupcový graf se specifikací začátků a konce sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/10_sin_cos_bar­s.py
11 11_sin_cos_circle.py vykreslení kružnice (parametrická křivka) https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/11_sin_cos_cir­cle.py
12 12_spiral.py vykreslení logaritmické spirály (parametrická křivka) https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/12_spiral.py
13 13_output_png.py export grafu do formátu PNG https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/13_ou­tput_png.py
14 14_legend_styling.py nastavení stylu zobrazení legendy https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/14_le­gend_styling.py
15 15_figure_size.py specifikace velikosti grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/15_fi­gure_size.py
16 16_axis_limits.py nastavení limitu na souřadných osách https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/16_a­xis_limits.py
17 17_linear_scale.py měřítka na osách https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/17_li­near_scale.py
18 18_log_scale.py logaritmické měřítko na y-ové ose https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/18_log_scale.py
       
19 19_styles.py styly vykreslování grafů – glyfy https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/19_styles.py
20 20_styles.py styly vykreslování grafů – glyfy https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/20_styles.py
21 21_scatter.py graf typu x-y https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/21_scatter.py
22 22_lorenz_attractor.py vykreslení Lorenzova atraktoru v 2D grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/22_lo­renz_attractor.py
23 23_row_plots.py uspořádání několika grafů na webové stránce https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/23_row_plots.py
24 24_grid_plots.py uspořádání několika grafů na webové stránce https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/24_grid_plot­s.py
25 25_grid_plot_sizes.py změna velikosti zobrazených grafů na webové stránce https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/25_grid_plot_si­zes.py
26 26_alpha.py změna průhlednosti vykreslovaných glyfů https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/26_alpha.py
27 27_colors.py modifikace barvy vykreslovaných glyfů https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/27_colors.py
28 28_colors.py modifikace barvy vykreslovaných glyfů https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/28_colors.py
29 29_heatmap.py heatmapa https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/29_heatmap.py
30 30_button.py tlačítko jako jeden z interaktivních prvků https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/30_button.py
31 31_select_color.py interaktivní výběr barvy z barvové palety https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/31_se­lect_color.py
32 32_select_color_size.py interaktivní výběr barvy a změna velikosti glyfů (stop) https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/32_se­lect_color_size.py
33 33_select_color_size_alpha.py interaktivní výběr barvy a změna velikosti glyfů (stop) i průhlednosti https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/33_se­lect_color_size_alpha.py
       
34 matplotlib_plot.py ukázka použití „konkurenčního“ projektu Matplotlib https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/mat­plotlib_plot.py
       
35 34_cathegorical_data01.py popisky na x-ové ose sloupcového grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/34_cat­hegorical_data01.py
36 35_cathegorical_data02.py popisky na x-ové ose sloupcového grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/35_cat­hegorical_data02.py
37 36_cathegorical_data03.py seřazení hodnot podle zadaného kritéria https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/36_cat­hegorical_data03.py
38 37_cathegorical_data04.py seřazení hodnot podle zadaného kritéria https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/37_cat­hegorical_data04.py
39 38_data_source.py hodnoty uložené v datové struktuře ColumnDataSource https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/38_da­ta_source.py
40 39_data_source_color.py obarvení hodnot v grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/39_da­ta_source_color.py
41 40_sin_cos_plot.py interaktivní přepočet grafů – jednoduché průběhy funkcí https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/40_sin_cos_plot­.py
42 41_sin_cos_plot_control_A.py přidání posuvníku pro interaktivní změnu amplitudy jednoho průběhu v grafu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/41_sin_cos_plot_con­trol_A.py
43 42_sin_cos_plot_control_B.py data pro vykreslení grafu dostupná ve formě ColumnDataSource https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/42_sin_cos_plot_con­trol_B.py
44 43_sin_cos_plot_control_C.py temná strana Bokehu – přepočet dat v JavaScriptu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/43_sin_cos_plot_con­trol_C.py
45 palette_ice.py barvová paleta https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/palette_ice.py
46 raster1.py graf obsahující data ve formě rastrového obrázku https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster1.py
47 raster2.py rastrová data s proměnným počtem sloupců a řádků https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster2.py
48 raster3.py textura – moiré https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster3.py
49 raster4.py použití externí barvové palety (LUT) https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster4.py
50 raster5.py rastrové obrázky a interní barvové palety Bokehu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster5.py
51 raster6.py rastrové obrázky a interní barvové palety Bokehu https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/raster6.py
52 theme_caliber.py nastavení tématu „caliber“ https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_caliber.py
53 theme_dark_minimal.py nastavení tématu „dark minimal“ https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_dark_minimal.py
54 theme_light_minimal.py nastavení tématu „light minimal“ https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_light_minimal.py
55 theme_night_sky.py nastavení tématu „night sky“ https://github.com/tisnik/most-popular-python-libs/blob/master/bokeh/the­me_night_sky.py

20. Odkazy na Internetu

  1. bokeh na GitHubu
    https://github.com/bokeh/bokeh
  2. First steps 1: Creating a line chart
    https://docs.bokeh.org/en/la­test/docs/first_steps/fir­st_steps1.html
  3. Python Bokeh tutorial – Interactive Data Visualization with Bokeh
    https://www.geeksforgeeks.org/python-bokeh-tutorial-interactive-data-visualization-with-bokeh/
  4. The R Project for Statistical Computing
    https://www.r-project.org/
  5. An Introduction to R
    https://cran.r-project.org/doc/manuals/r-release/R-intro.pdf
  6. R (programming language)
    https://en.wikipedia.org/wi­ki/R_(programming_language)
  7. Graphics, ggplot2
    http://r4stats.com/examples/graphics-ggplot2/
  8. Seriál Programovací jazyk Julia
    https://www.root.cz/seria­ly/programovaci-jazyk-julia/
  9. Plotly
    https://plotly.com/
  10. pyecharts
    https://github.com/pyechar­ts/pyecharts/blob/master/RE­ADME.en.md
  11. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib/
  12. Lorenzův atraktor
    https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-vi/#k02
  13. Lorenzův atraktor
    https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-iii/#k03
  14. Lorenz system
    https://en.wikipedia.org/wi­ki/Lorenz_system

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.