简体   繁体   English

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

[英]How to use TkAgg backend for matplotlib in ubuntu image on Azure Devops?

My matplotlib code is failing in ubuntu VMs in Azure DevOps;我的 matplotlib 代码在 Azure DevOps 的 ubuntu 虚拟机中失败; whereas the same code works in Azure Windows VMs and on my own ubuntu VM.而相同的代码适用于 Azure Windows VM 和我自己的 ubuntu VM。 This boiled-down Azure pipeline YAML reproduces the issue:这个简化的 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'

When the pipeline runs, it reports matplotlib 3.5.2 and Tcl/Tk version 8.6.8 are installed on the VM.当管道运行时,它报告 matplotlib 3.5.2 和 Tcl/Tk 版本 8.6.8 安装在 VM 上。 But the final task fails with:但最后的任务失败了:

/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'

Note the printed backend for matplotlib is agg rather than TkAgg .请注意 matplotlib 的打印后端是agg而不是TkAgg The same Python code works in my own ubuntu 18.04 VM after running sudo apt-get install python3-tk , and the code then reports TkAgg there.在运行sudo apt-get install python3-tk后,相同的 Python 代码在我自己的 ubuntu 18.04 VM 中运行,然后代码在那里报告TkAgg

So why doesn't this work in ubuntu in Azure DevOps?那么,为什么这在 Azure DevOps 中的 ubuntu 中不起作用? It looks like Tcl/Tk is not being installed or configured properly in the ubuntu VM.看起来 Tcl/Tk 没有在 ubuntu VM 中正确安装或配置。

Update If I insert matplotlib.use('TkAgg') after import matplotlib then the output does say Using: TkAgg .更新如果我在import matplotlib之后插入matplotlib.use('TkAgg')那么 output 会说Using: TkAgg But I get this error instead at the fig = plt.figure() line:但是我在fig = plt.figure()行得到了这个错误:

ImportError: Cannot load backend 'TkAgg' which requires the 'tk' interactive framework, as 'headless' is currently running

I've tried setting the environment variables DISPLAY and MPLBACKEND as well, but to no avail.我也尝试设置环境变量 DISPLAY 和 MPLBACKEND,但无济于事。

It turns out I needed to create a virtual display for Tcl/Tk to work correctly on the remote Azure DevOps VMs.事实证明,我需要为 Tcl/Tk 创建一个虚拟显示,以便在远程 Azure DevOps VM 上正常工作。 I used Xvfb , as that's already installed on the ubuntu 18.04 agent (as per here ).我使用了Xvfb ,因为它已经安装在 ubuntu 18.04 代理上(根据此处)。 You also need to set the DISPLAY environment variable to point at the virtual display.您还需要将DISPLAY环境变量设置为指向虚拟显示器。 Here's what worked for me in the end:这最终对我有用:

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'

The output of the final task was then:最终任务的 output 是:

/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

Note matplotlib automatically detects the TkAgg backend;注matplotlib自动检测TkAgg后端; you don't have to tell it to use it.你不必告诉它使用它。 Two gotchas that caught me out: Xvfb starts with a capital X;有两个问题让我很困惑:Xvfb 以大写字母 X 开头; and make sure you run it in the background!并确保你在后台运行它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM