176 lines
6.2 KiB
Python
176 lines
6.2 KiB
Python
"""CSC111 Winter 2022 Assignment 3: Graphs, Recommender Systems, and Clustering (Visualization)
|
|
|
|
Module Description
|
|
==================
|
|
|
|
This module contains some Python functions that you can use to visualize the graphs
|
|
you're working with on this assignment. You should not modify anything in this file.
|
|
It will not be submitted for grading.
|
|
|
|
Disclaimer: we didn't have time to make this file fully PythonTA-compliant!
|
|
|
|
Copyright and Usage Information
|
|
===============================
|
|
|
|
This file is provided solely for the personal and private use of students
|
|
taking CSC111 at the University of Toronto St. George campus. All forms of
|
|
distribution of this code, whether as given or with any changes, are
|
|
expressly prohibited. For more information on copyright for CSC111 materials,
|
|
please consult our Course Syllabus.
|
|
|
|
This file is Copyright (c) 2022 Mario Badr, David Liu, and Isaac Waller.
|
|
"""
|
|
import networkx as nx
|
|
from plotly.graph_objs import Scatter, Figure
|
|
|
|
import a3_part1
|
|
|
|
|
|
# Colours to use when visualizing different clusters.
|
|
COLOUR_SCHEME = [
|
|
'#2E91E5', '#E15F99', '#1CA71C', '#FB0D0D', '#DA16FF', '#222A2A', '#B68100',
|
|
'#750D86', '#EB663B', '#511CFB', '#00A08B', '#FB00D1', '#FC0080', '#B2828D',
|
|
'#6C7C32', '#778AAE', '#862A16', '#A777F1', '#620042', '#1616A7', '#DA60CA',
|
|
'#6C4516', '#0D2A63', '#AF0038'
|
|
]
|
|
|
|
LINE_COLOUR = 'rgb(210,210,210)'
|
|
VERTEX_BORDER_COLOUR = 'rgb(50, 50, 50)'
|
|
BOOK_COLOUR = 'rgb(89, 205, 105)'
|
|
USER_COLOUR = 'rgb(105, 89, 205)'
|
|
|
|
|
|
def visualize_graph(graph: a3_part1.Graph,
|
|
layout: str = 'spring_layout',
|
|
max_vertices: int = 5000,
|
|
output_file: str = '') -> None:
|
|
"""Use plotly and networkx to visualize the given graph.
|
|
|
|
Optional arguments:
|
|
- layout: which graph layout algorithm to use
|
|
- max_vertices: the maximum number of vertices that can appear in the graph
|
|
- output_file: a filename to save the plotly image to (rather than displaying
|
|
in your web browser)
|
|
"""
|
|
graph_nx = graph.to_networkx(max_vertices)
|
|
|
|
pos = getattr(nx, layout)(graph_nx)
|
|
|
|
x_values = [pos[k][0] for k in graph_nx.nodes]
|
|
y_values = [pos[k][1] for k in graph_nx.nodes]
|
|
labels = list(graph_nx.nodes)
|
|
kinds = [graph_nx.nodes[k]['kind'] for k in graph_nx.nodes]
|
|
|
|
colours = [BOOK_COLOUR if kind == 'book' else USER_COLOUR for kind in kinds]
|
|
|
|
x_edges = []
|
|
y_edges = []
|
|
for edge in graph_nx.edges:
|
|
x_edges += [pos[edge[0]][0], pos[edge[1]][0], None]
|
|
y_edges += [pos[edge[0]][1], pos[edge[1]][1], None]
|
|
|
|
trace3 = Scatter(x=x_edges,
|
|
y=y_edges,
|
|
mode='lines',
|
|
name='edges',
|
|
line=dict(color=LINE_COLOUR, width=1),
|
|
hoverinfo='none',
|
|
)
|
|
trace4 = Scatter(x=x_values,
|
|
y=y_values,
|
|
mode='markers',
|
|
name='nodes',
|
|
marker=dict(symbol='circle-dot',
|
|
size=5,
|
|
color=colours,
|
|
line=dict(color=VERTEX_BORDER_COLOUR, width=0.5)
|
|
),
|
|
text=labels,
|
|
hovertemplate='%{text}',
|
|
hoverlabel={'namelength': 0}
|
|
)
|
|
|
|
data1 = [trace3, trace4]
|
|
fig = Figure(data=data1)
|
|
fig.update_layout({'showlegend': False})
|
|
fig.update_xaxes(showgrid=False, zeroline=False, visible=False)
|
|
fig.update_yaxes(showgrid=False, zeroline=False, visible=False)
|
|
|
|
if output_file == '':
|
|
fig.show()
|
|
else:
|
|
fig.write_image(output_file)
|
|
|
|
|
|
def visualize_graph_clusters(graph: a3_part1.Graph, clusters: list[set],
|
|
layout: str = 'spring_layout',
|
|
max_vertices: int = 5000,
|
|
output_file: str = '') -> None:
|
|
"""Visualize the given graph, using different colours to illustrate the different clusters.
|
|
|
|
Hides all edges that go from one cluster to another. (This helps the graph layout algorithm
|
|
positions vertices in the same cluster close together.)
|
|
|
|
Same optional arguments as visualize_graph (see that function for details).
|
|
"""
|
|
graph_nx = graph.to_networkx(max_vertices)
|
|
all_edges = list(graph_nx.edges)
|
|
for edge in all_edges:
|
|
# Check if edge is within the same cluster
|
|
if any((edge[0] in cluster) != (edge[1] in cluster) for cluster in clusters):
|
|
graph_nx.remove_edge(edge[0], edge[1])
|
|
|
|
pos = getattr(nx, layout)(graph_nx)
|
|
|
|
x_values = [pos[k][0] for k in graph_nx.nodes]
|
|
y_values = [pos[k][1] for k in graph_nx.nodes]
|
|
labels = list(graph_nx.nodes)
|
|
|
|
colors = []
|
|
for k in graph_nx.nodes:
|
|
for i, c in enumerate(clusters):
|
|
if k in c:
|
|
colors.append(COLOUR_SCHEME[i % len(COLOUR_SCHEME)])
|
|
break
|
|
else:
|
|
colors.append(BOOK_COLOUR)
|
|
|
|
x_edges = []
|
|
y_edges = []
|
|
for edge in graph_nx.edges:
|
|
x_edges += [pos[edge[0]][0], pos[edge[1]][0], None]
|
|
y_edges += [pos[edge[0]][1], pos[edge[1]][1], None]
|
|
|
|
trace3 = Scatter(x=x_edges,
|
|
y=y_edges,
|
|
mode='lines',
|
|
name='edges',
|
|
line=dict(color=LINE_COLOUR, width=1),
|
|
hoverinfo='none'
|
|
)
|
|
trace4 = Scatter(x=x_values,
|
|
y=y_values,
|
|
mode='markers',
|
|
name='nodes',
|
|
marker=dict(symbol='circle-dot',
|
|
size=5,
|
|
color=colors,
|
|
line=dict(color=VERTEX_BORDER_COLOUR, width=0.5)
|
|
),
|
|
text=labels,
|
|
hovertemplate='%{text}',
|
|
hoverlabel={'namelength': 0}
|
|
)
|
|
|
|
data1 = [trace3, trace4]
|
|
fig = Figure(data=data1)
|
|
fig.update_layout({'showlegend': False})
|
|
fig.update_xaxes(showgrid=False, zeroline=False, visible=False)
|
|
fig.update_yaxes(showgrid=False, zeroline=False, visible=False)
|
|
fig.show()
|
|
|
|
if output_file == '':
|
|
fig.show()
|
|
else:
|
|
fig.write_image(output_file)
|