# Contour plots#

Contour plots are used to calculate and render lines of constant value in two-dimensional quadrilateral grids. Both the lines and the filled regions between lines can be rendered with a single function call.

## Simple example#

Here is a simple example rendering both contour lines and filled polygon regions.

```import numpy as np

from bokeh.palettes import Sunset8
from bokeh.plotting import figure, show

# Data to contour is the sum of two Gaussian functions.
x, y = np.meshgrid(np.linspace(0, 3, 40), np.linspace(0, 2, 30))
z = 1.3*np.exp(-2.5*((x-1.3)**2 + (y-0.8)**2)) - 1.2*np.exp(-2*((x-1.8)**2 + (y-1.3)**2))

p = figure(width=550, height=300, x_range=(0, 3), y_range=(0, 2))

levels = np.linspace(-1, 1, 9)
contour_renderer = p.contour(x, y, z, levels, fill_color=Sunset8, line_color="black")

colorbar = contour_renderer.construct_color_bar()

show(p)
```

By convention, `z` is the 2D array to contour and is defined on an `x`, `y` grid. Here the grid is a regularly-spaced Cartesian grid. `levels` contains the sequence of levels to contour.

Both `line_color` and `fill_color` are optional keyword arguments to `contour()`. `line_color` must be specified to draw contour lines and `fill_color` to draw filled contour polygons. They can be scalar or vector visual properties.

Note

The length of vector visual properties for contour lines is `len(levels)` and for filled contour polygons it is `len(levels)-1`.

In this example `line_color` is a scalar so every contour line is rendered as a solid black line. The `fill_color` is a vector so that the filled regions between contour levels are rendered with different colors.

There is a colorbar on the right of the plot which is obtained using `construct_color_bar()`. It automatically displays the same fill and line visual properties as the contour plot.

## Polar grid example#

Here is a more complicated example showing other features available for contour plots.

```import numpy as np

from bokeh.palettes import Cividis
from bokeh.plotting import figure, show

# Data to contour is a 2D sin wave on a polar grid.
radius, angle = np.meshgrid(np.linspace(0, 1, 20), np.linspace(0, 2*np.pi, 120))

p = figure(width=550, height=400)

levels = np.linspace(0, 2, 11)

contour_renderer = p.contour(
x=x, y=y, z=z, levels=levels,
fill_color=Cividis,
hatch_pattern=["x"]*5 + [""]*5,
hatch_color="white",
hatch_alpha=0.5,
line_color=["white"]*5 + ["black"] + ["red"]*5,
line_dash=["solid"]*6 + ["dashed"]*5,
line_width=*6 + *5,
)

colorbar = contour_renderer.construct_color_bar(title="Colorbar title")

show(p)
```

The grid is polar, wrapping around on itself, and there are many more visual properties including `line`, `fill` and `hatch` properties. Many of these are vector properties so that it is possible to emphasize, for example, positive and negative contour levels differently.

All visual properties can be scalar or vector of the correct length. Color visual properties `line_color`, `fill_color` and `hatch_color` support a few extra options for how they can be specified:

• A sequence of colors that is longer than required will be resampled using `linear_palette()`. The length 256 palettes such as `Cividis256` are useful here.

• A dictionary that maps from palette length (number of colors) to palette may be used, in which case a lookup into the dictionary is performed to return a palette of the correct length. The example here uses the palette collection `Cividis`.

`construct_color_bar()` accepts other keyword arguments that are passed to the `ContourColorBar` constructor to set properties such as the `title` shown here.

## Animated contours#

Bokeh can generate animated contour plots using `bokeh serve` as the contour calculations occur in Python. Here is an example taken from `examples/app/contour_animated.py`:

```import numpy as np

from bokeh.driving import count
from bokeh.palettes import PiYG
from bokeh.plotting import curdoc, figure
from bokeh.plotting.contour import contour_data

x, y = np.meshgrid(np.linspace(-1, 1, 41), np.linspace(-1, 1, 41))
levels = np.linspace(-1.0, 1.0, 11)

def get_z(timestep):
delta = 0.08*np.cos(timestep*0.15)
amps  = [0.95, 0.95, -0.95, -0.95]
xmids = [-0.4,  0.4, -0.4,  0.4]
ymids = [-0.4,  0.4,  0.4, -0.4]
rads  = [0.4 + delta, 0.4 + delta, 0.4 - delta, 0.4 - delta]

z = np.zeros_like(x)
z += amp*np.exp( -((x-xmid)**2 + (y-ymid)**2)/rad**2 )
return z

@count()
def callback(timestep):
z = get_z(timestep)
new_contour_data = contour_data(x, y, z, levels)
contour_renderer.set_data(new_contour_data)

fig = figure(width=600, height=450)

contour_renderer = fig.contour(x, y, get_z(0), levels, fill_color=PiYG,
line_color="black", line_width=*5 +  + *5)

colorbar = contour_renderer.construct_color_bar()

```

To run this on a Bokeh server use

```bokeh serve --show contour_animated.py
```

The key sequence of actions to perform the animation are:

1. Call `contour()` as usual, and store the returned `ContourRenderer`.

2. Determine the updated `z` array, which might be read from file or calculated, for example.

3. Pass the updated `z` and unchanged `x`, `y` and `levels` to `contour_data()` to generate a contour data object.

4. Call `set_data()` with the new contour data object.

5. Repeat from stage 2.

The animation example here assumes the grid, contour levels and visual properties are not changed. It is possible to do so, but care is needed to correctly deal with changing plot bounds and assignment of visual properties to contour levels, so it is usually easier to remove the old unwanted contour plot and replace it with a new one in these circumstances.

The only compulsory keyword arguments to `contour()` are `z`, `levels` and at least one of `fill_color` and `line_color`. `x` and `y` are optional and if not specified a Cartesian grid will be used with a grid spacing of 1 in both directions.
To exclude grid points from the contour calculation then either use a NumPy masked array for `z` with the excluded grid points masked out, or set the `z` values of those grid points to `np.nan`.
Contour lines are implemented using a `MultiLine` glyph and filled contour polygons as a `MultiPolygons` glyph with the `line_width` set to zero.
The calculation of contours is performed by `ContourPy`. For information about this see the ContourPy documentation.