Search code examples
pythonmatplotlibbokeh

How to add matplotlib object to Bokeh layout?


I am working on a tab-based local Bokeh application, and I am trying to include a matplotlib object in the first tab of this app.

The object is a Venn Diagram, which is outside of the scope of Bokeh.

So far, I have got something like this:

import bokeh
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import row, column
import matplotlib.pyplot as plt
from matplotlib_venn import venn2

output_file('test.html')

scatter = figure(plot_width = 900, plot_height = 400)

scatter.circle([1,2,3,4,5,6], [3,5,7,9,11,16], size = 12, alpha = 0.6)

bar = figure(plot_width = 450, plot_height = 400)

bar.quad(top = [3,5,7,9,11,16], bottom = 0, left = [1,2,3,4,5,6], right = [1.9,2.9,3.9,4.9,5.9,6.9])

venn2([set(['A', 'B', 'C', 'D', 'E']), set(['A', 'C', 'E', 'G', 'I'])])

plots = column(scatter, bar)

show(plots)

Ideally, I would like to position the Venn diagram in the manner shown below.

desired layout of resulting Panel object

I somewhat naïvely thought something like column(scatter, row(bar, plt.show())) would work, but it does not.

I'm relatively new to Python and I have never used MatPlotLib before.


Solution

  • To elaborate on the comment: there is not any built-in integration between Bokeh and MPL. If you to embed an MPL plot in some Bokeh content, I can think of two approaches:

    • If you an convert to a file format, e.g PNG, and host the image file somwhere accessible via URL, then you could use an HTML <img> tag in Bokeh Div to display the image file.

    • Otherwise, use PIL or some other tool to generate a NumPy of RGBA data for the image of the MPL plot. Then you can "plot" the MPL plot in a Bokeh plot using the ImageRGBA glyph, as suggested in the comment.

      # Just some synthetic RGBA data
      img = np.empty((20,20), dtype=np.uint32)
      view = img.view(dtype=np.uint8).reshape((N, N, 4))
      for i in range(N):
          for j in range(N):
              view[i, j, 0] = int(i/N*255)
              view[i, j, 1] = 158
              view[i, j, 2] = int(j/N*255)
              view[i, j, 3] = 255
      
      p = figure()
      
      # must give a vector of images
      p.image_rgba(image=[img], x=0, y=0, dw=10, dh=10)