【问题标题】:Is there an interactive graphing library for python是否有用于 python 的交互式图形库
【发布时间】:2011-04-22 20:46:30
【问题描述】:

我正在寻找 Python 的交互式图形库。

graph”是指由一组顶点连接的一组节点(不是 x-y 轴上的值图,也不是像素网格)。

通过“交互式”,我的意思是我可以拖放节点,我需要能够单击节点/顶点并让库将节点/顶点传递给我的回调,这可能会添加/删除节点/顶点或显示信息(由于数据集太大/复杂,我无法在启动时加载完整图表;相反,我将根据用户输入仅加载必要的数据切片)。

我所说的 Python 是指编程语言 Python,图形库应该具有 CPython 绑定。我有 Python 2.7 和 Python 3.1,但如有必要可以降级到 2.6。这种语言要求是因为我正在使用的数据集只有 Python 绑定。

图形库必须支持directed graph,并且能够自动布局节点。我需要在节点上贴标签。

最好,布局算法应该将相邻节点放置在彼此附近。它应该能够在我 4 岁的笔记本电脑中合理地处理 100-1000 个节点和大约 300-4000 个顶点(我通常从大约 100 个节点开始,但数量可能会根据用户输入而扩大)。最好它应该是一个没有太多依赖项的库(可能除了 Gnome)。开源是首选。

我已经使用 Tkinter Canvas 编写了我的程序的简单原型,但是我需要一个更严肃的图形库来扩展程序。我看过graphviz和matplotlib,但显然它们仅用于处理静态图,显然需要大量工作来进行交互式操作(如果我错了,请纠正我,我只是简单地看了它们) .我还尝试将图形生成为 SVG 文件并使用 Inkscape 来查看它,但它太慢且占用太多内存,而且由于顶点数量众多,它变得一团糟。

【问题讨论】:

    标签: python graph interactive


    【解决方案1】:

    看起来 Nodebox 可能是你想要的:

    http://nodebox.net/code/index.php/Graph Mac OSX

    http://www.cityinabottle.org/nodebox/ Windows(使用 OpenGL)

    图形对象也具有鼠标交互功能,捆绑 在graph.events 对象中。它有 以下属性:

    • graph.events.hovered: None 或鼠标悬停的节点。
    • graph.events.pressed:None或者鼠标所在的节点 按下。
    • graph.events.dragged: None 或者被拖动的节点。
    • graph.events.clicked: None 或最后点击的节点。
    • graph.events.popup:当True时,会在 悬停的节点。

    Gephi 也遇到过,看起来可能也有你想要的功能。

    http://gephi.org/ WindowsLinuxMac OSX

    Gephi 是一种交互式可视化 各类探索平台 网络和复杂系统, 动态和层次图。

    【讨论】:

      【解决方案2】:

      如果你还没有,你绝对应该看看 igraph 库。

      这是一个功能强大的库,可以处理大型图表和不同的布局样式。根据features 的列表,它还可用于有向图以及 2D 和 3D 中的交互式和非交互式可视化。还有一个tutorial

      更新:另一个著名的库是NetworkX,其中有Python 包here。请注意,Acorn 推荐的 Mac/Windows 软件 Nodebox 使用 NetworkX 算法。

      【讨论】:

      • igraph 的 tkplot 显然在其 Python 绑定中不可用,据我所见。
      【解决方案3】:

      我也有同样的问题。 最后,我认为 nodebox opengl 似乎可以解决问题。 请勿尝试使用以下链接中的图库

      http://nodebox.net/code/index.php/Graph

      使用 nodebox opengl。它不起作用,该图形库仅与 mac OSX nodebox 兼容。但无论如何这没关系,因为你不需要它。

      例如看下面的问题:

      Adding label to an edge of a graph in nodebox opnegl

      它显示了适用于我的示例代码,可以修改代码,以便单击节点不仅可以移动节点,还可以修改图形。

      直接删除

      label = "Placeholder"
      

      从代码中,它可以工作。

      编辑:

      我在这里放了一些更详细的示例代码: Nodebox open GL Graph, size function not recognized. (Ubuntu)

      【讨论】:

        【解决方案4】:

        我思考并尝试了这个问题中给出的所有解决方案,最终得到了以下解决方案。

        我认为最好的可扩展解决方案是使用 Matplotlib 的交互模式和 networkx。以下代码段解释了如何为鼠标单击显示数据点的注释。由于我们使用的是 Networkx,因此该解决方案的可扩展性远超预期。

        import networkx as nx
        import matplotlib.pyplot as plt
        import nx_altair as nxa
        from pylab import *
        
        class AnnoteFinder:  # thanks to http://www.scipy.org/Cookbook/Matplotlib/Interactive_Plotting
            """
            callback for matplotlib to visit a node (display an annotation) when points are clicked on.  The
            point which is closest to the click and within xtol and ytol is identified.
            """
            def __init__(self, xdata, ydata, annotes, axis=None, xtol=None, ytol=None):
                self.data = list(zip(xdata, ydata, annotes))
                if xtol is None: xtol = ((max(xdata) - min(xdata))/float(len(xdata)))/2
                if ytol is None: ytol = ((max(ydata) - min(ydata))/float(len(ydata)))/2
                self.xtol = xtol
                self.ytol = ytol
                if axis is None: axis = gca()
                self.axis= axis
                self.drawnAnnotations = {}
                self.links = []
        
            def __call__(self, event):
                if event.inaxes:
                    clickX = event.xdata
                    clickY = event.ydata
                    print(dir(event),event.key)
                    if self.axis is None or self.axis==event.inaxes:
                        annotes = []
                        smallest_x_dist = float('inf')
                        smallest_y_dist = float('inf')
        
                        for x,y,a in self.data:
                            if abs(clickX-x)<=smallest_x_dist and abs(clickY-y)<=smallest_y_dist :
                                dx, dy = x - clickX, y - clickY
                                annotes.append((dx*dx+dy*dy,x,y, a) )
                                smallest_x_dist=abs(clickX-x)
                                smallest_y_dist=abs(clickY-y)
                                print(annotes,'annotate')
                            # if  clickX-self.xtol < x < clickX+self.xtol and  clickY-self.ytol < y < clickY+self.ytol :
                            #     dx,dy=x-clickX,y-clickY
                            #     annotes.append((dx*dx+dy*dy,x,y, a) )
                        print(annotes,clickX,clickY,self.xtol,self.ytol )
                        if annotes:
                            annotes.sort() # to select the nearest node
                            distance, x, y, annote = annotes[0]
                            self.drawAnnote(event.inaxes, x, y, annote)
        
            def drawAnnote(self, axis, x, y, annote):
                if (x, y) in self.drawnAnnotations:
                    markers = self.drawnAnnotations[(x, y)]
                    for m in markers:
                        m.set_visible(not m.get_visible())
                    self.axis.figure.canvas.draw()
                else:
                    t = axis.text(x, y, "%s" % (annote), )
                    m = axis.scatter([x], [y], marker='d', c='r', zorder=100)
                    self.drawnAnnotations[(x, y)] = (t, m)
                    self.axis.figure.canvas.draw()
        
        df = pd.DataFrame('LOAD YOUR DATA')
        
        # Build your graph
        G = nx.from_pandas_edgelist(df, 'from', 'to')
        pos = nx.spring_layout(G,k=0.1, iterations=20)  # the layout gives us the nodes position x,y,annotes=[],[],[] for key in pos:
        x, y, annotes = [], [], []
        for key in pos:
            d = pos[key]
            annotes.append(key)
            x.append(d[0])
            y.append(d[1])
        
        fig = plt.figure(figsize=(10,10))
        ax = fig.add_subplot(111)
        ax.set_title('select nodes to navigate there')
        
        nx.draw(G, pos, font_size=6,node_color='#A0CBE2', edge_color='#BB0000', width=0.1,
                          node_size=2,with_labels=True)
        
        
        af = AnnoteFinder(x, y, annotes)
        connect('button_press_event', af)
        
        show()
        

        【讨论】:

          猜你喜欢
          • 2012-05-17
          • 1970-01-01
          • 2017-09-03
          • 1970-01-01
          • 2011-01-22
          • 2018-04-28
          • 2011-03-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多