<jupyter_start><jupyter_text>Panels and FacetingIn this notebook, we will introduce how to make graph visualization panels!<jupyter_code>%config InlineBackend.figure_format = 'retina'
%load_ext autoreload
%autoreload 2
from random import choice

import matplotlib.pyplot as plt
import networkx as nx
import numpy as np

import nxviz as nv<jupyter_output><empty_output><jupyter_text>Example graphHere's an example graph. It has both quantiative and qualitative data encoded on the nodes and edges.<jupyter_code>categories = "abcdefghijk"
node_categories = "12345"

G = nx.erdos_renyi_graph(n=70, p=0.1)
for u, v in G.edges():
    G.edges[u, v]["group"] = choice(categories)
    G.edges[u, v]["edge_val"] = np.random.exponential()

for n in G.nodes():
    G.nodes[n]["category"] = choice(node_categories)
    G.nodes[n]["value"] = np.random.normal()<jupyter_output><empty_output><jupyter_text>Non-panel'd versionLet's see what happens if we just try to plot all nodes and all edges together.<jupyter_code>nv.circos(
    G,
    group_by="category",
    node_color_by="category",
    edge_color_by="edge_val",
    edge_enc_kwargs={"alpha_scale": 5},
)<jupyter_output><empty_output><jupyter_text>This isn't particularly useful.The edges are over-populated on the visualization.If there were structure in the graph that were interesting,we'd find it hard to elucidate.Here, we can rely on the principle of small multiplesto design a more effective visualizations.  `nxviz` faceting APIGraph visualization panels are the solution here.We use categorical metadata on nodes or edgesto facet our visualizations.(Faceting refers to creating subplots that contain a subset of the full dataset,so that one can optimize for visual clarity.)Because nodes are more easily arranged than edges,we can facet our graph out by edge categories into **panels**.As such, one subcategory of graph visualization panelsis defined by a faceting of our graph by edge categories.Here are some examples.<jupyter_code>from nxviz import annotate, facet

# from nxviz import hive_panel, arc_panel, circos_panel
from nxviz.utils import edge_table, node_table<jupyter_output><empty_output><jupyter_text>Arc Panel<jupyter_code>facet.arc_panel(
    G,
    edge_group_by="group",
    node_group_by="category",
    node_color_by="category",
    edge_color_by="edge_val",
)<jupyter_output><empty_output><jupyter_text>Circos Panel<jupyter_code>facet.circos_panel(
    G,
    edge_group_by="group",
    node_group_by="category",
    node_color_by="category",
    edge_color_by="edge_val",
)<jupyter_output><empty_output><jupyter_text>Matrix Panel<jupyter_code>facet.matrix_panel(
    G,
    edge_group_by="group",
    node_group_by="category",
    node_color_by="category",
    edge_color_by="edge_val",
)<jupyter_output><empty_output><jupyter_text>Hive PanelHive panels are a special type of panel.Because hive plots alone can plot either 2 or 3 categories of nodes,it can't handle situations where there are more than 3 categories of nodes.Here is where a panel of hive plots comes in:each plot in the panel handles 3 of the categories that are present.As such, you will have ${K}\choose{3}$ plots to plot.For this reason, we don't recommend having more than 6 categories,otherwise you'll end up with a lot of plots to look at.<jupyter_code>facet.hive_panel(G, node_group_by="category", node_color_by="category")<jupyter_output><empty_output><jupyter_text>Custom panelsWhile there are plot-specific faceting APIs,you can use the building blocks in there to compose your own.In this example, we'll show you how to create a facet where we showonly edges that are associated with a particular group of nodes.For this, the key function to use is `node_group_edges`,which yields graphs that contains edges attached to a particular group,as well as the group itself.<jupyter_code>import inspect

from nxviz.facet import n_rows_cols, node_group_edges

print(inspect.getsource(node_group_edges))
node_group_by = "category"

graphs, groups = zip(*node_group_edges(G, node_group_by))
nrows, ncols = n_rows_cols(groups)
fig, axes = plt.subplots(figsize=(8, 8), nrows=3, ncols=3)
axes = list(axes.flatten())

for ax, G_sub, group in zip(axes, graphs, groups):
    plt.sca(ax)
    nv.circos(
        G_sub, group_by="category", sort_by="value", node_color_by="category"
    )
    annotate.circos_group(G_sub, group_by="category")
    ax.set_title(f"node group = {group}")


i = axes.index(ax)
for ax in axes[i + 1 :]:
    fig.delaxes(ax)

plt.tight_layout()<jupyter_output><empty_output><jupyter_text>Development patternThe core of faceting in nxviz is to return an iterator of graphsthat contain either1. a subset of nodes,2. a subset of edges,3. or a subset of nodes and edges.Using one of the faceting functions as an example to illustrate:<jupyter_code>import inspect

print(inspect.getsource(facet.edge_group))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08893886730729912, 'fraction_numerical': 0.005111429155591904, 'mean_word_length': 5.822873082287308, 'pattern_counts': {'":': 1, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '188650', 'license': 'MIT', 'n_tokens_mistral': 1616, 'n_tokens_neox': 1549, 'n_words': 494, 'path': 'docs/api/facet-api.ipynb', 'repo_name': 'ericmjl/nxviz', 'size': '4891'}