Mapping the language of team learning
Network visualization of semantic similarity between team learning survey items
In the network visualization below, each node represents a single item from a team learning measure and each edge represents semantic similarity.
Each node represents a single measure item.
Node size is based on degree centrality and
Node color is based on its assigned construct group.
Node pair similarity is double encoded using edge color and length.
Darker and shorter edges represent greater semantic similarity between a pair of nodes.
import pandas as pd
import networkx as nx
from pyvis.network import Network
from IPython.display import HTML
import matplotlib.colors as mcolors
import matplotlib.cm as cm
import html
import warningswarnings.filterwarnings('ignore')# Load data globally
nodes_df = pd.read_csv('nodes.csv')
links_df = pd.read_csv('links.csv')def display_horizontal_legend(df):
"""
Creates a standalone HTML legend with a two-row horizontal grid layout.
"""
unique_categories = df['Category'].unique()
category_colors = ['#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F', '#EDC948', '#B07AA1']
cat_map = {cat: category_colors[i % len(category_colors)] for i, cat in enumerate(unique_categories)}
# CSS Grid: grid-auto-flow: column forces items to fill columns first,
# and grid-template-rows: repeat(2, auto) restricts it to two rows.
legend_html = (
'<div style="padding:15px; background:white; border:1px solid #ddd; '
'font-family:sans-serif; border-radius:8px; width:100%; box-sizing:border-box; '
'text-align:center;">'
'<strong style="font-size:14px; display:block; margin-bottom:12px;">Process Category</strong>'
'<div style="display:grid; grid-auto-flow:column; grid-template-rows:repeat(2, auto); '
'gap:10px 20px; justify-content:center;">'
)
for cat, color in cat_map.items():
legend_html += (
f'<div style="display:flex; align-items:center; white-space:nowrap;">'
f'<span style="display:inline-block; width:12px; height:12px; '
f'background-color:{color}; margin-right:8px; border-radius:50%;"></span>'
f'<span style="font-size:13px;">{cat}</span></div>'
)
legend_html += '</div></div>'
return HTML(legend_html)def create_myst_network(nodes_df, links_df):
"""
Creates the network visualization. Labels are completely hidden using
transparent font colors and zero-size definitions.
"""
G = nx.Graph()
for _, row in nodes_df.iterrows():
G.add_node(row['id'], title=row['Item'], group=row['Category'])
for _, row in links_df.iterrows():
G.add_edge(row['from'], row['to'], weight=float(row['similVal']))
net = Network(
height="600px",
width="100%",
bgcolor="#ffffff",
font_color="rgba(0,0,0,0)", # Global font set to transparent
cdn_resources='remote'
)
degrees = dict(G.degree())
unique_categories = nodes_df['Category'].unique()
category_colors = ['#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F', '#EDC948', '#B07AA1']
cat_map = {cat: category_colors[i % len(category_colors)] for i, cat in enumerate(unique_categories)}
for node_id, deg in degrees.items():
node_data = G.nodes[node_id]
net.add_node(
node_id,
label=" ", # Use a space instead of empty string to overwrite defaults
font={'size': 0, 'color': 'rgba(0,0,0,0)'}, # Double-enforcement of invisibility
title=node_data['title'],
size=deg * 4,
color=cat_map[node_data['group']]
)
norm = mcolors.Normalize(vmin=links_df['similVal'].min(), vmax=links_df['similVal'].max())
mapper = cm.ScalarMappable(norm=norm, cmap=cm.Greys)
for u, v, d in G.edges(data=True):
edge_color = mcolors.to_hex(mapper.to_rgba(d['weight']))
net.add_edge(
u, v,
width=1 + d['weight'] * 5,
color=edge_color,
title=f"{d['weight']:.2f}"
)
net.force_atlas_2based()
raw_html = net.generate_html()
escaped_html = html.escape(raw_html)
iframe_output = (
f'<iframe srcdoc="{escaped_html}" width="100%" height="650px" '
f'style="border:none;" title="Network Visualization"></iframe>'
)
return HTML(iframe_output)display_horizontal_legend(nodes_df)Loading...
create_myst_network(nodes_df, links_df)Loading...