【问题标题】:How can I use matplotlib with igraph?如何将 matplotlib 与 igraph 一起使用?
【发布时间】:2016-03-21 15:42:49
【问题描述】:

如何在 python-igraph 中实现的现有图形中添加统计图形(图、轴、图表等)?我对 matplotlib 特别感兴趣,因为我有使用这个库的经验。

在我的例子中,igraph 被用于不同的布局选项。我当前的网络部分限制了 x 维度,而 y 由布局更改。我想在图表底部添加一个条形图,以列出与网络节点的 x 坐标相关的值的频率。

(我没有使用 scipy/ipython/pandas 库,反正还没有)

【问题讨论】:

    标签: python matplotlib igraph


    【解决方案1】:

    这不是一个完整的答案,但是作为评论发布太长了,所以我将其作为答案发布。随意扩展/编辑它。

    不久前(嗯,五年多以前)我尝试过将python-igraphmatplotlib 结合起来,总体结论是可以将两者结合起来,但方式相当复杂。

    首先,只有当您使用 Cairo 作为 matplotlib 的绘图后端时,该组合才有效,因为 python-igraph 使用 Cairo 作为图形绘图后端(并且它不支持任何其他绘图后端)。

    接下来,关键技巧是您可以以某种方式提取 Matplotlib 图形的 Cairo 曲面,然后将此曲面作为绘图目标传递给 igraph 的 plot() 函数 - 在这种情况下,igraph 不会创建单独的图形,而是刚开始在给定的表面上绘图。然而,在我尝试这个的时候,Matplotlib 中没有公共 API 可以从图形中提取开罗表面,所以我不得不求助于未记录的 Matplotlib 属性和函数,所以整个事情非常脆弱,它取决于很大程度上依赖于我使用的特定版本的 Matplotlib - 但它确实有效。

    整个过程总结在igraph-help邮件列表上的this thread。在线程中,我提供了以下 Python 脚本作为概念验证,为了完整起见,我将其复制在这里:

    from matplotlib.artist import Artist
    from igraph import BoundingBox, Graph, palettes
    
    class GraphArtist(Artist):
        """Matplotlib artist class that draws igraph graphs.
    
        Only Cairo-based backends are supported.
        """
    
        def __init__(self, graph, bbox, palette=None, *args, **kwds):
            """Constructs a graph artist that draws the given graph within
            the given bounding box.
    
            `graph` must be an instance of `igraph.Graph`.
            `bbox` must either be an instance of `igraph.drawing.BoundingBox`
            or a 4-tuple (`left`, `top`, `width`, `height`). The tuple
            will be passed on to the constructor of `BoundingBox`.
            `palette` is an igraph palette that is used to transform
            numeric color IDs to RGB values. If `None`, a default grayscale
            palette is used from igraph.
    
            All the remaining positional and keyword arguments are passed
            on intact to `igraph.Graph.__plot__`.
            """
            Artist.__init__(self)
    
            if not isinstance(graph, Graph):
                raise TypeError("expected igraph.Graph, got %r" % type(graph))
    
            self.graph = graph
            self.palette = palette or palettes["gray"]
            self.bbox = BoundingBox(bbox)
            self.args = args
            self.kwds = kwds
    
        def draw(self, renderer):
            from matplotlib.backends.backend_cairo import RendererCairo
            if not isinstance(renderer, RendererCairo):
                raise TypeError("graph plotting is supported only on Cairo backends")
            self.graph.__plot__(renderer.gc.ctx, self.bbox, self.palette, *self.args, **self.kwds)
    
    
    def test():
        import math
    
        # Make Matplotlib use a Cairo backend
        import matplotlib
        matplotlib.use("cairo.pdf")
        import matplotlib.pyplot as pyplot
    
        # Create the figure
        fig = pyplot.figure()
    
        # Create a basic plot
        axes = fig.add_subplot(111)
        xs = range(200)
        ys = [math.sin(x/10.) for x in xs]
        axes.plot(xs, ys)
    
        # Draw the graph over the plot
        # Two points to note here:
        # 1) we add the graph to the axes, not to the figure. This is because
        #    the axes are always drawn on top of everything in a matplotlib
        #    figure, and we want the graph to be on top of the axes.
        # 2) we set the z-order of the graph to infinity to ensure that it is
        #    drawn above all the curves drawn by the axes object itself.
        graph = Graph.GRG(100, 0.2)
        graph_artist = GraphArtist(graph, (10, 10, 150, 150), layout="kk")
        graph_artist.set_zorder(float('inf'))
        axes.artists.append(graph_artist)
    
        # Save the figure
        fig.savefig("test.pdf")
    
        print "Plot saved to test.pdf"
    
    if __name__ == "__main__":
        test()
    

    一个警告:我没有测试上面的代码,我现在不能测试它,因为我的机器上现在没有 Matplotlib。它曾经在五年前与当时的 Matplotlib 版本 (0.99.3) 一起工作。如果不进行重大修改,它现在可能无法运行,但它显示了总体思路,希望它不会太复杂而无法适应。

    如果您设法使它适合您,请随时编辑我的帖子。

    【讨论】:

    • 谢谢,除了需要将matplotlib.use("cairo.pdf") 交换为matplotlib.use("cairo") 之外,示例代码还可以工作。当我了解更多时,将继续努力并更新/接受。
    • 如果你使用matplotlib.use("cairo")...和print(...)而不是print ...当然,在python 3.5中运行这个效果很好。
    • 这很有帮助。我最终只使用了 cairo 和 igraph 中的绘图,但我也复制了它并将其作为示例运行。
    • 它适用于我,但不适用于分布在多个轴上的多个图表,仅适用于单个轴
    猜你喜欢
    • 2012-05-02
    • 2022-08-06
    • 2017-09-14
    • 2020-11-19
    • 1970-01-01
    • 2016-06-20
    • 2011-09-23
    • 2022-06-11
    • 2013-08-22
    相关资源
    最近更新 更多