Cómo cambiar la forma de un gráfico networkx en Python?


Así que creé una forma muy ingenua (probablemente ineficiente) de generar diagramas de hasse.

Pregunta:

Tengo 4 dimensiones... p q r s .

Quiero mostrarlo uniformemente (teseracto) pero no tengo idea de cómo remodelarlo. ¿Cómo se puede remodelar un gráfico de networkx en Python?

He visto algunos ejemplos de personas usando spring_layout() y draw_circular() pero no forma en el lo estoy buscando porque no son uniformes.

¿Hay alguna manera de remodelar mi gráfico y hacerlo uniforme? (es decir, remodelar mi diagrama de hasse en forma de teseracto (preferiblemente usando nx.draw())

Así es como se ven las mías actualmente: introduzca la descripción de la imagen aquí

Aquí está mi código para generar el diagrama de hasse de N dimensiones

#!/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() 

Quiero remodelarlo de esta manera: introduzca la descripción de la imagen aquí

Si alguien conoce una manera más fácil de hacer Diagramas de Hasse, por favor comparta algo de sabiduría pero ese no es el objetivo principal de este post.

Author: O.rka, 2015-06-07

1 answers

Esta es una respuesta pragmática, más que puramente matemática.

Creo que tiene dos problemas: uno con el diseño, el otro con su red.

1. Red

Tiene demasiados bordes en su red para que represente el teseracto de la unidad. Advertencia No soy un experto en matemáticas aquí, solo llegué a esto desde el ángulo de trazado (etiqueta matplotlib). Por favor, explícame si me equivoco.

Su proyección deseada y, por ejemplo, la wolfram mathworld la página para un diagrama Hasse para n=4 tiene solo 4 aristas conectadas a todos los nodos, mientras que usted tiene 6 aristas a los nodos de 2 y 7 aristas a los nodos de 3 bits. Su gráfico conecta completamente cada" nivel", es decir, los vectores 4-D con valores 0 1 se conectan a todos los vectores con valores 1 1, que luego se conectan a todos los vectores con valores 2 1 y así sucesivamente. Esto es más obvio en la proyección basada en la respuesta de Wikipedia (2a imagen de abajo)

2. Proyección

No pude encontrar un algoritmo o biblioteca preescrita para proyectar automáticamente el teseracto 4D en un plano 2D, pero encontré un par de ejemplos, por ejemplo, Wikipedia . A partir de esto, puede elaborar un conjunto coordinado que le convenga y pasarlo a la llamada nx.draw().

Aquí hay un ejemplo: he incluido dos conjuntos coordinados, uno que se parece a la proyección que muestra arriba, uno que coincide con este de wikipedia.

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() 

Nota-a menos que cambie lo que he mencionado en 1. arriba, todavía tienen su estructura de borde, por lo que no se verán exactamente igual que los ejemplos de la web. Esto es lo que se ve con su código de generación de red existente: puede ver los bordes adicionales si lo compara con su ejemplo (por ejemplo, I don't this pr should be connected to pqs:

Proyección'Dos cubos'

Proyección de teseracto generado por código

Proyección de ejemplo de Wikimedia

Proyección alternativa del teseracto generado por el código proporcionado


Nota

Si quieres entrar en las matemáticas de hacer sus propias proyecciones (y la construcción de pos matemáticamente), usted podría mirar este documento de investigación.


EDITAR:

La curiosidad me sacó lo mejor de mí y tuve que buscar una forma matemática de hacer esto. He encontrado este blog - el resultado principal de los cuales es la matriz de proyección:

Matriz de proyección 4D a 2D

Esto me llevó a desarrollar esta función para proyectar cada etiqueta, tomando la etiqueta que contiene ' p 'para significar que el punto tiene valor 1 en la 'p' axis, es decir, estamos tratando con la unidad teseracto. Así:

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)

Da una buena proyección en un octágono 2D regular con todos los puntos distintos.

Esto se ejecutará en el programa anterior, simplemente reemplace

 pos[label] = example_projection_coords[i]

Con

pos[label] = construct_projection(label)

Esto da el resultado:

proyección sobre un octágono

Juega con r1,r2,theta y phi para el contenido de su corazón:)

 13
Author: J Richard Snape,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-17 20:46:31