Как изменить график networkx в Python?

Поэтому я создал действительно наивный (вероятно, неэффективный) способ создания диаграмм Хассе.

Вопрос:

У меня есть 4 измерения... p q r s .

Я хочу отобразить его равномерно (tesseract), но я понятия не имею, как его изменить. Как изменить график networkx в Python?

Я видел несколько примеров людей, использующих spring_layout() и draw_circular(), но это не соответствует тому, что я ищу, потому что они неоднородны.

Есть ли способ изменить форму моего графика и сделать его однородным? (например, преобразовать мою диаграмму Хассе в форму тессеракта (предпочтительно с использованием nx.draw() )

Вот как сейчас выглядит мой: введите здесь описание изображения

Вот мой код для создания диаграммы hasse 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() 

Я хочу изменить его форму следующим образом: введите здесь описание изображения

Если кто-то знает более простой способ создания диаграмм Хассе, поделитесь мудростью, но это не основная цель этого поста.


person O.rka    schedule 07.06.2015    source источник
comment
Изменяя k из shell_layout, вы можете получить менее сложенный график. При значении 0,48 я получаю что-то читаемое, но не очень близкое к вашим ожиданиям.   -  person Cyrbil    schedule 14.06.2015
comment
Привет @cyrbil, я думаю, что должен быть способ получить координаты N-мерной 2D-проекции, поскольку это, по сути, то, что происходит с nx.hypercube_graph(3)   -  person O.rka    schedule 15.06.2015
comment
Дайте мне знать в комментариях, если вам нужно что-то еще / что-то, что неясно в моем ответе. В противном случае - получайте удовольствие от визуализации - буду признателен за принятие :)   -  person J Richard Snape    schedule 17.06.2015


Ответы (1)


Это прагматический, а не чисто математический ответ.

Я думаю, у вас две проблемы - одна с макетом, другая с вашей сетью.

1. Сеть

В вашей сети слишком много ребер, чтобы она могла представлять единичный тессеракт. Предостережение Я не эксперт по математике здесь - просто пришел к этому с точки зрения построения графика (тег matplotlib). Пожалуйста, объясните, если я ошибаюсь.

Ваша желаемая проекция и, например, страница wolfram mathworld с диаграммой Хассе для n=4 имеет только 4 ребра соединяют все узлы, тогда как у вас есть 6 ребер с 2-мя и 7 ребер с 3-битными узлами. Ваш график полностью соединяет каждый уровень, т. е. 4-мерные векторы с 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 выше, они по-прежнему будут иметь вашу граничную структуру, поэтому они не будут выглядеть точно так же, как примеры из Интернета. Вот как это выглядит с вашим существующим кодом генерации сети - вы можете увидеть дополнительные ребра, если сравните его с вашим примером (например, я не думаю, что этот pr должен быть подключен к pqs:

Проекция «Два куба»

Проекция тессеракта, сгенерированная кодом

Пример проекции Викимедиа

Альтернативная проекция тессеракта, созданная с помощью предоставленного кода


Примечание

Если вы хотите углубиться в математику создания собственных прогнозов (и построения pos математически), вы можете посмотреть данный исследовательский документ.


РЕДАКТИРОВАТЬ:

Любопытство взяло верх надо мной, и мне пришлось искать математический способ сделать это. Я нашел этот блог — главный результат которого матрица проекции:

Матрица проецирования 4D в 2D

Это побудило меня разработать эту функцию для проецирования каждой метки, взяв метку, содержащую «p», как означающую, что точка имеет значение 1 на оси «p», т.е. мы имеем дело с единичным тессерактом. Таким образом:

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)

Дает красивую проекцию в обычный двумерный восьмиугольник со всеми отдельными точками.

Это будет работать в вышеуказанной программе, просто замените

 pos[label] = example_projection_coords[i]

с

pos[label] = construct_projection(label)

Это дает результат:

проекция на восьмиугольник

играй с r1,r2,theta и phi сколько душе угодно :)

person J Richard Snape    schedule 17.06.2015
comment
вау, это было невероятно полезно J! это то, что я искал, и я не могу отблагодарить вас за то, что вы нашли время. я действительно думаю, что это будет иметь невероятную ценность для сообщества. - person O.rka; 18.06.2015
comment
В вашей сети слишком много ребер, я этого не уловил! просто исправил ошибку. нужно было использовать all() вместо set.intersect() - person O.rka; 18.06.2015