繁体   English   中英

是否有用于 python 的交互式图形库

[英]Is there an interactive graphing library for python

我正在寻找一个用于 Python 的交互式图形库。

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

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

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

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

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

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

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

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

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

节点框截图

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

  • graph.events.hoveredNone或鼠标悬停的节点。
  • graph.events.pressedNone或鼠标按下的节点。
  • graph.events.draggedNone或被拖动的节点。
  • graph.events.clickedNone或最后一个节点被点击。
  • graph.events.popup :当True ,将在悬停的节点上显示一个弹出窗口。

也遇到了 Gephi,看起来它也可能具有您想要的功能。

http://gephi.org/ WindowsLinuxMac OSX

Gephi 是一个交互式可视化和探索平台,适用于各种网络和复杂系统、动态和分层图。

gephi 截图

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

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

更新:另一个著名的图书馆是NetworkX对于其中有Python包在这里 请注意,Acorn 推荐的 Mac/Windows 软件 Nodebox 使用 NetworkX 算法。

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

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

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

例如,请参阅以下问题:

在 nodebox opnegl 中向图的边添加标签

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

删除即可

label = "Placeholder"

从代码和它的工作原理。

编辑:

我在这里放了一些更详细的示例代码: Nodebox open GL Graph,无法识别大小函数。 (Ubuntu)

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

我认为最好的可扩展解决方案是将 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()

暂无
暂无

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

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