Networks with Altair#

Dynamic Visualization#

Dynamic visualization responds to the viewer’s inputs. In dynamic visualizations, you can click on things, move nodes around, and get more information about the network in various ways. All the principles of static visualization described on the previous page also apply to dynamic visualization. But because you can more easily show node movement and create new arrangements in a dynamic visualization, you can typically include a lot more information in a single visualization. The key to a dynamic visualization is that it allows someone to explore the network on their own. This makes it both easier and harder to communicate an argument with a dynamic visualization. There are more tools at your disposal, but the viewer also has considerable freedom.

Using nx_altair#

In the Data Basics section, you saw how to make interactive visualizations with Altair. There is a plugin for this library, nx_altair, that allows you to use Altair’s syntax to create interactive network visualizations.

Remember that before you can use a new library, you must install it with !pip install nx_altair, but you only need to do this one time.

See also

Some documentation and guidance for nx_altair can be found on its Github page.

You’ll use nx_altair in concert with Altair and NetworkX:

# Necessary libraries
import networkx as nx
import pandas as pd
import altair as alt
import nx_altair as nxa

# Read Karate Club data as example
G = nx.karate_club_graph()
print(G)
Graph named "Zachary's Karate Club" with 34 nodes and 78 edges

You can make your network visualization more complex by first adding some attributes:

degree = nx.degree_centrality(G) # Add degree centrality
betweenness = nx.betweenness_centrality(G) # Add betweenness centrality
# Run louvain community detection
from networkx.algorithms.community import louvain_communities
louvain = louvain_communities(G, seed=42)
louvain = {g:str(i) for i,group in enumerate(louvain) for g in group}

# Add all attributes to graph
nx.set_node_attributes(G, degree, 'degree_centrality')
nx.set_node_attributes(G, betweenness, 'betweenness_centrality')
nx.set_node_attributes(G, louvain, "louvain_partition")

Creating a basic nx_altair graph#

The nx_altair plugin allows you to treat node and edge attributes just as you would columns in a tabular dataset (i.e. you can access them using quoted strings).

See also

nx_altair uses all the same attributes and options as the draw_networkx function in NetworkX. You can look at the NetworkX documentation for a full list of what you can do with these options.

Before you can draw a NetworkX graph, you have to select a layout. There are lots of layout options, and the spring_layout() function will give you a basic force-directed network:

pos = nx.spring_layout(G) 
# You can customize the position in many ways!
# This is only a starting point.

Once you have a layout, you can create a simple example of the nx_altair syntax with some of the available options:

# As with other altair charts, you must sometimes disable max rows
alt.data_transformers.disable_max_rows()
viz = nxa.draw_networkx(G, 
                        pos=pos, 
                        node_color='louvain_partition', 
                        node_size='degree_centrality',
                        node_tooltip=['degree_centrality','betweenness_centrality']
                       )
# Use .interactive() to make your plot interactive
viz.interactive()

Adding additional charts#

Because you’re using Altair to make your chart, in addition to adding zooming interactivity, you can also add additional explanatory charts. For instance, you can make a bar plot to show the number of nodes in each partition, and add that to your network visualization.

nodes = viz.layer[1] # Get the correct part of your previous visualization

# Create a bar chart based on nodes data
bars = alt.Chart(nodes.data).mark_bar().encode(
    x=alt.X('louvain_partition'),
    y=alt.Y('count()'),
    color=alt.Color('louvain_partition').legend(None),
)

# Place interactive network and bar chart side by side
viz.interactive() | bars