Skip to content

Instantly share code, notes, and snippets.

@Sieboldianus
Last active September 8, 2022 10:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sieboldianus/8b257c7b7f46b26c92280d984ed98fb1 to your computer and use it in GitHub Desktop.
Save Sieboldianus/8b257c7b7f46b26c92280d984ed98fb1 to your computer and use it in GitHub Desktop.
Setup and use svg export in bokeh/holoviews inside Docker (webdriver setup, browser installation)

Just to memorize, these are the steps to setup webdriver (chrome) and svg-export as of Bokeh 2.4.3 / Holoviews 1.14.8

This was tested in a Debian-based Docker container, but should work in most Linux distributions.

Install Selenium

Install in your conda environment:

conda install selenium webdriver-manager -c conda-forge

Install Chrome

apt-get update && apt-get install -y gnupg2
curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
echo "deb [arch=amd64]  http://dl.google.com/linux/chrome/deb/ stable main" >> \
    /etc/apt/sources.list.d/google-chrome.list
apt-get -y update
apt-get -y install google-chrome-stable

Optional: Install Chromedriver

This is an optional step, since webdriver_manager will automatically pull and install the matching Chromedriver (see below).

Get the Chrome version and install the matching Chromedriver

google-chrome --version

Google Chrome 104.0.5112.101

  • go to
  • click on matching version:
    • If you are using Chrome version 104, please download ChromeDriver 104.0.5112.79

  • copy path to chromedriver_linux64.zip
apt-get update && apt-get install -y zip wget
cd /tmp/
wget https://chromedriver.storage.googleapis.com/104.0.5112.79/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
mv chromedriver /usr/bin/chromedriver
chown root:root /usr/bin/chromedriver
chmod +x /usr/bin/chromedriver

Use in Bokeh/Holoviews

from bokeh.io import export_svgs
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from pathlib import Path

options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument("--no-sandbox")
options.add_argument("--window-size=2000x2000")
options.add_argument('--disable-dev-shm-usage')        

service = Service(ChromeDriverManager().install())
webdriver = webdriver.Chrome(service=service, options=options)

# Export svg in Bokeh/Holoviews
p =  hv.render(my_layers, backend='bokeh')
p.output_backend = "svg"
export_svgs(p, 
    filename=Path(output / 'svg' / 'graphic.svg'),
    webdriver=webdriver)

Note that --disable-dev-shm-usage is necessary for Chrome to work inside Docker, if the shm_size is too small.

An alternative is to increase the shm_size in your docker-compose.yml, e.g.:

version: '3.6'

services:
  mycontainer:
    build: .
    container_name: mycontainer
    restart: always
    shm_size: '4gb'

For other drivers (chromium, geckodriver), see the webdriver-manager readme.

Test

Here is another self-contained test:

import holoviews as hv
import numpy as np
from pathlib import Path

OUTPUT = Path.cwd() / "out"
OUTPUT.mkdir(exist_ok=True)

def load_chromedriver():
    """Loads chromedriver (for bokeh svg export), if found"""
    try:
        from selenium import webdriver
        from selenium.webdriver.chrome.service import Service
        from webdriver_manager.chrome import ChromeDriverManager
        
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        options.add_argument('--disable-gpu')
        options.add_argument("--no-sandbox")
        options.add_argument("--window-size=2000x2000")
        options.add_argument('--disable-dev-shm-usage')        
        
        service = Service(ChromeDriverManager().install())
        webdriver = webdriver.Chrome(service=service, options=options)
        print('Chromedriver loaded. Svg output enabled.')
    except:
        logging.warning('Chromedriver not found. Disabling svg output.')
        webdriver = None
    return webdriver

WEB_DRIVER = load_chromedriver()

if WEB_DRIVER:
    br = hv.renderer('bokeh')
    x = hv.Scatter(np.random.rand(100,2))
    plot = br.get_plot(x)
    plot = plot.state
    plot.output_backend='svg'
    export_svgs(plot, filename=OUTPUT / "out.svg", webdriver=WEB_DRIVER)
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment