diff --git a/Pipfile b/Pipfile index 5aab87f..12079c6 100644 --- a/Pipfile +++ b/Pipfile @@ -13,7 +13,8 @@ matplotlib = "*" jupyter = "*" networkx = "*" jupyterlab = "*" - +altair = "*" +python-igraph = {git = "https://github.com/igraph/python-igraph.git", ref="8864b46849b031a3013764d03e167222963c0f5d"} [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index f95fc94..32eb404 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "433fe4f585fb489189f98fca98bf4cb140597c32e8a662b212bc3af15471c865" + "sha256": "3a67e54d8190ab442ef984eb4e0e4a28809e7131b1f41e6d865996b8c5926dff" }, "host-environment-markers": { "implementation_name": "cpython", @@ -9,9 +9,9 @@ "os_name": "posix", "platform_machine": "x86_64", "platform_python_implementation": "CPython", - "platform_release": "4.15.3-2-ARCH", + "platform_release": "4.15.6-1-ARCH", "platform_system": "Linux", - "platform_version": "#1 SMP PREEMPT Thu Feb 15 00:13:49 UTC 2018", + "platform_version": "#1 SMP PREEMPT Sun Feb 25 12:53:23 UTC 2018", "python_full_version": "3.6.4", "python_version": "3.6", "sys_platform": "linux" @@ -27,6 +27,12 @@ ] }, "default": { + "altair": { + "hashes": [ + "sha256:c1303f77f1ba4d632f2958c83c0f457b2b969860b1ac9adfb872aefa1780baa7" + ], + "version": "==1.2.1" + }, "bleach": { "hashes": [ "sha256:cf567e7ed30ea5e05b31231d88ae170af1c5544758b9d7bebbc20590b7c30b1e", @@ -144,10 +150,10 @@ }, "jupyterlab": { "hashes": [ - "sha256:c5a140a76f5ed1c88e977372187c267817341a8dfc862807a45c4c72c6ab51bb", - "sha256:842914beca4d8a6fe62c45157b7f8fa44aaa570efdba7b19dab79605a51612e5" + "sha256:543f2f9a7f393d545ecf5a95a2290c97b88d78974a44b299b2bd387dc08b738e", + "sha256:96e01d709eda1e77eb4181b3109c8e0cf7ad7a69d0dfa2c42c94b5bcd65d220f" ], - "version": "==0.31.8" + "version": "==0.31.10" }, "jupyterlab-launcher": { "hashes": [ @@ -308,6 +314,7 @@ "sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a", "sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365" ], + "markers": "os_name != 'nt'", "version": "==0.5.2" }, "pygments": { @@ -336,6 +343,10 @@ ], "version": "==2.6.1" }, + "python-igraph": { + "git": "https://github.com/igraph/python-igraph.git", + "ref": "8864b46849b031a3013764d03e167222963c0f5d" + }, "pytz": { "hashes": [ "sha256:ed6509d9af298b7995d69a440e2822288f2eca1681b8cce37673dbb10091e5fe", @@ -436,6 +447,12 @@ ], "version": "==4.3.2" }, + "vega": { + "hashes": [ + "sha256:b531938b7623c3804fc06a008bcf7559d06e04b485067840dd7181699d126922" + ], + "version": "==0.4.4" + }, "wcwidth": { "hashes": [ "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c", diff --git a/bitcoin.ipynb b/bitcoin.ipynb new file mode 100644 index 0000000..8c22d78 --- /dev/null +++ b/bitcoin.ipynb @@ -0,0 +1,377 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "import igraph as ig" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Load the graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "G = ig.read(\"data/bitcoin/bitcoinotc.graphml\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "G.to_undirected(combine_edges=\"first\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Clique distribution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "G.clique_number()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "cl = G.cliques()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "plt.hist(list(map(len,cl)), bins=10);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Rescale the timestamps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "edges = pd.DataFrame([e.attributes().values() for e in G.es])\n", + "edges.columns = G.es.attribute_names()\n", + "edges.drop([\"Edge Label\", \"id\"], axis=1, inplace=True)\n", + "edges.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "timerange = edges.time.max() - edges.time.min()\n", + "timemin = edges.time.min()\n", + "G.es[\"time\"] = (G.es[\"time\"] - timemin) / timerange" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Temporal subgraphs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "G.subgraph_edges(G.es(lambda e: e[\"time\"] < 0.1)).summary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "def temporal_subgraph(graph, tmin=None, tmax=None, delete_vertices=True):\n", + " if tmin==None:\n", + " tmin = min(graph.es[\"time\"])\n", + " if tmax==None:\n", + " tmax = max(graph.es[\"time\"])\n", + " return G.subgraph_edges(G.es(lambda e: (e[\"time\"] > tmin) & (e[\"time\"] < tmax)), delete_vertices=delete_vertices)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "temporal_subgraph(G, tmin=0.1, tmax=0.3).summary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "ti = 0\n", + "dt = 0.01\n", + "subg = temporal_subgraph(G, tmin=ti, tmax=ti+dt)\n", + "layout = subg.layout(\"kk\")\n", + "ig.plot(subg, layout=layout)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "# Export multilayer graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "dt = 0.05\n", + "layout = []\n", + "subg = []\n", + "for i in range(2):\n", + " subg.append(temporal_subgraph(G, tmin=i*dt, tmax=i*dt+dt))\n", + " layout.append(subg[i].layout(\"kk\").coords)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "vs_df = pd.DataFrame()\n", + "es_df = pd.DataFrame()\n", + "for i in range(2):\n", + " subg_vs = pd.DataFrame(layout[i])\n", + " subg_vs.columns = [\"x\",\"y\"]\n", + " subg_vs[\"id\"] = np.arange(len(layout[i]))\n", + " subg_vs[\"layer\"] = i+1\n", + " # subg_vs.to_csv(\"vs1.csv\", index=False)\n", + " vs_df = pd.concat([vs_df,subg_vs])\n", + " subg_es = pd.DataFrame([[e.source,e.target] for e in subg[i].es])\n", + " subg_es.columns = [\"u\",\"v\"]\n", + " # subg_es.to_csv(\"es1.csv\", index=False)\n", + " es_df = pd.concat([es_df,subg_es])\n", + " \n", + "vs_df.to_csv(\"vs.csv\", index=False)\n", + "es_df.to_csv(\"es.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "autoscroll": false, + "collapsed": false, + "ein.tags": "worksheet-0", + "slideshow": { + "slide_type": "-" + } + }, + "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" + }, + "name": "bitcoin.ipynb" + }, + "nbformat": 4, + "nbformat_minor": 2 +}