Skip to content

Visualization (fa2.viz)

Render graph layouts to matplotlib figures or export to various formats.

Requires: pip install fa2[viz]

Quick Examples

from fa2.viz import plot_layout, export_layout

# Render to matplotlib
fig = plot_layout(G, positions, color_by_degree=True, title="My Graph")

# Export to D3.js-compatible JSON
export_layout(G, positions, fmt="json", path="graph.json")

# Export to PNG/SVG
export_layout(G, positions, fmt="png", path="graph.png")

# Export to Gephi format
export_layout(G, positions, fmt="gexf", path="graph.gexf")

Functions

plot_layout

plot_layout(G, positions, node_color: Optional[Union[str, list, ndarray]] = None, node_size: Optional[Union[float, list, ndarray]] = None, edge_alpha: float = 0.15, node_alpha: float = 0.8, figsize: tuple = (10, 8), title: Optional[str] = None, color_by_degree: bool = False, cmap: str = 'viridis', show_labels: bool = False, ax=None)

Render a graph layout as a matplotlib figure.

Parameters:

Name Type Description Default
G numpy.ndarray, scipy.sparse matrix, networkx.Graph, or igraph.Graph

The graph.

required
positions dict, list, numpy.ndarray, or igraph.Layout

Node positions from ForceAtlas2.forceatlas2() or wrappers.

required
node_color str, list, or ndarray

Node colors. If None and color_by_degree=True, colors by degree. Can be a single color string, a list of colors, or numeric values for colormap mapping.

None
node_size float, list, or ndarray

Node sizes. If None, sizes are proportional to degree.

None
edge_alpha float

Edge transparency (0-1). Default 0.15.

0.15
node_alpha float

Node transparency (0-1). Default 0.8.

0.8
figsize tuple

Figure size in inches. Default (10, 8).

(10, 8)
title str

Figure title.

None
color_by_degree bool

Color nodes by degree using colormap. Default False.

False
cmap str

Matplotlib colormap name. Default "viridis".

'viridis'
show_labels bool

Show node labels. Default False.

False
ax Axes

Axes to draw on. If None, creates a new figure.

None

Returns:

Type Description
Figure

The matplotlib figure.

Source code in fa2/viz.py
def plot_layout(
    G,
    positions,
    node_color: Optional[Union[str, list, np.ndarray]] = None,
    node_size: Optional[Union[float, list, np.ndarray]] = None,
    edge_alpha: float = 0.15,
    node_alpha: float = 0.8,
    figsize: tuple = (10, 8),
    title: Optional[str] = None,
    color_by_degree: bool = False,
    cmap: str = "viridis",
    show_labels: bool = False,
    ax=None,
):
    """Render a graph layout as a matplotlib figure.

    Parameters
    ----------
    G : numpy.ndarray, scipy.sparse matrix, networkx.Graph, or igraph.Graph
        The graph.
    positions : dict, list, numpy.ndarray, or igraph.Layout
        Node positions from ``ForceAtlas2.forceatlas2()`` or wrappers.
    node_color : str, list, or ndarray, optional
        Node colors. If None and ``color_by_degree=True``, colors by degree.
        Can be a single color string, a list of colors, or numeric values
        for colormap mapping.
    node_size : float, list, or ndarray, optional
        Node sizes. If None, sizes are proportional to degree.
    edge_alpha : float
        Edge transparency (0-1). Default 0.15.
    node_alpha : float
        Node transparency (0-1). Default 0.8.
    figsize : tuple
        Figure size in inches. Default (10, 8).
    title : str, optional
        Figure title.
    color_by_degree : bool
        Color nodes by degree using colormap. Default False.
    cmap : str
        Matplotlib colormap name. Default "viridis".
    show_labels : bool
        Show node labels. Default False.
    ax : matplotlib.axes.Axes, optional
        Axes to draw on. If None, creates a new figure.

    Returns
    -------
    matplotlib.figure.Figure
        The matplotlib figure.
    """
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        raise ImportError(
            "matplotlib is required for plot_layout. "
            "Install it with: pip install 'fa2[viz]'"
        ) from None

    _, pos_array, node_list, edges, node_index = _resolve_graph_and_positions(G, positions)
    n = len(node_list)
    dim = pos_array.shape[1]

    if dim not in (2, 3):
        raise ValueError(f"plot_layout supports 2D and 3D layouts, got dim={dim}")

    # Compute degrees using lookup dict
    degrees = np.zeros(n)
    for src, tgt, _ in edges:
        degrees[node_index[src]] += 1
        degrees[node_index[tgt]] += 1

    # Default node sizes proportional to degree
    if node_size is None:
        node_size = 20 + degrees * 5
    if isinstance(node_size, (int, float)):
        node_size = [node_size] * n

    # Default node colors
    if node_color is None:
        if color_by_degree:
            node_color = degrees
        else:
            node_color = "steelblue"

    if dim == 3:
        return _plot_3d(pos_array, node_list, edges, node_index, node_color, node_size,
                        edge_alpha, node_alpha, figsize, title, cmap, show_labels, ax)

    # 2D plot
    created_fig = ax is None
    if created_fig:
        fig, ax = plt.subplots(1, 1, figsize=figsize)
    else:
        fig = ax.figure

    # Draw edges
    for src, tgt, data in edges:
        si, ti = node_index[src], node_index[tgt]
        ax.plot([pos_array[si, 0], pos_array[ti, 0]],
                [pos_array[si, 1], pos_array[ti, 1]],
                color="gray", alpha=edge_alpha, linewidth=0.5, zorder=1)

    # Draw nodes — only pass cmap when color is numeric (avoids matplotlib warning)
    scatter_kw = dict(s=node_size, alpha=node_alpha, zorder=2, edgecolors="white", linewidths=0.3)
    _is_numeric = isinstance(node_color, np.ndarray) or (
        isinstance(node_color, list) and node_color and isinstance(node_color[0], (int, float))
    )
    if _is_numeric:
        scatter_kw.update(c=node_color, cmap=cmap)
    else:
        scatter_kw["color"] = node_color
    ax.scatter(pos_array[:, 0], pos_array[:, 1], **scatter_kw)

    if show_labels:
        for i, label in enumerate(node_list):
            ax.annotate(str(label), (pos_array[i, 0], pos_array[i, 1]),
                        fontsize=7, ha="center", va="center")

    if title:
        ax.set_title(title)
    ax.set_axis_off()
    if created_fig:
        fig.tight_layout()

    return fig

export_layout

export_layout(G, positions, fmt: str = 'json', path: Optional[str] = None, **plot_kwargs) -> Optional[bytes]

Export a graph layout to various formats.

Parameters:

Name Type Description Default
G numpy.ndarray, scipy.sparse matrix, networkx.Graph, or igraph.Graph

The graph.

required
positions dict, list, numpy.ndarray, or igraph.Layout

Node positions.

required
fmt str

Output format: "json", "png", "svg", "gexf", "graphml".

'json'
path str

File path to write to. If None, returns bytes (for "png", "svg") or a dict (for "json").

None
**plot_kwargs

Additional arguments passed to plot_layout() for image formats.

{}

Returns:

Type Description
bytes, dict, or None

Content if path is None, otherwise writes to file and returns None.

Source code in fa2/viz.py
def export_layout(
    G,
    positions,
    fmt: str = "json",
    path: Optional[str] = None,
    **plot_kwargs,
) -> Optional[bytes]:
    """Export a graph layout to various formats.

    Parameters
    ----------
    G : numpy.ndarray, scipy.sparse matrix, networkx.Graph, or igraph.Graph
        The graph.
    positions : dict, list, numpy.ndarray, or igraph.Layout
        Node positions.
    fmt : str
        Output format: ``"json"``, ``"png"``, ``"svg"``, ``"gexf"``, ``"graphml"``.
    path : str, optional
        File path to write to. If None, returns bytes (for ``"png"``,
        ``"svg"``) or a dict (for ``"json"``).
    **plot_kwargs
        Additional arguments passed to ``plot_layout()`` for image formats.

    Returns
    -------
    bytes, dict, or None
        Content if ``path`` is None, otherwise writes to file and returns None.
    """
    fmt = fmt.lower()

    if fmt == "json":
        return _export_json(G, positions, path)
    elif fmt in ("png", "svg"):
        return _export_image(G, positions, fmt, path, **plot_kwargs)
    elif fmt in ("gexf", "graphml"):
        return _export_graph_format(G, positions, fmt, path)
    else:
        raise ValueError(f"Unsupported format: {fmt!r}. Use 'json', 'png', 'svg', 'gexf', or 'graphml'.")