Как изменить граф networkx в Python?
поэтому я создал действительно наивный (вероятно, неэффективный) способ генерации диаграмм Хассе.
вопрос:
у меня есть 4 измерения... p
q
r
s
.
Я хочу отобразить его равномерно (Тессеракт), но я понятия не имею, как его изменить. как можно изменить граф networkx в Python?
Я видел несколько примеров людей, использующих spring_layout()
и draw_circular()
но он не формируется так, как я ищу, потому что они не однородны.
есть ли способ изменить мой график и сделать его однородным? (т. е. изменить мою диаграмму Хассе в форму Тессеракта (предпочтительно с помощью nx.draw()
)
вот как выглядит мой в настоящее время:
вот мой код для создания диаграммы Хассе из N измерений
#!/usr/bin/python
import networkx as nx
import matplotlib.pyplot as plt
import itertools
H = nx.DiGraph()
axis_labels = ['p','q','r','s']
D_len_node = {}
#Iterate through axis labels
for i in xrange(0,len(axis_labels)+1):
#Create edge from empty set
if i == 0:
for ax in axis_labels:
H.add_edge('O',ax)
else:
#Create all non-overlapping combinations
combinations = [c for c in itertools.combinations(axis_labels,i)]
D_len_node[i] = combinations
#Create edge from len(i-1) to len(i) #eg. pq >>> pqr, pq >>> pqs
if i > 1:
for node in D_len_node[i]:
for p_node in D_len_node[i-1]:
#if set.intersection(set(p_node),set(node)): Oops
if all(p in node for p in p_node) == True: #should be this!
H.add_edge(''.join(p_node),''.join(node))
#Show Plot
nx.draw(H,with_labels = True,node_shape = 'o')
plt.show()
Я хочу изменить его вроде этого:
если кто-нибудь знает более простой способ сделать диаграммы Хассе, пожалуйста поделиться какой-то мудростью но это не главная цель этого поста.
1 ответов
это прагматический, а не чисто математический ответ.
Я думаю, у вас есть две проблемы - одна с макетом, другая с вашей сетью.
1. Сеть
у вас слишком много ребер в вашей сети, чтобы она представляла собой единицу Тессеракт. предостережение я не эксперт по математике здесь-просто пришел к этому с угла построения (тег matplotlib). Пожалуйста, объясните, если я ошибаюсь.
нужный проекция и, например,вольфрам mathworld страница для диаграммы Хассе для n=4 имеет только 4 ребра, связанные со всеми узлами, в то время как у вас есть 6 ребер к 2 и 7 ребрам к 3-битным узлам. Ваш график полностью соединяет каждый "уровень", т. е. 4-D векторы с 0 1
значения соединяются со всеми векторами с 1 1
значение, которое затем соединяется со всеми векторами с 2 1
ценности и так далее. Это наиболее очевидно в проекции, основанной на ответе Википедии (2-е изображение ниже)
2. Проекция
я не смог найти заранее написанный алгоритм или библиотеку для автоматического проецирования 4D Тессеракта на 2D-плоскость, но я нашел пару примеров,например, в Википедии. Из этого вы можете разработать набор координат, который подойдет вам, и передать это в nx.draw()
звонок.
вот пример-я включил два набора координат, один из которых выглядит как проекция, которую вы показываете выше, один, который соответствует это из Википедии.
import networkx as nx
import matplotlib.pyplot as plt
import itertools
H = nx.DiGraph()
axis_labels = ['p','q','r','s']
D_len_node = {}
#Iterate through axis labels
for i in xrange(0,len(axis_labels)+1):
#Create edge from empty set
if i == 0:
for ax in axis_labels:
H.add_edge('O',ax)
else:
#Create all non-overlapping combinations
combinations = [c for c in itertools.combinations(axis_labels,i)]
D_len_node[i] = combinations
#Create edge from len(i-1) to len(i) #eg. pq >>> pqr, pq >>> pqs
if i > 1:
for node in D_len_node[i]:
for p_node in D_len_node[i-1]:
if set.intersection(set(p_node),set(node)):
H.add_edge(''.join(p_node),''.join(node))
#This is manual two options to project tesseract onto 2D plane
# - many projections are available!!
wikipedia_projection_coords = [(0.5,0),(0.85,0.25),(0.625,0.25),(0.375,0.25),
(0.15,0.25),(1,0.5),(0.8,0.5),(0.6,0.5),
(0.4,0.5),(0.2,0.5),(0,0.5),(0.85,0.75),
(0.625,0.75),(0.375,0.75),(0.15,0.75),(0.5,1)]
#Build the "two cubes" type example projection co-ordinates
half_coords = [(0,0.15),(0,0.6),(0.3,0.15),(0.15,0),
(0.55,0.6),(0.3,0.6),(0.15,0.4),(0.55,1)]
#make the coords symmetric
example_projection_coords = half_coords + [(1-x,1-y) for (x,y) in half_coords][::-1]
print example_projection_coords
def powerset(s):
ch = itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s)+1))
return [''.join(t) for t in ch]
pos={}
for i,label in enumerate(powerset(axis_labels)):
if label == '':
label = 'O'
pos[label]= example_projection_coords[i]
#Show Plot
nx.draw(H,pos,with_labels = True,node_shape = 'o')
plt.show()
Примечание - Если вы не измените то, что я сказал в 1. выше они все еще имеют вашу структуру edge, поэтому не будут выглядеть точно так же, как примеры из интернета. Вот как это выглядит с вашим существующим кодом генерации сети - вы можете увидеть дополнительные ребра, если сравните его с вашим примером (например, я не это pr
должен быть подключен к pqs
:
пример проекции Викимедиа
Примечание
если вы хотите попасть в математику делать свои собственные проекции (и строить pos
математически), вы можете посмотреть в данной научной работе.
EDIT:
любопытство взяло верх надо мной и мне пришлось искать математический способ, чтобы сделать это. Я нашел этот блог - главный результат чего быть матрицей проекции:
это привело меня к разработке этой функции для проецирования каждой метки, принимая метку, содержащую "p", чтобы означать, что точка имеет значение 1 на оси "p", т. е. мы имеем дело с единицей tesseract. Таким образом:
def construct_projection(label):
r1 = r2 = 0.5
theta = math.pi / 6
phi = math.pi / 3
x = int( 'p' in label) + r1 * math.cos(theta) * int('r' in label) - r2 * math.cos(phi) * int('s' in label)
y = int( 'q' in label) + r1 * math.sin(theta) * int('r' in label) + r2 * math.sin(phi) * int('s' in label)
return (x,y)
дает хорошую проекцию в регулярный 2D восьмиугольник со всеми точками.
это будет работать в вышеуказанной программе, просто заменить
pos[label] = example_projection_coords[i]
С
pos[label] = construct_projection(label)
это дает результат:
сыграет с r1
,r2
,theta
и phi
к вашему сердцу содержание:)