簡體   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