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:
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:
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.
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 ejemplo de Wikimedia
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:
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:
Juega con r1
,r2
,theta
y phi
para el contenido de su corazón:)
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