使用 pydot 的紧凑图形可视化
Compact graph-vizualization using pydot
我想可视化一个“线性”有向图,其布局如下:
所有入度和出度都是1(当然第一个和最后一个除外)。标签的长度不同,所以我无法轻松计算出一行或另一行适合多少个节点。我目前的代码是这样的。
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
G = nx.DiGraph()
G.add_node("XYZ 1.0")
for i in range(1, 20):
G.add_node(f'XYZ 1.{i}', style='filled', fillcolor='skyblue')
G.add_edge(f'XYZ 1.{i-1}', f'XYZ 1.{i}')
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
prog = 'dot'
file_name = f'nx_graph_{prog}.png'
pydt.write(file_name, prog=prog, format="png")
到目前为止我在一个需要运行在Pythondocker容器中的项目中使用networkx
,所以我想使用pydot
和 Networkx
,如果可能的话。
在一些 graphviz 程序中,如果我理解正确的话,我可以设置坐标,但是对于设置坐标,我应该知道框的宽度以避免框重叠。
我设法找到了一种使用 pydot 执行此操作的方法。我们可以使用 write_dot
函数创建一个带有坐标的点文件。回读它,我们可以获得 dot
程序创建的坐标(以及宽度和高度)。我们可以以某种方式计算新坐标并在 networkx
有向图中修改它们。再次转换为 pydot.Dot
对象,最后,我们可以使用 neato
和 -n
选项来创建图形,这样我们就可以使用我们设置的坐标。可以在下面看到一个工作代码。
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
import pydot
from typing import List
G = nx.DiGraph()
G.add_node(0, label="XYZ 1.0")
for i in range(1, 20):
G.add_node(i, label=f'XYZ 1.{i}')
G.add_edge(i - 1, i)
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
dot_data = pydt.create_dot()
pydt2 = pydot.graph_from_dot_data(dot_data.decode('utf-8'))[0]
def get_position(node):
pydot_node = pydt2.get_node(str(node))[0]
return [float(i) for i in pydot_node.get_attributes().get("pos")[1:-1].split(',')]
def fix_position(position: List, w: float = 1000, shift: float = 80):
x_orig, y_orig = position
n = int(x_orig / w)
y = y_orig - n * shift
remain_x = x_orig - n * w
if n % 2 == 0:
x = remain_x
else:
x = w - remain_x
return x, y
def refresh_coordinates_using_x():
for node in G.nodes:
position = get_position(node)
x, y = fix_position(position)
pos = f'"{x},{y}!"'
G.nodes[node]['pos'] = pos
refresh_coordinates_using_x()
pydt3 = to_pydot(G)
file_name = f'nx_graph_neato.png'
pydt3.write(file_name, prog=["neato", "-n"], format="png")
如果您想根据宽度计算节点的位置,您需要知道坐标以磅为单位,而宽度以英寸为单位。 1英寸是72分。
结果将与此类似。
我想可视化一个“线性”有向图,其布局如下:
所有入度和出度都是1(当然第一个和最后一个除外)。标签的长度不同,所以我无法轻松计算出一行或另一行适合多少个节点。我目前的代码是这样的。
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
G = nx.DiGraph()
G.add_node("XYZ 1.0")
for i in range(1, 20):
G.add_node(f'XYZ 1.{i}', style='filled', fillcolor='skyblue')
G.add_edge(f'XYZ 1.{i-1}', f'XYZ 1.{i}')
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
prog = 'dot'
file_name = f'nx_graph_{prog}.png'
pydt.write(file_name, prog=prog, format="png")
到目前为止我在一个需要运行在Pythondocker容器中的项目中使用networkx
,所以我想使用pydot
和 Networkx
,如果可能的话。
在一些 graphviz 程序中,如果我理解正确的话,我可以设置坐标,但是对于设置坐标,我应该知道框的宽度以避免框重叠。
我设法找到了一种使用 pydot 执行此操作的方法。我们可以使用 write_dot
函数创建一个带有坐标的点文件。回读它,我们可以获得 dot
程序创建的坐标(以及宽度和高度)。我们可以以某种方式计算新坐标并在 networkx
有向图中修改它们。再次转换为 pydot.Dot
对象,最后,我们可以使用 neato
和 -n
选项来创建图形,这样我们就可以使用我们设置的坐标。可以在下面看到一个工作代码。
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
import pydot
from typing import List
G = nx.DiGraph()
G.add_node(0, label="XYZ 1.0")
for i in range(1, 20):
G.add_node(i, label=f'XYZ 1.{i}')
G.add_edge(i - 1, i)
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
dot_data = pydt.create_dot()
pydt2 = pydot.graph_from_dot_data(dot_data.decode('utf-8'))[0]
def get_position(node):
pydot_node = pydt2.get_node(str(node))[0]
return [float(i) for i in pydot_node.get_attributes().get("pos")[1:-1].split(',')]
def fix_position(position: List, w: float = 1000, shift: float = 80):
x_orig, y_orig = position
n = int(x_orig / w)
y = y_orig - n * shift
remain_x = x_orig - n * w
if n % 2 == 0:
x = remain_x
else:
x = w - remain_x
return x, y
def refresh_coordinates_using_x():
for node in G.nodes:
position = get_position(node)
x, y = fix_position(position)
pos = f'"{x},{y}!"'
G.nodes[node]['pos'] = pos
refresh_coordinates_using_x()
pydt3 = to_pydot(G)
file_name = f'nx_graph_neato.png'
pydt3.write(file_name, prog=["neato", "-n"], format="png")
如果您想根据宽度计算节点的位置,您需要知道坐标以磅为单位,而宽度以英寸为单位。 1英寸是72分。
结果将与此类似。