Menu

#873 tulip-python crashes when headless: "QPixmap: Must construct a QApplication before a QPaintDevice"

3.5.x
open
nobody
None
5
2018-08-06
2018-08-03
No

I use tulip for rendering graphs to png and svg. The script reads a gexf, creates a view, applies algorithms, saves a png screenshot and exports a svg. It works fine when I use it from my desktop envrironment. I use the createNodeLinkDiagramView(g, show=False), so the script works without any displayed windows. It should therefore also work in a headless environment.

But when executed in a headless environment, it crashes.
The minimal complete example below shows the bug. First we create a LXD container, then we install tulip via pip3. When loading the c++ plugins, the interpreter crashes.

# lxc launch ubuntu:18.04
# lxc exec close-manatee bash
root@close-manatee:~# apt install python3-pip
root@close-manatee:~# pip3 install --upgrade pip
root@close-manatee:~# apt install libxrender1 libsm6 libgl1
root@close-manatee:~# python3 -m pip install tulipgui-python tulip-python
root@close-manatee:~# python3
Python 3.6.5 (default, Apr  1 2018, 05:46:30) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tulipgui
>>> import tulip
>>> tulip.tlp.loadPlugins()
QPixmap: Must construct a QApplication before a QPaintDevice
Aborted (core dumped)
root@close-manatee:~# 

Can you help me debug this problem? Am I missing dependencies?

Discussion

  • Patrick Mary

    Patrick Mary - 2018-08-06

    Most of the Tulip gui plugins (views, interactors, perspectives) needs a QApplication to be instantiated, so they cannot be loaded without a previously existing QApplication. By the way, saving a png screenshot from a node-link diagram view also needs a QApplication object which in turn needs to connect to an X server when instantiated on Linux. So from my point of view it cannot works in an headless environment.

     
  • jim_jom@web.de

    jim_jom@web.de - 2018-08-06

    Thanks for your reply. I managed to get it somewhat working in LXD/Docker by using Xvfb and installing tons of dependencies (probably more than needed).
    The script imports the GEXF, creates a hidden node-link window and then exports a PNG - which is working fine. The final PNG file contains the picture just like I need it.

    But somehow the SVG export still segfaults. Do you know if the SVG Export module is different to the PNG export in any way? How can I narrow down why it is faulting?

    The Dockerfile:

    FROM python:3.6
    
    RUN mkdir /graphs
    VOLUME /graphs
    
    RUN apt-get update && apt-get install -y libgl1 tulip libtulip-core-4.8 libtulip-dev libtulip-gui-4.8 libtulip-ogdf-4.8 libtulip-ogl-4.8 libtulip-python-4.8 libxrender1 libsm6 libgl1 xvfb libegl1-mesa libegl1-mesa-drivers libgl1-mesa-dri libgl1-mesa-glx libglapi-mesa libgles2-mesa libglu1-mesa mesa-utils
    
    COPY mylib.whl /tmp/
    RUN pip3 install /tmp/mylib.whl # also installs Python dependencies
    
    CMD rm -f /tmp/.X1-lock && Xvfb :1 -screen 0 1024x768x24 +extension GLX +render -noreset & DISPLAY=:1 python3 -m "mylib.graph_to_image"
    

    The script:

    if "GEXF" not in tlp.getImportPluginsList():
        tlp.loadPlugins() # segfault here was mitigated by installing tons of packages via apt-get
    assert("GEXF" in tlp.getImportPluginsList())
    
    importedgraph = tlp.importGraph("GEXF", { "filename" : "/tmp/graph.gexf" })
    
    # Layout FM^3
    viewLayout = importedgraph.getLayoutProperty("viewLayout")
    params = tlp.getDefaultPluginParameters("FM^3 (OGDF)", importedgraph)
    importedgraph.applyLayoutAlgorithm("FM^3 (OGDF)", viewLayout, params)
    
    # Show graph info in the view
    viewport = tlpgui.createNodeLinkDiagramView(importedgraph, show=False)
    pars = viewport.getRenderingParameters()
    pars.setViewArrow(True)
    pars.setViewEdgeLabel(True)
    pars.setViewNodeLabel(True)
    pars.setLabelsDensity(100)
    pars.setLabelScaled(True)
    viewport.setRenderingParameters(pars)
    
    # Save PNG
    viewport.saveSnapshot("/tmp/graph.png", png_width, png_height)
    PIL.Image.open("/tmp/graph.png").save("/tmp/graph.png", format="PNG", optimize=True, compress_level=9)
    
    # Save SVG
    params = tlp.getDefaultPluginParameters("SVG Export", importedgraph)
    params["Edge extremities"] = True
    params["Makes SVG output human readable"] = False
    params["Export edge labels"] = True
    tlp.exportGraph('SVG Export', importedgraph, "/tmp/graph.svg", params ) # Segfault still happens
    
     
  • Patrick Mary

    Patrick Mary - 2018-08-06

    The saveSnapshort feature makes a rendering of the graph layout in a QPixmap used to create a QImage which then will be saved in a png file. While the "SVG export" works directly from the Tulip graph structure to describe the graph layout in the svg format; and so some layout properties values may not be properly handled.

     
  • jim_jom@web.de

    jim_jom@web.de - 2018-08-06

    The ExportSvg.cpp has been changed May 2018. The PyPi Package is from November 2017. Maybe the bug is already fixed.

    Do you work on getting Tulip 5.2 into PyPi?

     

Log in to post a comment.

MongoDB Logo MongoDB