Ejemplo n.º 1
0
def comps_to_nx_planar_embedding(components):
    """Set of connected planar graphs (possibly derived) to nx.PlanarEmbedding."""
    res = nx.PlanarEmbedding()
    for g in components:
        g = g.underive_all()
        g = g.to_planar_embedding(relabel=False)
        res = nx.PlanarEmbedding(nx.compose(res, g))
    # Relabel once all the components are in the same graph.
    # relabel_networkx(res)
    return res
Ejemplo n.º 2
0
 def test_missing_edge_orientation(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         embedding.add_edge(1, 2)
         embedding.add_edge(2, 1)
         # Invalid structure because the orientation of the edge was not set
         embedding.check_structure()
Ejemplo n.º 3
0
 def test_invalid_edge_orientation(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         embedding.add_half_edge_first(1, 2)
         embedding.add_half_edge_first(2, 1)
         embedding.add_edge(1, 3)
         embedding.check_structure()
Ejemplo n.º 4
0
 def test_not_fulfilling_euler_formula(self):
     embedding = nx.PlanarEmbedding()
     for i in range(5):
         for j in range(5):
             if i != j:
                 embedding.add_half_edge_first(i, j)
     embedding.check_structure()
Ejemplo n.º 5
0
 def test_not_fulfilling_euler_formula(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         for i in range(5):
             for j in range(5):
                 if i != j:
                     embedding.add_half_edge_first(i, j)
         embedding.check_structure()
def test_invalid_half_edge():
    with pytest.raises(nx.NetworkXException):
        embedding_data = {
            1: [2, 3, 4],
            2: [1, 3, 4],
            3: [1, 2, 4],
            4: [1, 2, 3]
        }
        embedding = nx.PlanarEmbedding()
        embedding.set_data(embedding_data)
        nx.combinatorial_embedding_to_pos(embedding)
Ejemplo n.º 7
0
def check_embedding_data(embedding_data):
    """Checks that the planar embedding of the input is correct"""
    embedding = nx.PlanarEmbedding()
    embedding.set_data(embedding_data)
    pos_fully = nx.combinatorial_embedding_to_pos(embedding, False)
    msg = "Planar drawing does not conform to the embedding (fully " "triangulation)"
    assert planar_drawing_conforms_to_embedding(embedding, pos_fully), msg
    check_edge_intersections(embedding, pos_fully)
    pos_internally = nx.combinatorial_embedding_to_pos(embedding, True)
    msg = "Planar drawing does not conform to the embedding (internal " "triangulation)"
    assert planar_drawing_conforms_to_embedding(embedding, pos_internally), msg
    check_edge_intersections(embedding, pos_internally)
Ejemplo n.º 8
0
def get_dual(primal):
    """
    Returns the dual of a planar embedding.

    Parameters
    ----------
    primal: nx.PlanarEmbedding

    Returns
    -------
    primal_faces: dict
        A dict whose values are lists representing facial walks of
        the primal and whose keys are its dual nodes.
    dual: nx.PlanarEmbedding
        The dual of the primal.
    dual_faces: dict
        A dict whose values are lists representing facial walks of
        the dual and whose keys are nodes of the primal.
    """
    if not isinstance(primal, nx.PlanarEmbedding):
        print("'primal' must be a planar embedding.")

    # Constracting the dual embedding of 'primal'.
    primal_faces = get_faces(primal)
    dual = nx.PlanarEmbedding()
    for tail, primal_face in primal_faces.items():
        # Define a clockwize rotation around tail in dual nodes.
        pre_head = None
        for i in range(len(primal_face)):
            u = primal_face[i]
            v = primal_face[(i + 1) % len(primal_face)]
            head = primal.edges[v, u]['dual_node']
            dual.add_half_edge_cw(tail, head, pre_head)
            pre_head = head
            primal.edges[v, u]['right_half_edge'] = (tail, head)
            dual.edges[tail, head]['dual_node'] = u
            dual.edges[tail, head]['right_half_edge'] = (u, v)

    # A face of 'dual' can be derived from
    # clockwize rotation around a node of 'primal'.
    dual.check_structure()
    dual_faces = {}
    for u in primal.nodes:
        dual_face = []
        for v in primal.neighbors_cw_order(u):
            dual_face.append(primal.edges[u, v]['right_half_edge'][0])
        dual_faces[u] = dual_face

    return primal_faces, dual, dual_faces
Ejemplo n.º 9
0
def convert_pos_to_embedding(G, pos):
    """
        Only straight line in G.
    """
    emd = nx.PlanarEmbedding()
    for node in G:
        neigh_pos = {
            neigh: (pos[neigh][0]-pos[node][0], pos[neigh][1]-pos[node][1]) for neigh in G[node]
        }
        neighbors_sorted = sorted(G.adj[node], key=lambda v: m.atan2(neigh_pos[v][1], neigh_pos[v][0]))  # counter clockwise
        last = None
        for neigh in neighbors_sorted:
            emd.add_half_edge_ccw(node, neigh, last)
            last = neigh
    emd.check_structure()
    return emd
def main():
    # Cycle graph

    _, embedding = nx.check_planarity(nx.cycle_graph(20))
    embedding_fully, _ = nx.triangulate_embedding(embedding, True)
    diff_fully = nx.Graph(list(embedding_fully.edges - embedding.edges))
    embedding_internal, _ = nx.triangulate_embedding(embedding, False)
    diff_internal = nx.Graph(list(embedding_internal.edges - embedding.edges))
    pos = nx.combinatorial_embedding_to_pos(embedding_fully)
    nx.draw(diff_fully, pos, alpha=0.5, width=1, style="dotted", node_size=30)
    nx.draw(embedding, pos, width=2 , node_size=30)
    plt.savefig("drawing_cycle_fully_triangulated.png", format="PNG")
    plt.show()

    pos = nx.combinatorial_embedding_to_pos(embedding_internal)
    nx.draw(diff_internal, pos, alpha=0.5, width=1, style="dotted", node_size=30)
    nx.draw(embedding, pos, width=2, node_size=30)
    plt.savefig("drawing_cycle_internally_triangulated.png", format="PNG")
    plt.show()

    # Other graph
    G = nx.Graph([(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (1, 4), (4, 3)])
    is_planar, embedding = nx.check_planarity(G)
    print(is_planar)
    embedding_fully, _ = nx.triangulate_embedding(embedding, True)
    diff_fully = nx.Graph(list(embedding_fully.edges - embedding.edges))
    embedding_internal, _ = nx.triangulate_embedding(embedding, False)
    diff_internal = nx.Graph(list(embedding_internal.edges - embedding.edges))
    pos = nx.combinatorial_embedding_to_pos(embedding_fully)
    nx.draw(diff_fully, pos, alpha=0.5, width=1, style="dotted", node_size=30)
    nx.draw(embedding, pos, width=2, node_size=30)
    plt.savefig("drawing_other_fully_triangulated.png", format="PNG")
    plt.show()

    pos = nx.combinatorial_embedding_to_pos(embedding_internal)
    nx.draw(diff_internal, pos, alpha=0.5, width=1, style="dotted", node_size=30)
    nx.draw(embedding, pos, width=2, node_size=30)
    plt.savefig("drawing_other_internally_triangulated.png", format="PNG")
    plt.show()

    embedding_data = {0: [36, 42], 1: [], 2: [23, 16], 3: [19], 4: [23, 17], 5: [45, 18], 6: [42, 29, 40], 7: [48, 26, 32], 8: [15, 44, 23], 9: [11, 27], 10: [39, 11, 32, 47, 26, 15], 11: [10, 9], 12: [41, 34, 35], 13: [48], 14: [28, 45], 15: [34, 8, 10], 16: [2, 39, 21], 17: [4], 18: [5], 19: [22, 3], 20: [], 21: [16, 49], 22: [26, 47, 19], 23: [8, 2, 4], 24: [46], 25: [], 26: [7, 34, 10, 22, 38], 27: [9, 48], 28: [36, 41, 14], 29: [6], 30: [48], 31: [], 32: [7, 10, 46], 33: [48], 34: [12, 15, 26], 35: [12, 41], 36: [0, 28, 43], 37: [47], 38: [26], 39: [16, 10], 40: [6], 41: [28, 12, 35], 42: [44, 0, 6], 43: [36], 44: [8, 42], 45: [14, 5], 46: [32, 24], 47: [22, 10, 37], 48: [27, 7, 13, 30, 33], 49: [21]}
    embedding = nx.PlanarEmbedding()
    embedding.set_data(embedding_data)
    pos = nx.combinatorial_embedding_to_pos(embedding, fully_triangulate=False)
    nx.draw(embedding, pos, node_size=30)
    plt.savefig("drawing_large_graph_internally_triangulated.png", format="PNG")
    plt.show()
Ejemplo n.º 11
0
 def get_planar_embedding(self):
     """only straight line in G."""
     emd = nx.PlanarEmbedding()
     for node in self.g:
         neigh_pos = {
             neigh: (self.pos[neigh][0] - self.pos[node][0],
                     self.pos[neigh][1] - self.pos[node][1])
             for neigh in self.g[node]
         }
         neighes_sorted = sorted(
             self.g.adj[node],
             key=lambda v: math.atan2(neigh_pos[v][1], neigh_pos[v][0]
                                      ))  # counter clockwise
         last = None
         for neigh in neighes_sorted:
             emd.add_half_edge_ccw(node, neigh, last)
             last = neigh
     emd.check_structure()
     return emd
Ejemplo n.º 12
0
def get_radial(primal):
    """
    Returns the dual and the radial of a planar embedding.
    The radial graph of a planar embedding G is also known as the vertex-face map
    whose vertices are the vertices of G together with the faces of G,
    and whose edges correspond to the vertex-face incidence in G.

    Parameters
    ----------
    primal: nx.PlanarEmbedding

    Returns
    -------
    dual: nx.PlanarEmbedding
        The dual of the primal.
    radial: nx.PlanarEmbedding
        The radial of the primal.
    """
    primal_faces, dual, dual_faces = get_dual(primal)
    radial = nx.PlanarEmbedding()
    for p in primal.nodes:
        p_name = 'p' + str(p)
        pre_d_name = None
        for d in dual_faces[p]:
            d_name = 'd' + str(d)
            radial.add_half_edge_cw(p_name, d_name, pre_d_name)
            pre_d_name = d_name
        radial.nodes[p_name]['primal'] = True
        radial.nodes[p_name]['original'] = p
    for d in dual.nodes:
        d_name = 'd' + str(d)
        pre_p_name = None
        for p in primal_faces[d]:
            p_name = 'p' + str(p)
            radial.add_half_edge_cw(d_name, p_name, pre_p_name)
            pre_p_name = p_name
        radial.nodes[d_name]['primal'] = False
        radial.nodes[d_name]['original'] = d
    radial.check_structure()
    return dual, radial
Ejemplo n.º 13
0
    def to_planar_embedding(self, relabel=True):
        """Converts to nx.PlanarEmbedding.

        Returns
        -------
        PlanarEmbedding
        """
        nodes = self.half_edge.node_dict()
        embedding = nx.PlanarEmbedding()
        # Loop over all nodes in the graph (node_nr).
        for node in nodes:
            embedding.add_node(node)
            # Loop over all half-edges incident the the current node, in ccw order around the node.
            reference_neighbour = None
            for he in nodes[node]:
                if he.opposite is None:
                    continue
                embedding.add_half_edge_ccw(node, he.opposite.node_nr,
                                            reference_neighbour)
                reference_neighbour = he.opposite.node_nr
        if relabel:
            relabel_networkx(embedding)
        return embedding
Ejemplo n.º 14
0
 def test_unsuccessful_face_traversal(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         embedding.add_edge(1, 2, ccw=2, cw=3)
         embedding.add_edge(2, 1, ccw=1, cw=3)
         embedding.traverse_face(1, 2)
Ejemplo n.º 15
0
 def test_successful_face_traversal(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_half_edge_first(1, 2)
     embedding.add_half_edge_first(2, 1)
     face = embedding.traverse_face(1, 2)
     assert face == [1, 2]
Ejemplo n.º 16
0
 def test_connect_components(self):
     embedding = nx.PlanarEmbedding()
     embedding.connect_components(1, 2)
Ejemplo n.º 17
0
 def test_missing_reference(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         embedding.add_half_edge_cw(1, 2, 3)
Ejemplo n.º 18
0
 def test_missing_half_edge(self):
     with pytest.raises(nx.NetworkXException):
         embedding = nx.PlanarEmbedding()
         embedding.add_half_edge_first(1, 2)
         # Invalid structure because other half edge is missing
         embedding.check_structure()
Ejemplo n.º 19
0
def triangulate_embedding(embedding, fully_triangulate=True):
    """Triangulates the embedding.

    Traverses faces of the embedding and adds edges to a copy of the
    embedding to triangulate it.
    The method also ensures that the resulting graph is 2-connected by adding
    edges if the same vertex is contained twice on a path around a face.

    Parameters
    ----------
    embedding : nx.PlanarEmbedding
        The input graph must contain at least 3 nodes.

    fully_triangulate : bool
        If set to False the face with the most nodes is chooses as outer face.
        This outer face does not get triangulated.

    Returns
    -------
    (embedding, outer_face) : (nx.PlanarEmbedding, list) tuple
        The element `embedding` is a new embedding containing all edges from
        the input embedding and the additional edges to triangulate the graph.
        The element `outer_face` is a list of nodes that lie on the outer face.
        If the graph is fully triangulated these are three arbitrary connected
        nodes.

    """
    if len(embedding.nodes) <= 1:
        return embedding, list(embedding.nodes)
    embedding = nx.PlanarEmbedding(embedding)

    # Get a list with a node for each connected component
    component_nodes = [next(iter(x)) for x in nx.connected_components(embedding)]

    # 1. Make graph a single component (add edge between components)
    for i in range(len(component_nodes) - 1):
        v1 = component_nodes[i]
        v2 = component_nodes[i + 1]
        embedding.connect_components(v1, v2)

    # 2. Calculate faces, ensure 2-connectedness and determine outer face
    outer_face = []  # A face with the most number of nodes
    face_list = []
    edges_visited = set()  # Used to keep track of already visited faces
    for v in embedding.nodes():
        for w in embedding.neighbors_cw_order(v):
            new_face = make_bi_connected(embedding, v, w, edges_visited)
            if new_face:
                # Found a new face
                face_list.append(new_face)
                if len(new_face) > len(outer_face):
                    # The face is a candidate to be the outer face
                    outer_face = new_face

    # 3. Triangulate (internal) faces
    for face in face_list:
        if face is not outer_face or fully_triangulate:
            # Triangulate this face
            triangulate_face(embedding, face[0], face[1])

    if fully_triangulate:
        v1 = outer_face[0]
        v2 = outer_face[1]
        v3 = embedding[v2][v1]["ccw"]
        outer_face = [v1, v2, v3]

    return embedding, outer_face
Ejemplo n.º 20
0
 def test_smoke_planar_layout_embedding_input(self):
     embedding = nx.PlanarEmbedding()
     embedding.set_data({0: [1, 2], 1: [0, 2], 2: [0, 1]})
     nx.planar_layout(embedding)
Ejemplo n.º 21
0
 def test_missing_edge_orientation(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_edge(1, 2)
     embedding.add_edge(2, 1)
     # Invalid structure because the orientation of the edge was not set
     embedding.check_structure()
Ejemplo n.º 22
0
def test_invalid_half_edge():
    embedding_data = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]}
    embedding = nx.PlanarEmbedding()
    embedding.set_data(embedding_data)
    nx.combinatorial_embedding_to_pos(embedding)
Ejemplo n.º 23
0
 def get_star_embedding(n):
     embedding = nx.PlanarEmbedding()
     for i in range(1, n):
         embedding.add_half_edge_first(0, i)
         embedding.add_half_edge_first(i, 0)
     return embedding
Ejemplo n.º 24
0
 def test_missing_half_edge(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_half_edge_first(1, 2)
     # Invalid structure because other half edge is missing
     embedding.check_structure()
Ejemplo n.º 25
0
 def test_invalid_edge_orientation(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_half_edge_first(1, 2)
     embedding.add_half_edge_first(2, 1)
     embedding.add_edge(1, 3)
     embedding.check_structure()
Ejemplo n.º 26
0
def test_triangulate_embedding2():
    embedding = nx.PlanarEmbedding()
    embedding.connect_components(1, 2)
    expected_embedding = {1: [2], 2: [1]}
    check_triangulation(embedding, expected_embedding)
Ejemplo n.º 27
0
 def test_missing_reference(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_half_edge_cw(1, 2, 3)
Ejemplo n.º 28
0
def test_triangulate_embedding1():
    embedding = nx.PlanarEmbedding()
    embedding.add_node(1)
    expected_embedding = {1: []}
    check_triangulation(embedding, expected_embedding)
Ejemplo n.º 29
0
 def test_unsuccessful_face_traversal(self):
     embedding = nx.PlanarEmbedding()
     embedding.add_edge(1, 2, ccw=2, cw=3)
     embedding.add_edge(2, 1, ccw=1, cw=3)
     embedding.traverse_face(1, 2)