
Bokeh 布局系统完全指南用 row、column、gridplot 与 sizing modes 构建响应式数据仪表盘【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokehBokeh 在浏览器中渲染交互式数据可视化而布局layout系统正是把多个图plot与控件widget组织成仪表盘和数据应用的关键。本文以官方用户指南 layouts.rst 为骨架系统讲解内置布局函数column、row、gridplot、layout的用法并结合仓库源码逐一剖析七种 sizing modes 的行为与适用场景帮助你在实际项目中快速搭建自适应浏览器窗口的复杂界面。布局系统概览Bokeh 的布局系统提供一组高阶函数用来把任意数量的 plot 与 widget 组合成行、列或网格。文档在开头即点明其设计目标Layout functions let you build a grid of plots and widgets. You can have as many rows, columns, or grids of plots in one layout as you like. Bokeh layouts also allow for a number of sizing options, or modes. These modes allow plots and widgets to resize to fit the browser window.所有布局函数都定义在 src/bokeh/layouts.py 中统一接收UIElement图、控件、Row、Column、Spacer 等作为子元素。从源码看row()与column()的签名完全对称都支持“位置参数逐个传入”或“单个列表传入”两种调用方式并接受可选的sizing_mode与透传给底层模型的**kwargsdef row(*children: UIElement | list[UIElement], sizing_mode: SizingModeType | None None, **kwargs: Any) - Row def column(*children: UIElement | list[UIElement], sizing_mode: SizingModeType | None None, **kwargs: Any) - Column值得一提的细节是源码注释明确写到row/column会强制所有子对象使用相同的 sizing_modeForces all objects to have the same sizing_mode, which is required for complex layouts to work这也是复杂嵌套布局能够稳定工作的前提。内置布局函数Column 布局纵向排列需要把图或控件垂直堆叠时使用column。官方示例 vertical.py 创建了三个 250×250 的散点图然后通过show(column(s1, s2, s3))纵向展示from bokeh.layouts import column from bokeh.plotting import figure, show x list(range(11)) y0 x y1 [10 - i for i in x] y2 [abs(i - 5) for i in x] # create three plots s1 figure(width250, height250, background_fill_color#fafafa) s1.scatter(x, y0, size12, color#53777a, alpha0.8) s2 figure(width250, height250, background_fill_color#fafafa) s2.scatter(x, y1, size12, markertriangle, color#c02942, alpha0.8) s3 figure(width250, height250, background_fill_color#fafafa) s3.scatter(x, y2, size12, markersquare, color#d95b43, alpha0.8) # put the results in a column and show show(column(s1, s2, s3))Row 布局横向排列需要水平并排时使用row。示例 horizontal.py 与上面的代码几乎一致仅最后一行改为show(row(s1, s2, s3))。两个函数可以直接互换便于快速尝试不同的排布方向。gridplot绘图专用网格gridplot专门用于把多个plot排成网格其核心特性是把所有子图的工具tools合并进一个父级工具栏网格中的每个图共享同一个激活工具。其完整签名见 src/bokeh/layouts.pydef gridplot( children: list[UIElement | None] | list[list[UIElement | None]], *, sizing_mode: SizingModeType | None None, toolbar_location: LocationType | None above, ncols: int | None None, width: int | None None, height: int | None None, toolbar_options: dict[ToolbarOptions, Any] | None None, merge_tools: bool True, ) - GridPlot关键参数说明childrenplot 的列表或“列表的列表”二维网格。想在某个位置留空直接传None即可。ncols如果传入扁平的 plot 列表用ncols指定列数源码内部会调用_chunks(children, ncols)自动重排为二维网格此时若传入嵌套列表会抛出ValueError。width/height统一设置网格中所有图的宽高源码在item.width width、item.height height处逐个覆盖。toolbar_location工具栏相对网格的位置默认above设为None则不显示工具栏。merge_tools默认True合并所有子图工具设为False则每个图保留自己的工具栏。toolbar_options字典用于定制合并后工具栏的属性如logo、autohide、active_drag等。示例 grid.py 展示了“2×2 网格中留一个空位”的写法from bokeh.layouts import gridplot from bokeh.plotting import figure, show # ... 创建 s1、s2、s3 三个散点图 ... # make a grid grid gridplot([[s1, s2], [None, s3]], width250, height250) show(grid)而 grid_convenient.py 展示了便捷写法——只传扁平列表加ncols同样可以附带统一尺寸grid gridplot([s1, s2, s3], ncols2, width250, height250)从源码 src/bokeh/layouts.py 看merge_toolsTrue时的合并过程相当精细先遍历子图收集所有Toolbar把每个 plot 的toolbar_location置为None隐藏各自工具栏再用group_tools(tools, mergemerge)把同类型工具聚合成ToolProxy可同时作用于所有子图并将多个子图竞争性的logo、autohide、active_drag、active_inspect等属性通过assert_unique收敛为最终值——这正是“所有图共享同一个激活工具”的底层实现。layout通用网格布局当需要同时混排 plot 与 widget 时使用layout函数。它接收“列表的列表”形式的二维网格并自动把每一行包装成row、整体包装成column省去手动嵌套的麻烦。文档中的经典示例sliders column(amp, freq, phase, offset) layout([ [bollinger], [sliders, plot], [p1, p2, p3], ])完整可运行版本见 dashboard.py它把“布林带图 滑块控制的正弦波图 三个联动平移散点图”组合成一个grid(...)仪表盘。其中滑块组件通过column(amp, freq, phase, offset, sizing_modestretch_width)排成一列四个滑块分别控制振幅、频率、相位与偏移并通过CustomJS回调实时重算正弦曲线l grid([bollinger(), slider(), linked_panning()], sizing_modestretch_both)layout函数在源码中同样支持传sizing_mode参数作用于整个网格文档原图dashboard 效果图可在仓库 docs/bokeh/source/_images 目录中查看。补充说明仓库还提供了更底层的 grid() 函数返回GridBox模型它支持三种模式嵌套列表、嵌套 Row/Column 实例、扁平列表加nrows/ncols并可自动计算跨行跨列坐标如grid([p1, [[p2, p3], p4]])会生成(p1, 0, 0, 1, 2)这样的 span 元组。日常开发中layout()的自动包装足够用grid()适合需要精细控制合并单元格的场景。深入理解 sizing modes七种模式的行为定义sizing_mode是LayoutDOM上的一个属性定义于 src/bokeh/models/layouts.py枚举值定义在 src/bokeh/core/enums.py 中共七个值加一个inherit。官方文档给出的语义如下模式行为fixed组件保持自身宽高不随浏览器窗口变化stretch_width填充可用宽度不保持宽高比高度依组件类型而定可能贴合内容或固定stretch_height填充可用高度不保持宽高比宽度依组件类型而定stretch_both同时填充可用宽度与高度不保持宽高比scale_width填充可用宽度保持原始或指定宽高比scale_height填充可用高度保持原始或指定宽高比scale_both同时填充宽高保持原始或指定宽高比使用要点根据模式不同可能需要显式提供width和/或height。例如stretch_width模式下组件没有固定高度来源必须指定一个固定的height文档原话you have to specify a fixed height when using thestretch_widthmode。row/column等容器会把自身的 sizing_mode共享给所有未显式设置模式的子组件。这也解释了 sizing_mode_multiple.py 中为何要为每个子组件单独声明模式——一旦容器设置了模式未声明者会自动继承。从源码层面看LayoutDOM.sizing_mode 的帮助文档进一步说明了优先级关系sizing_mode是高层便捷设置底层还有更细粒度的width_policy、height_policy与aspect_ratio属性一旦显式设置了这些底层策略它们优先于sizing_mode生效。因此如果你的需求超出七种模式的表达能力例如“宽度可伸缩但不超过 600px”可以直接改用 policy 类属性做微调。此外源码中的_check_min_preferred_max_width等校验逻辑表明min_width/max_width/min_height/max_height会与固定尺寸共同参与最终尺寸的钳制。单对象响应式演示sizing_mode.py 提供了一个交互式演示通过下拉框实时切换单个图的 sizing mode直观观察图在不同容器中的伸缩行为from bokeh.core.enums import SizingMode from bokeh.layouts import column, row from bokeh.models import Div, Select from bokeh.plotting import figure, show p figure(sizing_modefixed) p.scatter(flipper_length_mm, body_mass_g, sourcedata, fill_alpha0.4, size12, colorfactor_cmap(species, Category10_3, data.species.unique())) div Div(textSelect a sizing mode to see how a plot resizes inside a parent container.) select Select(titleSizing mode, valuefixed, optionslist(SizingMode), width300) select.js_link(value, p, sizing_mode) container row(p, height800, sizing_modestretch_width) container.stylesheets.append(:host { border: 10px solid grey; }) layout column(div, select, container) layout.sizing_mode stretch_both # set separately to avoid also setting children show(layout)该示例有几个值得注意的实践细节select.js_link(value, p, sizing_mode)用js_link把下拉框的value属性与图的sizing_mode直接联动无需编写任何 JavaScript 回调。先组合再单独设置容器模式示例刻意在column(...)构造完成后再赋值layout.sizing_mode stretch_both注释明确说明这是为了“avoid also setting children”——避免模式被传播到子组件与文档“容器共享模式给未显式设置的子组件”的规则完全对应。给容器加视觉边框通过container.stylesheets.append(:host { border: 10px solid grey; })注入 CSS便于肉眼观察图的伸缩边界。文档同时给出一个重要的使用警告如果外层 DOM 元素没有定义可填充的确定高度那些需要向高度方向 scale/stretch 的模式可能把图压缩到最小尺寸。也就是说stretch_height、stretch_both、scale_height、scale_both这类依赖高度的模式要求父级容器具备明确的高度例如通过height参数或 CSS 指定否则浏览器无法确定“可用高度”到底是多少。多对象嵌套布局实战sizing_mode_multiple.py 是文档重点讲解的“典型复杂嵌套布局”展示了四种模式在同一布局中共存的完整写法# plot scales to original aspect ratio based on available width plot figure(y_range(-10, 10), width400, height200, background_fill_color#fafafa, sizing_modestretch_both) plot.line(x, y, sourcesource, line_width3, line_alpha0.6) # slider fills all space available to it amp Slider(start0.1, end10, value1, step.1, titleAmplitude, sizing_modestretch_both) freq Slider(start0.1, end10, value1, step.1, titleFrequency, sizing_modestretch_both) phase Slider(start0, end6.4, value0, step.1, titlePhase, sizing_modestretch_both) offset Slider(start-5, end5, value0, step.1, titleOffset, sizing_modestretch_both) # fixed sized for the entire column widgets column(amp, freq, phase, offset, sizing_modefixed, height250, width150) # heading fills available width heading Div(sizing_modestretch_width, height80, textIn this wave example, the sliders on the left can be used to change the amplitude, frequency, phase, and offset of the wave.) # entire layout fills all space available to it layout column(heading, row(widgets, plot), sizing_modestretch_both) show(layout)这个布局的层次结构是最外层column(heading, row(widgets, plot))以stretch_both充满整个页面 → 内部row分为“固定宽度滑块列 弹性绘图区” → 滑块列用fixed固定为 150×250 → 四个滑块各自stretch_both平分列内空间。整个应用还通过CustomJS实现了滑块驱动正弦曲线实时更新的联动效果是一份“布局 交互”结合的完整范本。布局系统的边界与替代方案文档明确提醒Bokeh 布局系统不是全能的布局引擎。它在设计上刻意牺牲了一部分能力以换取常见场景仪表盘、数据应用的简洁表达。具体而言同一布局中混用大量不同 sizing mode 时可能在性能与视觉表现两方面都不理想需要高度定制化设计如杂志式版式、任意定位、复杂响应式断点时不应强行用 Bokeh 布局堆叠。官方给出的替代路径是使用ug_output_embed主题下的嵌入 APIbokeh.embed模块把图或组件嵌入到自有的 HTML 模板中由你自己的 CSS 负责页面排版从而借助更成熟的 CSS 布局能力flexbox、grid 等实现更复杂的版式。这也符合 Bokeh“把布局交给浏览器 CSS 引擎”的边界划分Bokeh 布局解决“图与控件的组合排列”自定义 CSS 解决“页面的整体视觉设计”。仓库中 examples/basic/layouts/css_layouts.py 与 examples/basic/layouts/custom_layout.py 正是这一思路的延伸示例展示了如何结合自定义 CSS 或定制 DOM 结构来突破内置布局的表达范围可供进阶参考。小结Bokeh 的布局体系由两条主线构成组合函数column、row、gridplot、layout负责把 plot 与 widget 组织成行、列、网格sizing modes七种模式负责让组件随浏览器窗口自适应缩放。掌握gridplot的工具合并机制、layout的自动行列包装、以及“容器模式会传播给子组件、底层 policy 优先于 sizing_mode”这两条源码级规则就能从“能用”进阶到“用得准”快速搭建出专业的响应式数据仪表盘。官方指南docs/bokeh/source/docs/user_guide/basic/layouts.rst布局函数实现src/bokeh/layouts.py模式枚举定义src/bokeh/core/enums.py组件基类与模式校验src/bokeh/models/layouts.py配套示例examples/basic/layoutsvertical.py、horizontal.py、grid.py、grid_convenient.py、dashboard.py、sizing_mode.py、sizing_mode_multiple.py【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考