Bokeh Creates Plots Fast When the Kernel is Interrupted

I have been using Bokeh for 1 year through Jupyter Notebooks, and recently, I have encountered an interesting issue and an even more interesting workaround.

For the last few months, whenever I have been plotting Bokeh plots, they have been rendering much more slowly than I am used to: it takes 5-10 seconds per plot with <100 glyphs and up to 5 minutes per plot with >1000 glyphs. I assumed my computer was slow and that Bokeh had performance limitations.

However, I have discovered that if I first generate the plot variable p in one cell, then I show the plot in a second cell with bokeh.io.show(p), then I interrupt the kernel while running the second cell, and then I rerun the second cell, it plots instantly.

I have reproduced this several times across notebooks and over a few weeks. Has anyone else encountered this?

I am running Windows 10 on a laptop with 16GB RAM (Intel i7-1260) and 12 cores/16 threads (I think). My computing environment is below.

$ jupyter --version
Selected Jupyter core packages...
IPython          : 8.20.0
ipykernel        : 6.28.0
ipywidgets       : 8.1.2
jupyter_client   : 8.6.0
jupyter_core     : 5.5.0
jupyter_server   : 2.10.0
jupyterlab       : 4.0.11
nbclient         : 0.8.0
nbconvert        : 7.10.0
nbformat         : 5.9.2
notebook         : 7.0.8
qtconsole        : 5.5.1
traitlets        : 5.7.1

> $ python --version
Python 3.11.8

(The below was run in Jupyter)

> $ bokeh.io.output_notebook()
BokehJS 3.4.0 successfully loaded.

In case it is relevant, I have been building all of my plots with a function I coded for convenience:

def generate_plot(x_range, x_axis_type, x_label, y_range, y_axis_type, y_label, title, font_size=20, height = 325, width = 325, x_interval = None, y_interval = None):
    """This function takes in x axis data, y axis data, and a title, and simply
    returns a Bokeh plot object with customization to make the graphs readable."""
    if y_range and x_range:
        p = bokeh.plotting.figure(width = width, height = height, y_range = y_range, x_range = x_range, title = title,
                                  x_axis_label = x_label, y_axis_label = y_label, x_axis_type = x_axis_type, y_axis_type = y_axis_type)
    elif y_range and not x_range:
        p = bokeh.plotting.figure(width = width, height = height, y_range = y_range, title = title,
                                  x_axis_label = x_label, y_axis_label = y_label, x_axis_type = x_axis_type, y_axis_type = y_axis_type)
    elif x_range and not y_range:
        p = bokeh.plotting.figure(width = width, height = height, x_range = x_range, title = title,
                                  x_axis_label = x_label, y_axis_label = y_label, x_axis_type = x_axis_type, y_axis_type = y_axis_type)
    else:
        p = bokeh.plotting.figure(width = width, height = height, title = title,
                                  x_axis_label = x_label, y_axis_label = y_label, x_axis_type = x_axis_type, y_axis_type = y_axis_type)
    font_size = "{0:}px".format(font_size)
    p.title.align, p.title.text_font, p.title.text_font_style = "center", "aptos", "bold" # Title text options
    p.title.text_font_size = "24px" # Title text size
    p.xaxis.axis_label_text_font, p.xaxis.axis_label_text_font_style = "aptos", "bold" # X-axis label text options
    p.xaxis.major_label_text_font, p.xaxis.major_label_text_font_style = "aptos", "bold" # X-axis tick labels text options
    p.xaxis.axis_label_text_font_size, p.xaxis.major_label_text_font_size = font_size, font_size # Y-axis & tick label sizes
    p.yaxis.axis_label_text_font, p.yaxis.axis_label_text_font_style = "aptos", "bold" # Y-axis label text options
    p.yaxis.major_label_text_font, p.yaxis.major_label_text_font_style = "aptos", "bold" # Y-axis tick labels text options
    p.yaxis.axis_label_text_font_size, p.yaxis.major_label_text_font_size = font_size, font_size # Y-axis & tick label sizes
    p.xgrid.visible, p.ygrid.visible, p.outline_line_color = False, False, None # X grid, Y grid, and outline visibility
    p.ygrid.minor_grid_line_color = p.xgrid.minor_grid_line_color = p.ygrid.grid_line_color
    p.ygrid.grid_line_color = p.xgrid.grid_line_color = "grey"
    p.outline_line_color = p.background_fill_color # Make outline invisible vs. background
    if x_interval: p.xaxis.ticker.min_interval = p.xaxis.ticker.max_interval = x_interval# Set the interval between major x-axis ticks to the value 'x_interval', if it has been given
    if y_interval: p.yaxis.ticker.min_interval = p.yaxis.ticker.max_interval = y_interval # Set the interval between major y-axis ticks to the value 'y_interval', if it has been given

@Shruteek I haven’t ever seen this. In any case, it’s not possible to speculate at all without a complete Minimal Reproducible Example [1] that can be taken and run, as-is without modification, to reproduce.


  1. minimal means e.g. stripped of all styling and visual changes, comments, etc. unless their presence is actually needed to reproduce things, i.e. the smallest number of lines of code to demonstrate the problem. ↩︎

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.