Skip to content

Instantly share code, notes, and snippets.

@EliotAndres
Last active April 30, 2018 15:28
Show Gist options
  • Save EliotAndres/10d87567a2f81209f4c9be62c421a5df to your computer and use it in GitHub Desktop.
Save EliotAndres/10d87567a2f81209f4c9be62c421a5df to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Plotting your friend network using Plotly, NetworkX and python-louvain\n",
"\n",
"\n",
"In this notebook I'll show you how to plot a friend graph.\n",
"\n",
"Original notebook author: [Lucas Allen](https://twitter.com/lucasallenio), [original code](https://github.com/lgallen/twitter-graph)\n",
"\n",
"Author: [Eliot Andres](https://twitter.com/eliotandres)\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<script>requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window.Plotly) {{require(['plotly'],function(plotly) {window.Plotly=plotly;});}}</script>"
],
"text/vnd.plotly.v1+html": [
"<script>requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window.Plotly) {{require(['plotly'],function(plotly) {window.Plotly=plotly;});}}</script>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import plotly.offline as py\n",
"from plotly.graph_objs import *\n",
"\n",
"import community\n",
"import networkx as nx\n",
"import colorlover as cl\n",
"import numpy as np\n",
"import pickle\n",
"\n",
"py.init_notebook_mode(connected=True)\n",
"\n",
"# This is your Facebook id. It can also be a number\n",
"CENTRAL_ID = 'eliotandres'\n",
"\n",
"# This is the pickle file containing the raw graph data\n",
"GRAPH_FILENAME = 'friend_graph_clean.pickle'"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"\n",
"# To generate the friend graph, see:\n",
"# friend_graph a dict of lists in the form {'friend1': ['friend2, 'friend3']}\n",
"with open(GRAPH_FILENAME, 'rb') as f:\n",
" friend_graph = pickle.load(f)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Firtered out 46 items\n"
]
}
],
"source": [
"\n",
"# First, we'll clean the edges of the grap\n",
"edges = []\n",
"nodes = [CENTRAL_ID]\n",
"\n",
"# Only keep friends with at least 2 common friends\n",
"central_friends = {}\n",
"\n",
"for k, v in friend_graph.items():\n",
" # This contains the list number of mutual friends.\n",
" # Doing len(v) does not work because ometimes instead of returning mutual\n",
" # friends, Facebook returns all the person's friends\n",
" intersection_size = len(np.intersect1d(list(friend_graph.keys()), v))\n",
" if intersection_size > 2:\n",
" central_friends[k] = v\n",
" \n",
"print('Firtered out {} items'.format(len(friend_graph.keys()) - len(central_friends.keys())))\n",
"\n",
"# Extract edges from graph\n",
"for k, v in central_friends.items():\n",
" for item in v:\n",
" if item in central_friends.keys():\n",
" edges.append((k, item))\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Added 13257 edges\n"
]
}
],
"source": [
"# Create the graph. \n",
"# Small reminder: friends are the nodes and friendships are the edges here\n",
"G = nx.Graph()\n",
"G.add_nodes_from([CENTRAL_ID])\n",
"G.add_nodes_from(central_friends.keys())\n",
"\n",
"G.add_edges_from(edges)\n",
"print('Added {} edges'.format(len(edges) ))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define Positioning\n",
"\n",
"Plotly does not have a true library for graph theory. We will use NetworkX to define the position of coordinates of a scatterplot and the attributes to describe the nodes of that scatterplot. Once a positioning is determined above, define it below as \"pos\", a dictionary of x and y coordinates."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"pos = nx.spring_layout(G)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## Community detection\n",
"\n",
"In this step we'll color the different friends clusters. We'll use the louvain method described in Fast unfolding of communities in large networks, Vincent D Blondel, Jean-Loup Guillaume, Renaud Lambiotte, Renaud Lefebvre, Journal of Statistical Mechanics: Theory and Experiment 2008(10), P10008 (12pp). Details [here](https://github.com/taynaud/python-louvain)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"part = community.best_partition(G)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Define scatter_nodes() and scatter_edges()\n",
"\n",
"These functions create Plotly \"traces\" of the nodes and edges using the layout defined in \"pos\". "
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"# Get a list of all node ids\n",
"nodeID = G.node.keys()"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"# The louvain community library returns cluster ids, we have turn them into colors using color lovers\n",
"\n",
"colors = cl.scales['12']['qual']['Paired']\n",
"\n",
"def scatter_nodes(pos, labels=None, color='rgb(152, 0, 0)', size=8, opacity=1):\n",
" # pos is the dict of node positions\n",
" # labels is a list of labels of len(pos), to be displayed when hovering the mouse over the nodes\n",
" # color is the color for nodes. When it is set as None the Plotly default color is used\n",
" # size is the size of the dots representing the nodes\n",
" # opacity is a value between [0,1] defining the node color opacity\n",
"\n",
" trace = Scatter(x=[], \n",
" y=[], \n",
" mode='markers', \n",
" marker=Marker(\n",
" showscale=False,\n",
" colorscale='Greens',\n",
" reversescale=True,\n",
" color=[], \n",
" size=10,\n",
" line=dict(width=0)))\n",
" for nd in nodeID:\n",
" trace['x'].append(pos[nd][0])\n",
" trace['y'].append(pos[nd][1])\n",
" color = colors[part[nd] % len(colors)]\n",
" trace['marker']['color'].append(color)\n",
" attrib=dict(name='', text=labels , hoverinfo='text', opacity=opacity) # a dict of Plotly node attributes\n",
" trace=dict(trace, **attrib)# concatenate the dict trace and attrib\n",
" trace['marker']['size']=size\n",
"\n",
" return trace "
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"def scatter_edges(G, pos, line_color='#a3a3c2', line_width=1, opacity=.2):\n",
" trace = Scatter(x=[], \n",
" y=[], \n",
" mode='lines'\n",
" )\n",
" for edge in G.edges():\n",
" trace['x'] += [pos[edge[0]][0],pos[edge[1]][0], None]\n",
" trace['y'] += [pos[edge[0]][1],pos[edge[1]][1], None] \n",
" trace['hoverinfo']='none'\n",
" trace['line']['width']=line_width\n",
" if line_color is not None: # when it is None a default Plotly color is used\n",
" trace['line']['color']=line_color\n",
" return trace "
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"# Node label information available on hover. Note that some html tags such as line break <br> are recognized within a string.\n",
"labels = []\n",
"\n",
"for nd in nodeID:\n",
" labels.append('{} ({})'.format(nd, part[nd],))"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"trace1 = scatter_edges(G, pos, line_width=0.25)\n",
"trace2 = scatter_nodes(pos, labels=labels)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Configure the plot and call Plotly"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"width=600\n",
"height=600\n",
"axis=dict(showline=False, # hide axis line, grid, ticklabels and title\n",
" zeroline=False,\n",
" showgrid=False,\n",
" showticklabels=False,\n",
" title='' \n",
" )\n",
"layout=Layout(title= '',\n",
" \n",
" font= Font(),\n",
" showlegend=False,\n",
" autosize=False,\n",
" width=width,\n",
" height=height,\n",
" xaxis=dict(\n",
" title='Facebook friend graph',\n",
" titlefont=dict(\n",
" size=14,\n",
" color='#fff'),\n",
" showgrid=False,\n",
" \n",
" showline=False,\n",
" showticklabels=False,\n",
" zeroline=False\n",
" ),\n",
" yaxis=YAxis(axis),\n",
" margin=Margin(\n",
" l=40,\n",
" r=40,\n",
" b=85,\n",
" t=100,\n",
" pad=0,\n",
" \n",
" ),\n",
" hovermode='closest',\n",
" paper_bgcolor='rgba(0,0,0,1)',\n",
" plot_bgcolor='rgba(0,0,0,1)'\n",
" )\n",
"\n",
"\n",
"data=Data([trace1, trace2])\n",
"\n",
"fig = Figure(data=data, layout=layout)\n",
"py.iplot(fig)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment