python - 如何在 Azure Devops 上的 ubuntu 镜像中为 matplotlib 使用 TkAgg 后端?

标签 python matplotlib ubuntu tkinter azure-devops

我的 matplotlib 代码在 Azure DevOps 的 ubuntu VM 中失败;而相同的代码适用于 Azure Windows VM 和我自己的 ubuntu VM。这个简化的 Azure 管道 YAML 重现了这个问题:

trigger:
- none

pool:
  vmImage: ubuntu-18.04

variables:
  python.version: '3.7'

steps:
- task: UsePythonVersion@0
  inputs:
    versionSpec: '$(python.version)'
    addToPath: true
  displayName: 'Use Python $(python.version)'

- bash: |
    pip install --upgrade pip &&
    pip install matplotlib &&
    pip list
  displayName: 'Install required packages'

- bash: |
    sudo apt-get install python3-tk
  displayName: 'Install Tcl/Tk GUI toolkit'

- task: PythonScript@0
  inputs:
    scriptSource: inline
    script: |
      import tkinter
      print('Tcl/Tk version: {}'.format(tkinter.Tcl().eval('info patchlevel')))
  displayName: 'Report Tcl/Tk version'

- task: PythonScript@0
  inputs:
    scriptSource: inline
    script: |
      import matplotlib
      import matplotlib.pyplot as plt
      
      print("Using: " + matplotlib.get_backend())
      
      plt.rcParams['toolbar'] = 'toolmanager'
      
      fig = plt.figure()
      ax = fig.add_subplot(111)
      
      tm = fig.canvas.manager.toolmanager
      tm.remove_tool('help')
  displayName: 'Remove help button from toolbar'
当管道运行时,它报告 VM 上安装了 matplotlib 3.5.2 和 Tcl/Tk 版本 8.6.8。但最后的任务失败了:
/home/vsts/work/_temp/5e3dce70-dff2-405e-b5ef-8dac88d22243.py:6: UserWarning: Treat the new Tool classes introduced in v1.5 as experimental for now; the API and rcParam may change in future versions.
  plt.rcParams['toolbar'] = 'toolmanager'
/home/vsts/work/_temp/5e3dce70-dff2-405e-b5ef-8dac88d22243.py:13: UserWarning: ToolManager does not control tool help
  tm.remove_tool('help')
Using: agg
Traceback (most recent call last):
  File "/home/vsts/work/_temp/5e3dce70-dff2-405e-b5ef-8dac88d22243.py", line 13, in <module>
    tm.remove_tool('help')
  File "/opt/hostedtoolcache/Python/3.7.12/x64/lib/python3.7/site-packages/matplotlib/backend_managers.py", line 210, in remove_tool
    tool.destroy()
AttributeError: 'NoneType' object has no attribute 'destroy'
注意 matplotlib 的打印后端是 agg而不是 TkAgg .运行 sudo apt-get install python3-tk 后,相同的 Python 代码在我自己的 ubuntu 18.04 VM 中工作,然后代码报告 TkAgg那里。
那么为什么这在 Azure DevOps 的 ubuntu 中不起作用呢?看起来 Tcl/Tk 没有在 ubuntu VM 中正确安装或配置。
更新
如果我插入 matplotlib.use('TkAgg')import matplotlib 之后那么输出会说 Using: TkAgg .但我在 fig = plt.figure() 收到此错误线:
ImportError: Cannot load backend 'TkAgg' which requires the 'tk' interactive framework, as 'headless' is currently running
我也尝试设置环境变量 DISPLAY 和 MPLBACKEND,但无济于事。

最佳答案

事实证明,我需要为 Tcl/Tk 创建一个虚拟显示器,以便在远程 Azure DevOps VM 上正常工作。我用了Xvfb ,因为它已经安装在 ubuntu 18.04 代理上(根据 here )。您还需要设置 DISPLAY指向虚拟显示器的环境变量。这最终对我有用:

trigger:
- none

pool:
  vmImage: ubuntu-18.04

variables:
  python.version: '3.7'

steps:
- task: UsePythonVersion@0
  inputs:
    versionSpec: '$(python.version)'
    addToPath: true
  displayName: 'Use Python $(python.version)'

- bash: |
    pip install matplotlib &&
    pip list
  displayName: 'Install required packages'

- task: PythonScript@0
  inputs:
    scriptSource: inline
    script: |
      import tkinter
      print('Tcl/Tk version: {}'.format(tkinter.Tcl().eval('info patchlevel')))
  displayName: 'Report Tcl/Tk version'

- bash: |
    Xvfb :1 -screen 0 640x480x16 &
  displayName: 'Create virtual display'

- bash: |
    echo "##vso[task.setvariable variable=DISPLAY]:1.0"
  displayName: 'Set DISPLAY'

- task: PythonScript@0
  inputs:
    scriptSource: inline
    script: |
      import matplotlib
      import matplotlib.pyplot as plt
      
      print("Using: " + matplotlib.get_backend())
      
      plt.rcParams['toolbar'] = 'toolmanager'
      
      fig = plt.figure()
      ax = fig.add_subplot(111)
      
      tm = fig.canvas.manager.toolmanager
      tm.remove_tool('help')
  displayName: 'Remove help button from toolbar'
最终任务的输出是:
/home/vsts/work/_temp/b7d18caa-56d0-4438-9d8c-b6bbaa04935b.py:10: UserWarning: Treat the new Tool classes introduced in v1.5 as experimental for now; the API and rcParam may change in future versions.
  plt.rcParams['toolbar'] = 'toolmanager'
Using: TkAgg
注意 matplotlib 会自动检测 TkAgg 后端;你不必告诉它使用它。两个让我大吃一惊的陷阱: Xvfb 以大写 X 开头;并确保在后台运行它!

关于python - 如何在 Azure Devops 上的 ubuntu 镜像中为 matplotlib 使用 TkAgg 后端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72112080/

相关文章:

python - 检查函数是否属于一个类

python - 面向对象访问matplotlib中的fill_between阴影区域

node.js - 错误 : npm update

docker - 无法从外部访问暴露的 docker 端口

python - 为什么此数据存储为字符串而不是 float ? (Python)

python - 如何在直方图 bin 中获取数据

在 mayavi 场景窗口关闭之前,Python 脚本不会继续

python - 如何暂停 for 循环并等待用户输入 matplotlib

linux - 如何使 Unix 二进制文件自包含?

python - 是否有任何对象可以使 str() 函数在 python 中抛出错误或异常?