等高线图#

等高线图用于在二维四边形网格中计算和渲染恒定值的线。可以使用单个函数调用来渲染线和线之间的填充区域。

简单示例#

以下是一个简单示例,它渲染等高线和填充的多边形区域。

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()
p.add_layout(colorbar, "right")

show(p)

按照惯例,z 是要生成等高线的二维数组,它定义在 xy 网格上。这里,网格是一个等间距的笛卡尔网格。 levels 包含要生成等高线的级别序列。

line_colorfill_color 都是 contour() 的可选关键字参数。必须指定 line_color 来绘制等高线,并指定 fill_color 来绘制填充的等高线多边形。它们可以是标量或向量视觉属性。

注意

等高线的向量视觉属性的长度为 len(levels),而填充的等高线多边形的长度为 len(levels)-1

在此示例中,line_color 是一个标量,因此每条等高线都以黑色实线渲染。 fill_color 是一个向量,因此等高线级别之间的填充区域以不同的颜色渲染。

在图的右侧有一个颜色条,它使用 construct_color_bar() 获得。它会自动显示与等高线图相同的填充和线视觉属性。

极坐标网格示例#

以下是一个更复杂的示例,它展示了等高线图的其他可用功能。

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))
x = radius*np.cos(angle)
y = radius*np.sin(angle)
z = 1 + np.sin(3*angle)*np.sin(np.pi*radius)

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=[1]*6 + [2]*5,
)

colorbar = contour_renderer.construct_color_bar(title="Colorbar title")
p.add_layout(colorbar, "right")

show(p)

网格是极坐标网格,它本身环绕,并且还有许多其他视觉属性,包括 linefillhatch 属性。其中许多是向量属性,因此可以突出显示例如正负等高线级别。

所有视觉属性都可以是标量或具有正确长度的向量。颜色视觉属性 line_colorfill_colorhatch_color 支持一些额外的选项来指定它们的方式。

  • 比所需长度更长或更短的颜色序列将使用 interp_palette() 进行重采样。长度为 256 的调色板(例如 Cividis256)在这里很有用。

  • 可以使用调色板集合,例如 Cividis,它是一个字典,将调色板长度(颜色数量)映射到调色板。如果集合包含具有正确长度的调色板,则使用该调色板。如果所需长度超出集合中可用的长度,则使用最接近长度的调色板并进行线性插值。

construct_color_bar() 接受其他关键字参数,这些参数将传递给 ContourColorBar 构造函数以设置属性,例如此处显示的 title

动画等高线#

Bokeh 可以使用 bokeh serve 生成动画等高线图,因为等高线计算在 Python 中进行。以下是一个来自 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)
    for amp, xmid, ymid, rad in zip(amps, xmids, ymids, rads):
        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=[1]*5 + [3] + [1]*5)

colorbar = contour_renderer.construct_color_bar()
fig.add_layout(colorbar, 'right')

curdoc().add_periodic_callback(callback, 40)
curdoc().add_root(fig)

要在 Bokeh 服务器上运行此代码,请使用

bokeh serve --show contour_animated.py

执行动画的关键步骤序列为

  1. 像往常一样调用 contour(),并将返回的 ContourRenderer 存储起来。

  2. 确定更新后的 z 数组,该数组可能来自文件读取或计算而来。

  3. 将更新后的 z 和未更改的 xylevels 传递给 contour_data() 以生成等高线数据对象。

  4. 使用新的等高线数据对象调用 set_data()

  5. 从步骤 2 重复。

此处的动画示例假设网格、等高线级别和视觉属性没有改变。可以这样做,但需要小心处理更改的绘图边界并将视觉属性分配给等高线级别,因此在这些情况下,通常更容易删除旧的无用等高线图并用一个新的替换它。

高级细节#

contour() 的唯一必需关键字参数是 zlevels 以及 fill_colorline_color 中的至少一个。 xy 是可选的,如果未指定,则将使用笛卡尔网格,网格间距在两个方向上均为 1。

要从等高线计算中排除网格点,可以使用 z 的 NumPy 掩码数组,将排除的网格点掩盖,或者将这些网格点的 z 值设置为 np.nan

等高线使用 MultiLine 符号实现,填充的等高线多边形使用 MultiPolygons 符号实现,line_width 设置为零。

等高线的计算由 ContourPy 执行。有关此内容的信息,请参阅 ContourPy 文档

注意

Bokeh 版本 3.0 中添加了等高线功能,并且计划在未来的版本中进行改进。