예제 #1
0
    def test_approx_radius(self):
        adjacency = test_graph()
        n = adjacency.shape[0]

        spring = Spring(approx_radius=1.)
        layout = spring.fit_transform(adjacency)
        self.assertEqual((n, 2), layout.shape)
예제 #2
0
 def test_errors(self):
     adjacency = test_graph()
     with self.assertRaises(ValueError):
         Spring(position_init='toto')
         Spring().fit(adjacency, position_init=np.ones(2, 2))
     with self.assertRaises(TypeError):
         # noinspection PyTypeChecker
         Spring().fit(adjacency, position_init='toto')
예제 #3
0
    def test_pos_init(self):
        adjacency = test_graph()
        n = adjacency.shape[0]

        spring = Spring(strength=0.1, position_init='spectral', tol=1e3)
        layout = spring.fit_transform(adjacency)
        self.assertEqual((n, 2), layout.shape)
        layout = spring.fit_transform(adjacency, position_init=layout)
        self.assertEqual((n, 2), layout.shape)
예제 #4
0
    def test_shape(self):
        for adjacency in [test_graph(), test_digraph()]:
            n = adjacency.shape[0]
            spring = Spring()
            layout = spring.fit_transform(adjacency)
            self.assertEqual((n, 2), layout.shape)

            spring = Spring(n_components=3)
            layout = spring.fit_transform(adjacency)
            self.assertEqual((n, 3), layout.shape)
예제 #5
0
    def test_undirected(self):
        adjacency = test_graph()
        n = adjacency.shape[0]

        method = Spring()
        embedding = method.fit_transform(adjacency)
        self.assertEqual(embedding.shape, (n, 2))
        pred1 = method.predict(adjacency[0])
        pred2 = method.predict(adjacency[0].toarray())
        self.assertEqual(pred1.shape, (2, ))
        self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)

        pred1 = method.predict(adjacency)
        pred2 = method.predict(adjacency.toarray())
        self.assertTupleEqual(pred1.shape, (n, 2))
        self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)
예제 #6
0
    def test_undirected(self):
        adjacency = test_graph()
        n = adjacency.shape[0]

        for method in self.methods:
            with self.assertRaises(ValueError):
                method.predict(adjacency[0])

            embedding = method.fit_transform(adjacency)

            self.assertEqual(embedding.shape, (n, 2))

            ref = embedding[0]
            pred1 = method.predict(adjacency[0])
            pred2 = method.predict(adjacency[0].toarray())

            self.assertEqual(pred1.shape, (2, ))
            self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)
            self.assertAlmostEqual(np.linalg.norm(pred1 - ref), 0)

            pred1 = method.predict(adjacency)
            pred2 = method.predict(adjacency.toarray())

            self.assertTupleEqual(pred1.shape, (n, 2))
            self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)
            self.assertAlmostEqual(np.linalg.norm(pred1 - embedding), 0)

        method = Spring()
        embedding = method.fit_transform(adjacency)
        self.assertEqual(embedding.shape, (n, 2))
        pred1 = method.predict(adjacency[0])
        pred2 = method.predict(adjacency[0].toarray())
        self.assertEqual(pred1.shape, (2, ))
        self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)

        pred1 = method.predict(adjacency)
        pred2 = method.predict(adjacency.toarray())
        self.assertTupleEqual(pred1.shape, (n, 2))
        self.assertAlmostEqual(np.linalg.norm(pred1 - pred2), 0)
예제 #7
0
def svg_graph(adjacency: Optional[sparse.csr_matrix] = None, position: Optional[np.ndarray] = None,
              names: Optional[np.ndarray] = None,
              labels: Optional[Iterable] = None, scores: Optional[Iterable] = None,
              membership: Optional[sparse.csr_matrix] = None,
              seeds: Union[list, dict] = None, width: Optional[float] = 400, height: Optional[float] = 300,
              margin: float = 20, margin_text: float = 3, scale: float = 1, node_order: Optional[np.ndarray] = None,
              node_size: float = 7, node_size_min: float = 1, node_size_max: float = 20,
              display_node_weight: bool = False, node_weights: Optional[np.ndarray] = None, node_width: float = 1,
              node_width_max: float = 3, node_color: str = 'gray',
              display_edges: bool = True, edge_labels: Optional[list] = None,
              edge_width: float = 1, edge_width_min: float = 0.5,
              edge_width_max: float = 20, display_edge_weight: bool = True,
              edge_color: Optional[str] = None, label_colors: Optional[Iterable] = None,
              font_size: int = 12, directed: bool = False, filename: Optional[str] = None) -> str:
    """Return SVG image of a graph.

    Parameters
    ----------
    adjacency :
        Adjacency matrix of the graph.
    position :
        Positions of the nodes.
    names :
        Names of the nodes.
    labels :
        Labels of the nodes (negative values mean no label).
    scores :
        Scores of the nodes (measure of importance).
    membership :
        Membership of the nodes (label distribution).
    seeds :
        Nodes to be highlighted (if dict, only keys are considered).
    width :
        Width of the image.
    height :
        Height of the image.
    margin :
        Margin of the image.
    margin_text :
        Margin between node and text.
    scale :
        Multiplicative factor on the dimensions of the image.
    node_order :
        Order in which nodes are displayed.
    node_size :
        Size of nodes.
    node_size_min :
        Minimum size of a node.
    node_size_max:
        Maximum size of a node.
    node_width :
        Width of node circle.
    node_width_max :
        Maximum width of node circle.
    node_color :
        Default color of nodes (svg color).
    display_node_weight :
        If ``True``, display node weights through node size.
    node_weights :
        Node weights (used only if **display_node_weight** is ``True``).
    display_edges :
        If ``True``, display edges.
    edge_labels :
        Labels of the edges, as a list of tuples (source, destination, label)
    edge_width :
        Width of edges.
    edge_width_min :
        Minimum width of edges.
    edge_width_max :
        Maximum width of edges.
    display_edge_weight :
        If ``True``, display edge weights through edge widths.
    edge_color :
        Default color of edges (svg color).
    label_colors:
        Colors of the labels (svg colors).
    font_size :
        Font size.
    directed :
        If ``True``, considers the graph as directed.
    filename :
        Filename for saving image (optional).

    Returns
    -------
    image : str
        SVG image.

    Example
    -------
    >>> from sknetwork.data import karate_club
    >>> graph = karate_club(True)
    >>> adjacency = graph.adjacency
    >>> position = graph.position
    >>> from sknetwork.visualization import svg_graph
    >>> image = svg_graph(adjacency, position)
    >>> image[1:4]
    'svg'
    """
    # check adjacency
    if adjacency is None:
        if position is None:
            raise ValueError("You must specify either adjacency or position.")
        else:
            n = position.shape[0]
            adjacency = sparse.csr_matrix((n, n)).astype(int)
    else:
        n = adjacency.shape[0]

    # node order
    if node_order is None:
        node_order = np.arange(n)

    # position
    if position is None:
        spring = Spring()
        position = spring.fit_transform(adjacency)

    # node colors
    node_colors = get_node_colors(n, labels, scores, membership, node_color, label_colors)

    # node sizes
    if node_weights is None:
        node_weights = adjacency.T.dot(np.ones(n))
    node_sizes = get_node_sizes(node_weights, node_size, node_size_min, node_size_max, display_node_weight)

    # node widths
    node_widths = get_node_widths(n, seeds, node_width, node_width_max)

    # rescaling
    position, width, height = rescale(position, width, height, margin, node_size, node_size_max, display_node_weight)

    if names is not None:
        text_length = np.max(np.array([len(str(name)) for name in names]))
        width += text_length * font_size * .5

    # scaling
    position *= scale
    height *= scale
    width *= scale

    svg = """<svg width="{}" height="{}" xmlns="http://www.w3.org/2000/svg">\n""".format(width, height)

    # edges
    if display_edges:
        adjacency_coo = sparse.coo_matrix(adjacency)

        if edge_color is None:
            if names is None:
                edge_color = 'black'
            else:
                edge_color = 'gray'

        if directed:
            svg += """<defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" >\n"""
            svg += """<path d="M0,0 L0,6 L9,3 z" fill="{}"/></marker></defs>\n""".format(edge_color)

        edge_colors, edge_order, edge_colors_residual = get_edge_colors(adjacency, edge_labels, edge_color,
                                                                        label_colors)
        edge_widths = get_edge_widths(adjacency_coo, edge_width, edge_width_min, edge_width_max, display_edge_weight)

        for ix in edge_order:
            i = adjacency_coo.row[ix]
            j = adjacency_coo.col[ix]
            color = edge_colors[ix]
            if directed:
                svg += svg_edge_directed(pos_1=position[i], pos_2=position[j], edge_width=edge_widths[ix],
                                         edge_color=color, node_size=node_sizes[j])
            else:
                svg += svg_edge(pos_1=position[i], pos_2=position[j],
                                edge_width=edge_widths[ix], edge_color=color)

        for i, j, color in edge_colors_residual:
            if directed:
                svg += svg_edge_directed(pos_1=position[i], pos_2=position[j], edge_width=edge_width,
                                         edge_color=color, node_size=node_sizes[j])
            else:
                svg += svg_edge(pos_1=position[i], pos_2=position[j],
                                edge_width=edge_width, edge_color=color)

    # nodes
    for i in node_order:
        if membership is None:
            svg += svg_node(position[i], node_sizes[i], node_colors[i], node_widths[i])
        else:
            if membership[i].nnz == 1:
                index = membership[i].indices[0]
                svg += svg_node(position[i], node_sizes[i], node_colors[index], node_widths[i])
            else:
                svg += svg_pie_chart_node(position[i], node_sizes[i], membership[i].todense(),
                                          node_colors, node_widths[i])

    # text
    if names is not None:
        for i in range(n):
            svg += svg_text(position[i] + node_sizes[i] + (margin_text, 0), names[i], font_size)
    svg += """</svg>\n"""

    if filename is not None:
        with open(filename + '.svg', 'w') as f:
            f.write(svg)

    return svg
예제 #8
0
def svg_graph(adjacency: sparse.csr_matrix, position: Optional[np.ndarray] = None, names: Optional[np.ndarray] = None,
              labels: Optional[Union[dict, np.ndarray]] = None, scores: Optional[np.ndarray] = None,
              seeds: Union[list, dict] = None, width: float = 400, height: float = 300,
              margin: float = 20, margin_text: float = 3, scale: float = 1, node_order: Optional[np.ndarray] = None,
              node_size: float = 7, node_size_min: float = 1, node_size_max: float = 20,
              display_node_weight: bool = False, node_weights: Optional[np.ndarray] = None, node_width: float = 1,
              node_width_max: float = 3, node_color: str = 'gray',
              display_edges: bool = True, edge_width: float = 1, edge_width_min: float = 0.5,
              edge_width_max: float = 20, edge_weight: bool = True, edge_color: Optional[str] = None,
              font_size: int = 12, directed: bool = False, filename: Optional[str] = None) -> str:
    """Return SVG image of a graph.

    Parameters
    ----------
    adjacency :
        Adjacency matrix of the graph.
    position :
        Positions of the nodes.
    names :
        Names of the nodes.
    labels :
        Labels of the nodes (negative values mean no label).
    scores :
        Scores of the nodes (measure of importance).
    seeds :
        Nodes to be highlighted (if dict, only keys are considered).
    width :
        Width of the image.
    height :
        Height of the image.
    margin :
        Margin of the image.
    margin_text :
        Margin between node and text.
    scale :
        Multiplicative factor on the dimensions of the image.
    node_order :
        Order in which nodes are displayed.
    node_size :
        Size of nodes.
    node_size_min :
        Minimum size of a node.
    node_size_max:
        Maximum size of a node.
    node_width :
        Width of node circle.
    node_width_max :
        Maximum width of node circle.
    node_color :
        Default color of nodes (svg color).
    display_node_weight :
        Display node weights by node size.
    node_weights :
        Node weights (used only if **display_node_weight** is ``True``).
    display_edges :
        If ``True``, display edges.
    edge_width :
        Width of edges.
    edge_width_min :
        Minimum width of edges.
    edge_width_max :
        Maximum width of edges.
    edge_weight :
        Display edge weights with edge widths.
    edge_color :
        Default color of edges (svg color).
    font_size :
        Font size.
    directed :
        If ``True``, considers the graph as directed.
    filename :
        Filename for saving image (optional).

    Returns
    -------
    image : str
        SVG image.

    Example
    -------
    >>> from sknetwork.data import karate_club
    >>> graph = karate_club(True)
    >>> adjacency = graph.adjacency
    >>> position = graph.position
    >>> from sknetwork.visualization import svg_graph
    >>> image = svg_graph(adjacency, position)
    >>> image[1:4]
    'svg'
    """
    n = adjacency.shape[0]

    # node order
    if node_order is None:
        node_order = np.arange(n)

    # position
    if position is None:
        spring = Spring()
        position = spring.fit_transform(adjacency)

    # colors
    colors = get_colors(n, labels, scores, node_color)
    if edge_color is None:
        if names is None:
            edge_color = 'black'
        else:
            edge_color = 'gray'

    # node sizes
    if node_weights is None:
        node_weights = adjacency.dot(np.ones(n))
    node_sizes = get_node_sizes(node_weights, node_size, node_size_min, node_size_max, display_node_weight)

    # node widths
    node_widths = get_node_widths(n, seeds, node_width, node_width_max)

    # edge widths
    adjacency_ = sparse.coo_matrix(adjacency)
    edge_widths = get_edge_widths(adjacency_.data, edge_width, edge_width_min, edge_width_max, edge_weight)

    # rescaling
    position, width, height = rescale(position, width, height, margin, node_size_max, display_node_weight)

    if names is not None:
        text_length = np.max(np.array([len(str(name)) for name in names]))
        width += text_length * font_size * .5

    # scaling
    position *= scale
    height *= scale
    width *= scale

    svg = """<svg width="{}" height="{}" xmlns="http://www.w3.org/2000/svg">""".format(width, height)
    if directed:
        svg += """<defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto" >"""
        svg += """<path d="M0,0 L0,6 L9,3 z" fill="{}"/></marker></defs>""".format(edge_color)

    # edges
    if display_edges:
        n_edges = len(adjacency_.row)
        for ix in range(n_edges):
            i = adjacency_.row[ix]
            j = adjacency_.col[ix]
            if directed:
                svg += svg_edge_directed(pos_1=position[i], pos_2=position[j], stroke_width=edge_widths[ix],
                                         stroke_color=edge_color, node_size=node_sizes[j])
            else:
                svg += svg_edge(pos_1=position[i], pos_2=position[j], stroke_width=edge_widths[ix], stroke_color=edge_color)

    # nodes
    for i in node_order:
        svg += svg_node(position[i], node_sizes[i], colors[i], node_widths[i])

    # text
    if names is not None:
        for i in range(n):
            svg += svg_text(position[i] + node_sizes[i] + (margin_text, 0), names[i], font_size)
    svg += """</svg>"""

    if filename is not None:
        with open(filename + '.svg', 'w') as f:
            f.write(svg)

    return svg