
在 Windows 上用 Python 3.6 安装 Mayavi是很多做三维可视化的人绕不过去的一道坎。直接执行pip install mayavi大概率会看到一个超长的依赖解析过程然后在一串红色报错里结束换成 whl 方法把预编译好的安装包提前下载好再按顺序手动装整个过程反而顺畅得多。这篇文章就围绕“Windows Python 3.6 Mayavi 工具包”这个组合把 whl 方法的原理、版本匹配、完整操作步骤和踩坑记录都讲一遍适合不想折腾源码编译、只想尽快把 Mayavi 跑起来的开发者参考。1. 先别急着 pip installMayavi 在 Windows 上“装不上”的根源1.1 Mayavi 不是单个包而是一整条依赖链很多人第一次遇到 Mayavi是在搜“Python 三维可视化”的时候。它的上层接口mlab非常好用一行mlab.plot3d()就能画出三维曲线mlab.mesh()可以显示三维表面。但 Mayavi 本质上不是一个小工具它建立在 VTK 之上而 VTK 是一个用 C 写成的重量级可视化库。Mayavi 的完整依赖链大致是这样的最底层是 VTK负责三维图形渲染、网格计算和数据处理中间一层是 Enthought Tool Suite简称 ETS提供 traits 属性系统、traitsui 界面框架、pyface 跨平台 GUI 抽象最上层才是 Mayavi 的 mlab 接口也就是你平时敲的那些代码。这意味着当你执行pip install mayavi时pip 需要先解决 VTK、traits、traitsui、pyface、numpy、Qt 绑定这一大串依赖。问题恰恰出现在这里不是每个依赖在 Windows 上都有现成的二进制包不是每个包都愿意老老实实让你一键装完。1.2 一碰到源码编译Windows 就劝退大多数人pip 安装包的时候有两种来源一种是 wheel也就是预编译好的二进制包pip 只需要把文件解压到 site-packages 里另一种是 sdist也就是源代码包pip 需要在你的机器上现场编译。如果某个依赖只有源代码包pip 就会启动构建流程。对于纯 Python 包这通常没问题但一旦涉及 C/C 扩展模块Windows 上就是另一番景象了。VTK 这种体量的项目源码编译需要完整匹配的 MSVC 编译器、CMake 配置、Qt 头文件路径和 numpy 头文件版本任何一个环节不对都会当场报错。我自己见过最多的报错场景是卡在Installing build dependencies ...这一步等半天之后通知你编译失败。有些朋友为了装上 Mayavi甚至去折腾 Visual Studio Build Tools装完又发现编译出来的二进制和 Python 3.6 的 ABI 对不上。这个方向基本是死路尤其在依赖链这么长的情况下任何一个包编译失败都会让你前功尽弃。1.3 whl 方法的核心思路把安装控制权拿回自己手上whl 方法说白了就是提前去第三方预编译 wheel 仓库里找到与当前 Python 版本、系统架构匹配的那一批.whl文件然后手动用pip install 文件名.whl逐个安装。这样做有三个明显的好处绕开了源码编译所有包都是预编译好的装起来的体验跟装普通 Python 包一样轻松依赖版本、依赖顺序完全由你控制不会出现 pip 自动解析时“东拉西扯”的情况出了问题容易定位因为每一步都是手动执行的你知道是哪一步失败的。当然whl 方法也有它的要求你必须懂得看文件名的平台标记必须知道先装哪个后装哪个还得能处理一些历史版本之间的隐性冲突。别急这些我下面一个个展开。2. 动手前必须想明白的三件事版本、位数与 wheel 命名2.1 确认 Python 3.6 的位数和 pip 环境在 Mayavi 这个场景里第一个关键前提就是 Python 3.6 必须是 64 位。为什么因为第三方预编译 wheel 仓库里绝大多数科学计算包只提供 64 位 Windows 版本32 位 Python 几乎找不到对应的 VTK 和 Mayavi 包。先打开命令行依次执行这三条命令python --version pip --version python -c import struct; print(struct.calcsize(P) * 8)如果最后输出的是64说明你的 Python 是 64 位如果输出32建议你直接重装 64 位 Python 3.6不要在 32 位环境里继续挣扎。pip --version这一步很多人会忽略它其实非常关键。有时候你的系统里装了多个 Python比如 3.6 和 3.8 并存光标输入python进的是 3.6但pip可能指向另一个解释器。建议你直接看pip --version输出的解释器路径确保当前命令行里的 python 和 pip 是同一个环境。2.2 wheel 文件名就是说明书cp36 / cp36m / win_amd64 是什么拿到一个.whl文件时初学者最容易蒙圈因为文件名长得像乱码。其实每个字符都有含义。以这个经典命名为例Mayavi-4.7.1-cp36-cp36m-win_amd64.whl拆开来看Mayavi是包名4.7.1是版本号cp36表示该 wheel 专属支持 CPython 3.6cp36m表示 Python 解释器带了 pymalloc 和窄 Unicode 编译选项官方发布的 CPython 3.6 默认满足win_amd64表示目标平台是 64 位 Windows。有时候你会看到abi3这种标记它代表二进制接口兼容能在一个范围内的 Python 版本上通用。比如某些 VTK 版本会标注cp36 abi3看起来好像更灵活但在 Mayavi 这种老生态里我仍然倾向于选择明确标注cp36的版本兼容性风险最小。下载文件的时候对照你自己环境的三个信息包名、cp36、win_amd64。三者同时匹配基本不会出现“not a supported wheel on this platform”的报错。2.3 一套我实际验证过的依赖版本组合Mayavi 4.7.x 是支持 Python 3.6 的最后一代版本线2017 年之后新版 Mayavi 逐步转向更新的 Python但 4.7.1 在 Python 3.6 上运行很成熟。下面这套组合是我在 Windows 10 64 位 Python 3.6.8 的环境里验证过的软件包推荐版本说明numpy1.19.5最后一个支持 Python 3.6 的版本太高版本会出现接口不匹配PyQt55.15.2Qt5 系ETS 通过 qt4 后端识别pyqt5-sip12.9.1与 PyQt5 5.15.2 配套的 sip 版本traits6.2.0ETS 的属性系统traitsui7.x带 cp36 标记与 Qt 界面集成pyface7.x带 cp36 标记ETS 通用 GUI 层VTK8.1.2 或 9.0.1主选 8.1.2兼容性最稳9.0.1 也能用Mayavi4.7.1顶层可视化主包严格来说第三方预编译仓库里的版本号可能和我这边略有出入。没关系规则是优先选带cp36标记、且和这个表属于同一代际的版本。宁可旧一点也别盲目上最新版因为最新版往往是为新 Python 编译的在 3.6 上反而不透明。3. 完整实操从空环境到跑通 Mayavi 可视化窗口3.1 先建一个干净的虚拟环境我强烈建议你用一个独立的虚拟环境来干这件事而不是直接往系统 Python 里塞。原因很现实Mayavi 对 numpy 版本非常敏感如果你后面再装别的项目依赖很可能把 numpy 升上去结果 Mayavi 就罢工了。用虚拟环境隔离可以把这个环境下所有包的版本关系锁死。创建环境并激活python -m venv D:\py36_mayavi_env D:\py36_mayavi_env\Scripts\activate.bat激活成功后命令行提示符前面会多出一个(py36_mayavi_env)这就是环境生效的标志。接着升级一下 pippython -m pip install --upgrade pip21.3.1为什么要固化成 21.3.1因为这是 Python 3.6 支持的最后一个 pip 版本。更高版本的 pip 已经放弃对 Python 3.6 的支持装新 pip 反而可能出现兼容问题。3.2 按顺序手动安装依赖别让 pip 自作主张所有依赖文件准备好之后进入它们的所在目录开始逐个安装。命令里有一个很关键的参数--no-deps。pip install --no-deps numpy-1.19.5-cp36-cp36m-win_amd64.whl pip install --no-deps pyqt5_sip-12.9.1-cp36-cp36m-win_amd64.whl pip install --no-deps PyQt5-5.15.2-cp36-cp36m-win_amd64.whl pip install --no-deps traits-6.2.0-cp36-cp36m-win_amd64.whl pip install --no-deps traitsui-7.2.0-cp36-cp36m-win_amd64.whl pip install --no-deps pyface-7.3.0-cp36-cp36m-win_amd64.whl pip install --no-deps VTK-8.1.2-cp36-cp36m-win_amd64.whl这里解释一下--no-deps的作用如果不加这个参数pip 在安装某个 whl 时会检查它的依赖是否已满足不满足就会去线上仓库自己找。一旦它找到一个不兼容 Python 3.6 的源包又开始编译那就回到刚开头的老路上了。把这些依赖挨个手动装齐最后 pip 就没什么需要“操心”的了路径完全由你把控。注意文件名必须以你实际下载的文件为准不要直接复制粘贴。比如 VTK 的版本是 8.1.2但文件名里可能带cp36-cp36m-win_amd64也可能带其他标记一切以文件名为准。3.3 安装 Mayavi 本体并设置 ETS_TOOLKIT依赖全部就位后最后安装 Mayavipip install --no-deps Mayavi-4.7.1-cp36-cp36m-win_amd64.whl装完先不要急着import mayavi有一个环境变量需要设置。ETS 这套体系在历史上对 Qt 后端沿用了一个非常容易误导人的名字qt4。就算你现在装的是 PyQt5ETS 仍然认qt4这个后端标识。所以在命令行里先设置set ETS_TOOLKITqt4如果你是用 PowerShell可以写成$env:ETS_TOOLKITqt4更稳妥的做法是在代码里 import 任何 mayavi 模块之前设置这个变量import os os.environ[ETS_TOOLKIT] qt4不设置的话ETS 可能默认去找 wx 或者其他后端报错会非常模糊比如Invalid toolkit或者找不到界面框架。3.4 用一段最小代码验证安装结果新建一个测试脚本比如test_mayavi.py写入下面的内容import os os.environ[ETS_TOOLKIT] qt4 import numpy as np from mayavi import mlab t np.linspace(0, 2 * np.pi, 100) x np.sin(t) y np.cos(t) z t mlab.plot3d(x, y, z, t, tube_radius0.1) mlab.show()运行它python test_mayavi.py如果一切正常屏幕上会弹出一个三维窗口一条螺旋曲线带着颜色映射出现在视野中你可以用鼠标拖动旋转视角。看到这个窗口说明 Mayavi 已经在这个 Python 3.6 环境里真正跑起来了。如果窗口没出现但终端也没有报错那问题多半出在 Qt 事件循环没有启动检查一下脚本最后是否调用了mlab.show()。4. 高发报错实录与排查顺序建议收藏4.1 报错速查表现象、原因与解决方向我在不同机器上装过很多次 Mayavi踩过的坑基本可以集中成下面这张表报错现象常见原因处理思路not a supported wheel on this platformwheel 文件名与当前 Python 版本或位数不匹配确认 Python 是 64 位文件名里同时有cp36和win_amd64ModuleNotFoundError: No module named vtkVTK 没真正装进当前环境用pip list查看激活正确环境后重装ImportError: DLL load failed: 找不到指定的模块VTK 与 numpy 版本不匹配或缺少运行库换 numpy 1.19.5安装对应 VC 运行库RuntimeError: Invalid toolkit qt4没有安装 PyQt5或 ETS_TOOLKIT 设错安装 PyQt5 5.15.2 与 pyqt5-sip确认环境变量值AttributeError: module numpy has no attribute floatnumpy 版本太新在 Python 3.6 上强制降回 1.19.5窗口能弹出但黑屏或卡死OpenGL 驱动或渲染后端问题更新显卡驱动关闭虚拟机的 3D 加速尝试不同 VTK 版本4.2 最容易骗人的两个坑Qt4 后端和 numpy 版本先说 Qt4 后端。很多同学装完 PyQt5 后觉得“我 Qt5 都装好了你还想怎样”结果一运行报Invalid toolkit qt4。这里要理解一个历史背景ETS 的 pyface 框架定义 Qt 后端时用了qt4这个名称但它并不绑定 Qt4 的库而是把 PyQt4、PyQt5 甚至 PySide 都抽象在同一个后端里。因此你装 PyQt5ETS 依然以qt4来识别只是底层加载的是 PyQt5 的模块。再说 numpy 版本。Python 3.6 的生命周期末期numpy 官方最后提供的支持版本就是 1.19.5。如果你在这套环境里不小心装了 numpy 1.20 以上的版本VTK 在加载 C 扩展时可能出现 DLL 加载失败而且报错信息很可能只指向 vtk 模块完全没提 numpy。遇到这种情况我的第一反应永远是先看 numpy 版本强制降回 1.19.5 再试一次。4.3 实在装不上时我按这个顺序排查如果上面的步骤都走完还是不行不要慌按下面的顺序一点点缩小范围确认当前解释器和环境变量。执行python -c import sys; print(sys.version, sys.maxsize 2**32)看到3.6.x和True才是正确环境。确认 pip 指向的也是同一个解释器。执行pip --version看路径是否还在你的虚拟环境里。按依赖顺序逐个导入包用最直接的方式确认失败现场python -c import numpy; print(numpy.__version__) python -c import PyQt5; print(PyQt5.__version__) python -c import vtk; print(vtk.__version__) python -c import traits; print(traits.__version__) python -c import traitsui; print(traitsui.__version__) python -c import pyface; print(pyface.__version__)哪一行报错就先把问题限定在那个包上用pip uninstall清掉后重新选择兼容版本安装。前面全部通过之后最后再试from mayavi import mlab。如果失败仔细看堆栈的末尾到底是从 vtk 层报的错、traits 层报的错还是 Qt 层报的错。定位到具体层级后再回到上面的速查表。按这个顺序排查绝大多数问题都会在第二步或第三步暴露出来比漫无目的地重装要高效得多。最后分享一点我在多次安装后的体会Mayavi 这种老牌 ETS 生态组件真正卡人的往往不是 Mayavi 本身而是依赖版本的一致性。只要把 Python 位数、wheel 标记、安装顺序、Qt 后端这四件事一次做对整个安装过程其实不超过十五分钟。如果你以后还需要在别的机器上复现这套环境把今天记下来的版本组合和这条命令序列存成一份笔记会比现场翻文档省太多时间。