How to make a contour plot in python using Bokeh (or other libs)?
Asked Answered
I

5

6

I am interested in making a contour plot in Bokeh. I have not been able to find anything on the net so far.

As a reminder, this is contour plot:

enter image description here

Any help would be appreciated. I would also welcome suggestions to other libraries but with prerequisite of allowing for interactive/animated plots, and not only rendering static output (images).

Irtysh answered 4/11, 2015 at 22:11 Comment(6)
use matplotlib for examples see matplotlib.org/examples/pylab_examples/contour_demo.html and matplotlib.org/examples/pylab_examples/contour_image.htmlUnruh
A high level canned contour plot bokeh.charts.Contour is still an open feature request as of Bokeh 0.10 but will hopefully be in one of the next few releases. It would be a nice project for a new contributor, if you are interested in helping please stop by the Bokeh mailing list or GH tracker.Stephenson
@Unruh I am not aware that matpotlib allows for interactive/animated web previews, am I wrong?Irtysh
@Stephenson Thanks for the great suggestion.Irtysh
I don't know about web either but it allows for interactive plotting.Unruh
Bokeh does allow presenting matplotlib figures in a web application. I don't know if it handles contours, but you should try. bokeh.pydata.org/en/0.10.0/docs/user_guide/compat.html#overviewVicarial
P
5

Plotly has supported contour plots in Python for the past year:

https://plot.ly/python/contour-plots/

https://plot.ly/pandas/contour-plots/

Density plots (contour plots with adjacent histograms):

https://plot.ly/python/2d-density-plots/

https://plot.ly/pandas/2d-density-plots/

The Plotly Python library is on pip, 100% free and open-source.

python-contour-plot

Perkin answered 22/2, 2016 at 6:33 Comment(0)
A
7

You can also use matplotlibs contour plot for calculation of the contour data and then plot the contours using bokehs multi_line. I'm also plotting text labels (which are unfortunately a bit ugly).

import numpy as np
import matplotlib.pyplot as plt
from bokeh.models import ColumnDataSource
from bokeh.io import output_file
from bokeh.plotting import gridplot,figure, show

def get_contour_data(X, Y, Z):
    cs = plt.contour(X, Y, Z)
    xs = []
    ys = []
    xt = []
    yt = []
    col = []
    text = []
    isolevelid = 0
    for isolevel in cs.collections:
        isocol = isolevel.get_color()[0]
        thecol = 3 * [None]
        theiso = str(cs.get_array()[isolevelid])
        isolevelid += 1
        for i in range(3):
            thecol[i] = int(255 * isocol[i])
        thecol = '#%02x%02x%02x' % (thecol[0], thecol[1], thecol[2])

        for path in isolevel.get_paths():
            v = path.vertices
            x = v[:, 0]
            y = v[:, 1]
            xs.append(x.tolist())
            ys.append(y.tolist())
            xt.append(x[len(x) / 2])
            yt.append(y[len(y) / 2])
            text.append(theiso)
            col.append(thecol)

    source = ColumnDataSource(data={'xs': xs, 'ys': ys, 'line_color': col,'xt':xt,'yt':yt,'text':text})
    return source


output_file("contour.html")

N = 400
x = np.linspace(-1, 1, N)
y = np.linspace(-1, 1, N)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2

source = get_contour_data(X,Y,Z)
plot = figure(plot_width=400,plot_height=400,x_range=[-1,1], y_range=[-1,1])
plot.multi_line(xs='xs', ys='ys', line_color='line_color', source=source)
plot.text(x='xt',y='yt',text='text',source=source,text_baseline='middle',text_align='center')
show(plot)

this is the output:

enter image description here

Auction answered 4/6, 2016 at 18:13 Comment(1)
Love this solution, since Bokeh's contour plotting abilities continue to seem hacky to this day.Anniceannie
L
7

I wrote a filled contour tool based on matplotlib output:

https://github.com/asher-pembroke/bokeh-tools

Logroll answered 6/6, 2016 at 20:46 Comment(0)
P
5

Plotly has supported contour plots in Python for the past year:

https://plot.ly/python/contour-plots/

https://plot.ly/pandas/contour-plots/

Density plots (contour plots with adjacent histograms):

https://plot.ly/python/2d-density-plots/

https://plot.ly/pandas/2d-density-plots/

The Plotly Python library is on pip, 100% free and open-source.

python-contour-plot

Perkin answered 22/2, 2016 at 6:33 Comment(0)
A
5

Thanks Pablo your answer really helped me.

Using your example I made a similar plot that adds the contour lines by using the skimage library. I also turned on the hover tool as in the Bokeh image example that you referenced. Hopefully someone else comes along and adds the line labels.

Note that the following code is meant to run in Jupyter Notebook.

from skimage import measure
import numpy as np

from bokeh.plotting import figure, show, output_notebook
from bokeh.models import (ColorBar,
                          FixedTicker, 
                          LinearColorMapper, 
                          PrintfTickFormatter)

output_notebook()

N = 500
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)

mapper = LinearColorMapper(palette='Spectral11', low=-1, high=1)

p = figure(x_range=(0, 10), y_range=(0, 10),
           tooltips=[("x", "$x"), ("y", "$y"), ("value", "@image")])

# must give a vector of image data for image parameter
p.image(image=[d], x=0, y=0, dw=10, dh=10, palette='Spectral11')

levels = np.linspace(-1, 1, 12)
color_bar = ColorBar(color_mapper=mapper, 
                     major_label_text_font_size="8pt",
                     ticker=FixedTicker(ticks=levels),
                     formatter=PrintfTickFormatter(format='%.2f'),
                     label_standoff=6, 
                     border_line_color=None, 
                     location=(0, 0))

p.add_layout(color_bar, 'right')

for level in levels:
  contours = measure.find_contours(d, level)
  for contour in contours:
    x = contour[:,1]/50
    y = contour[:,0]/50
    p.line(x, y, color='grey', line_width=2)

show(p)

enter image description here

Americano answered 14/2, 2019 at 0:3 Comment(1)
Great idea using measure from skimage. And yes, adding the line labels is still missing in bokeh I think.Roobbie
R
3

By choosing a palette with 10 values, like in the example you provide, one can use image (see Bokeh image example) in bokeh to simulate a contour plot. The black contour lines and the numbers are missing, but the boundaries between the colors are actually the contour lines. Also, as far as I know Bokeh does not provide a color bar, but you can code it as another image (UPDATE: Latests versions of Bokeh do provide colorbar. ):

from bokeh.io import output_file
from bokeh.plotting import gridplot,figure, show
from bokeh.models import ColumnDataSource,FixedTicker
import numpy as np
from matplotlib import cm,colors

output_file("contour.html")
cmap = cm.get_cmap("jet") #choose any matplotlib colormap here
num_slabs = 10 # number of color steps
jet_10 = [colors.rgb2hex(m) for m in cmap(np.arange(0,cmap.N,cmap.N/(num_slabs-1)))]
vmin = 0
vmax = 1550
N = 200
x = np.linspace(0, 10, N)
y = np.linspace(0, 10, N)
xx, yy = np.meshgrid(x, y)
d = vmax * (1. + np.sin(xx)*np.cos(yy))

source = ColumnDataSource(data={'d': [d], 'xx': [x], 'yy': [y]})
p = figure(plot_width=400,plot_height=400,x_range=[0, 10], y_range=[0, 10],min_border_right=10)
p.image(image="d", x=[0], y=[0], dw=[10], dh=[10], palette=jet_10,source=source)

# The following code is for the colorbar:
pcb = figure(plot_width=80,plot_height=400,x_range=[0, 1], y_range=[0, vmax],min_border_right=10)
pcb.image(image=[np.linspace(vmin,vmax,100).reshape(100,1)],x=[0],y=[0],dw=[1],dh=[vmax-vmin], palette=jet_10)
pcb.xaxis.major_label_text_color = None
pcb.xaxis.major_tick_line_color = None
pcb.xaxis.minor_tick_line_color = None
pcb.yaxis[0].ticker=FixedTicker(ticks=np.linspace(vmin,vmax,num_slabs+1)) # 11 ticks
pgrid = gridplot([[p,pcb]])  # this places the colorbar next to the image
show(pgrid)

The output will look like: enter image description here

Roobbie answered 25/2, 2016 at 5:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.