{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Aragon Conviction Voting Model - Version 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Overview \n",
    "\n",
    "[Conviction Voting](https://medium.com/giveth/conviction-voting-a-novel-continuous-decision-making-alternative-to-governance-aa746cfb9475) is a novel decision making process where votes express their preference for which proposals they would like to see approved in a continuous rather than discrete way. The longer the community keeps a preference on an individual proposal, the “stronger” the proposal conviction becomes. In the conviction voting model, a graph structure is used to record the introduction and removal of participants, candidates, proposals, and their outcomes.\n",
    "\n",
    "## cadCAD Overview\n",
    "\n",
    "In the cadCAD simulation [methodology](https://community.cadcad.org/t/differential-specification-syntax-key/31), we operate on four layers: **Policies, Mechanisms, States**, and **Metrics**. Information flows do not have explicit feedback loop unless noted. **Policies** determine the inputs into the system dynamics, and can come from user input, observations from the exogenous environment, or algorithms. **Mechanisms** are functions that take the policy decisions and update the States to reflect the policy level changes. **States** are variables that represent the system quantities at the given point in time, and **Metrics** are computed from state variables to assess the health of the system. Metrics can often be thought of as KPIs, or Key Performance Indicators. \n",
    "\n",
    "At a more granular level, to setup a model, there are system conventions and configurations that must be [followed.](https://community.cadcad.org/t/introduction-to-simulation-configurations/34)\n",
    "\n",
    "The way to think of cadCAD modeling is analogous to machine learning pipelines which normally consist of multiple steps when training and running a deployed model. There is preprocessing, which includes segregating features between continuous and categorical, transforming or imputing data, and then instantiating, training, and running a machine learning model with specified hyperparameters. cadCAD modeling can be thought of in the same way as states, roughly translating into features, are fed into pipelines that have built-in logic to direct traffic between different mechanisms, such as scaling and imputation. Accuracy scores, ROC, etc. are analogous to the metrics that can be configured on a cadCAD model, specifying how well a given model is doing in meeting its objectives. The parameter sweeping capability of cadCAD can be thought of as a grid search, or way to find the optimal hyperparameters for a system by running through alternative scenarios. A/B style testing that cadCAD enables is used in the same way machine learning models are A/B tested, except out of the box, in providing a side by side comparison of muliple different models to compare and contrast performance. Utilizing the field of Systems Identification, dynamical systems models can be used to \"online learn\" by providing a feedback loop to generative system mechanisms. \n",
    "\n",
    "\n",
    "## Differential Specification\n",
    "![](images/Aragon_v1.png)\n",
    "\n",
    "## Schema of the states\n",
    "The model consists of a temporal in memory graph database called *network* containing nodes of type **Participant** and type **Proposal**. Participants will have *holdings* and Proposals will have *funds_required, status*(candidate or active), *conviction*. Edges in the network go from nodes of type Participant to nodes of type Proposal with the edges having the key *type*, of which all will be set to *support*. Edges from participant $i$ to proposal $j$ will have the following additional characteristics:\n",
    "* Each pairing (i,j) will have *affinity*, which determines how much $i$ likes or dislikes proposal $j$.\n",
    "* Each participant $i$, assigns its $tokens$ over the edges (i,j) for all $j$ such that the summation of all $j$ such that ```Sum_j = network.edges[(i,j)]['tokens'] = network.nodes[i]['holdings']```\n",
    "* Each pairing (i,j) will have *conviction* local to that edge whose update at each timestep is computed using the value of *tokens* at that edge.\n",
    "* Each proposal *j* will have a *conviction* which is equal to the sum of the conviction on its inbound edges: ```network.nodes[j]['conviction'] = Sum_i  network.edges[(i,j)]['conviction']```\n",
    "* The \"trigger function\" will check whether each proposal $j$ has met the criteria for passing; if a proposal passes its *status* changes from *candidate* to *active*, and an amount of funds equal to its *funds_required* will be decremented from *funds*.\n",
    "\n",
    "\n",
    "The other state variable in the model is *funds*, which is a numpy floating point. \n",
    "\n",
    "The system consists of 100 time steps without a parameter sweep or monte carlo.\n",
    "\n",
    "\n",
    "## Partial State Update Blocks\n",
    "\n",
    "Each partial state update block is kind of a like a phase in a phased based board game. Everyone decides what to do and it reconciles all decisions. One timestep is a full turn, with each block being a phase of a timestep or turn. We will walk through the individaul Partial State update blocks one by one below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{\n",
    "# system.py: \n",
    "'policies': { \n",
    "    'random': driving_process\n",
    "},\n",
    "'variables': {\n",
    "    'network': update_network,\n",
    "    'funds':increment_funds,\n",
    "}\n",
    "```\n",
    "\n",
    "To simulate the arrival of participants and proposal into the system, we have a driving process to represent the arrival of individual agents. For simplification, we are using hyperparameters for supply and sentiment, 1,231,286.81 and 0.6 respectively. We use a random uniform distribution generator, over [0, 1), to calculate the number of new participants. We then use an expoential distribution to calculate the particpant's tokens by using a loc of 0.0 and a scale of expected holdings, which is calcutulaed by .1*supply/number of existing participants. We calcualte the number of new proposals by     \n",
    "```\n",
    "proposal_rate = 1/median_affinity * (1+total_funds_requested/funds)\n",
    "rv2 = np.random.rand()\n",
    "new_proposal = bool(rv2<1/proposal_rate)\n",
    "```\n",
    "The network state variable is updated to include the new participants and proposals, while the funds state variable is updated for the increase in system funds. \n",
    "[To see the partial state update code, click here](model/model/system.py)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{\n",
    "  # participants.py   \n",
    "  'policies': {\n",
    "      'completion': check_progress \n",
    "    },\n",
    "    'variables': { \n",
    "        'network': complete_proposal\n",
    "    }\n",
    "},\n",
    "```\n",
    "\n",
    "In the next phase of the turn, [to see the logic code, click here](model/model/participants.py), the *check_progress* behavior checks for the completion of previously funded proposals. The code calculates the completion and failure rates as follows:\n",
    "\n",
    "```\n",
    "likelihood = 1.0/(base_completion_rate+np.log(grant_size))\n",
    "\n",
    "failure_rate = 1.0/(base_failure_rate+np.log(grant_size))\n",
    "if np.random.rand() < likelihood:\n",
    "    completed.append(j)\n",
    "elif np.random.rand() < failure_rate:\n",
    "    failed.append(j)\n",
    "```\n",
    "With the base_completion_rate being 100 and the base_failure_rate as 200. \n",
    "\n",
    "The mechanism then updates the respective *network* nodes. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{\n",
    " # proposals.py\n",
    "  'policies': {\n",
    "      'release': trigger_function \n",
    "    },\n",
    "    'variables': { \n",
    "        'funds': decrement_funds, \n",
    "        'network': update_proposals \n",
    "    }\n",
    "},\n",
    " ```\n",
    " \n",
    "The [trigger release function](model/model/proposals.py) checks to see if each proposal passes or not. If a proposal passes, funds are decremented by the amount of the proposal, while the proposal's status is changed in the network object."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "{ \n",
    "    # participants.py\n",
    "    'policies': { \n",
    "        'participants_act': participants_decisions\n",
    "    },\n",
    "    'variables': {\n",
    "        'network': update_tokens \n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "The Participants decide based on their affinity if which proposals they would like to support,[to see the logic code, click here](model/model/participants.py). Proposals that participants have high affinity for receive more support and pledged tokens than proposals with lower affinity and sentiment. We then update everyone's holdings and their conviction for each proposal.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model next steps\n",
    "\n",
    "The the model described above is a minimalist model, first iteration model that covers the core mechanisms of the Aragon Conviction Voting model. Below are next additional dynamics we can attend to enrich the model, and provide workstreams for subsequent iterations of this lab notebook.\n",
    "* Sentiment\n",
    "* Mixing of token holdings among participants\n",
    "* Departure of participants\n",
    "* Participants influencing each others opinions\n",
    "* Proposals which are good or no good together\n",
    "* Multiple proposal stages such as killed, failed and completed\n",
    "* Affects of outcomes on sentiment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simulation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configuration\n",
    "let's factor out into its own notebook where we review the config object and its partial state update blocks, with a slightly deeper dive on the trigger function. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.\n",
      "  import pandas.util.testing as tm\n"
     ]
    }
   ],
   "source": [
    "from model import economyconfig"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# pull out configurations to illustrate\n",
    "sim_config,genesis_states,seeds,partial_state_update_blocks = economyconfig.get_configs()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'N': 1,\n",
       " 'T': range(0, 100),\n",
       " 'M': [{}],\n",
       " 'subset_id': 0,\n",
       " 'subset_window': deque([0, None]),\n",
       " 'simulation_id': 0,\n",
       " 'run_id': 0}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sim_config"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'policies': {'random': <function model.model.system.driving_process(params, step, sL, s)>},\n",
       "  'variables': {'network': <function model.model.system.update_network(params, step, sL, s, _input)>,\n",
       "   'funds': <function model.model.system.increment_funds(params, step, sL, s, _input)>}},\n",
       " {'policies': {'completion': <function model.model.participants.check_progress(params, step, sL, s)>},\n",
       "  'variables': {'network': <function model.model.participants.complete_proposal(params, step, sL, s, _input)>}},\n",
       " {'policies': {'release': <function model.model.proposals.trigger_function(params, step, sL, s)>},\n",
       "  'variables': {'funds': <function model.model.proposals.decrement_funds(params, step, sL, s, _input)>,\n",
       "   'network': <function model.model.proposals.update_proposals(params, step, sL, s, _input)>}},\n",
       " {'policies': {'participants_act': <function model.model.participants.participants_decisions(params, step, sL, s)>},\n",
       "  'variables': {'network': <function model.model.participants.update_tokens(params, step, sL, s, _input)>}}]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "partial_state_update_blocks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialization\n",
    "To create the genesis_states, we create our in-memory graph database within networkx. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import libraries\n",
    "import networkx as nx\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from model.model.conviction_helper_functions import * \n",
    "\n",
    "# Parameters\n",
    "n= 60 #initial participants\n",
    "m= 3 #initial proposals\n",
    "\n",
    "initial_sentiment = .6\n",
    "\n",
    "initial_funds = 40781.42\n",
    "\n",
    "def initialize_network(n,m, inital_funds, expected_supply = 10**6):\n",
    "    '''\n",
    "    Definition:\n",
    "    Function to initialize network x object\n",
    "    '''\n",
    "    # initilize network x graph\n",
    "    network = nx.DiGraph()\n",
    "    # create participant nodes with type and token holding\n",
    "    for i in range(n):\n",
    "        network.add_node(i)\n",
    "        network.nodes[i]['type']= \"participant\"\n",
    "        \n",
    "        h_rv = expon.rvs(loc=0.0, scale= expected_supply/n)\n",
    "        network.nodes[i]['holdings'] = h_rv\n",
    "        \n",
    "    \n",
    "    participants = get_nodes_by_type(network, 'participant')\n",
    "    initial_supply = np.sum([ network.nodes[i]['holdings'] for i in participants])\n",
    "       \n",
    "    \n",
    "    # Generate initial proposals\n",
    "    for ind in range(m):\n",
    "        j = n+ind\n",
    "        network.add_node(j)\n",
    "        network.nodes[j]['type']=\"proposal\"\n",
    "        network.nodes[j]['conviction'] = 0\n",
    "        network.nodes[j]['status'] = 'candidate'\n",
    "        network.nodes[j]['age'] = 0\n",
    "        \n",
    "        r_rv = gamma.rvs(3,loc=0.001, scale=10000)\n",
    "        network.nodes[j]['funds_requested'] = r_rv\n",
    "        \n",
    "        network.nodes[j]['trigger']= trigger_threshold(r_rv, initial_funds, initial_supply)\n",
    "        \n",
    "        for i in range(n):\n",
    "            network.add_edge(i, j)\n",
    "            \n",
    "            rv = np.random.rand()\n",
    "            a_rv = 1-4*(1-rv)*rv #polarized distribution\n",
    "            network.edges[(i, j)]['affinity'] = a_rv\n",
    "            network.edges[(i, j)]['tokens'] = 0\n",
    "            network.edges[(i, j)]['conviction'] = 0\n",
    "            network.edges[(i, j)]['type'] = 'support'\n",
    "            \n",
    "        proposals = get_nodes_by_type(network, 'proposal')\n",
    "        total_requested = np.sum([ network.nodes[i]['funds_requested'] for i in proposals])\n",
    "        \n",
    "        \n",
    "    return network, initial_funds\n",
    "\n",
    "# run the initialize_network function to create the initial states of the simulation\n",
    "network, initial_funds = initialize_network(n,m,initial_funds)\n",
    "\n",
    "\n",
    "# Create initial states\n",
    "genesis_states = { \n",
    "                'network':network,\n",
    "                'funds':initial_funds\n",
    "\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'network': <networkx.classes.digraph.DiGraph at 0x7f4b3cb7b290>,\n",
       " 'funds': 40781.42}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "genesis_states"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# To explore our model prior to the simulation, we extract key components from our networkX object into lists.\n",
    "proposals = get_nodes_by_type(network, 'proposal')\n",
    "participants = get_nodes_by_type(network, 'participant')\n",
    "supporters = get_edges_by_type(network, 'support')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exploring the State Data Structure\n",
    "\n",
    "A graph is a type of temporal data structure that evolves over time. A graph $\\mathcal{G}(\\mathcal{V},\\mathcal{E})$ consists of vertices or nodes, $\\mathcal{V} = \\{1...\\mathcal{V}\\}$ and is connected by edges  $\\mathcal{E} \\subseteq \\mathcal{V} \\times \\mathcal{V}$.\n",
    "\n",
    "See *Schema of the states* above for more details\n",
    "\n",
    "\n",
    "Let's explore!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'participant', 'holdings': 11273.789624257935}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sample a participant\n",
    "network.nodes[participants[0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Histogram of Participants Token Holdings')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 8160 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Let's look at the distribution of participant holdings at the start of the sim\n",
    "plt.hist([ network.nodes[i]['holdings'] for i in participants])\n",
    "plt.title('Histogram of Participants Token Holdings')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'type': 'proposal',\n",
       " 'conviction': 0,\n",
       " 'status': 'candidate',\n",
       " 'age': 0,\n",
       " 'funds_requested': 18949.143684698993,\n",
       " 'trigger': inf}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#lets look at proposals\n",
    "network.nodes[proposals[0]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Proposals initially start without any conviction, and with the status of a candidate. If the proposal's amount of  conviction is greater than it's trigger, then the proposal moves to active and it's funds requested are granted. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All initial proposal start with 0 conviction and state 'candidate'we can simply examine the amounts of funds requested"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 0, 'Proposals')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 10100 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.bar( proposals, [ network.nodes[i]['funds_requested'] for i in proposals])\n",
    "plt.title('Histogram of Proposals Funds Requested')\n",
    "plt.xlabel('Proposals')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Conviction is a concept that arises in the edges between participants and proposals in the initial conditions there are no votes yet so we can look at that later however, the voting choices are driven by underlying affinities which we can see now."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 137.58, 'participant_id')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 19056 characters]\n",
      "text/plain": [
       "<Figure size 1440x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "affinities = np.empty((n,m))\n",
    "for i_ind in range(n):\n",
    "    for j_ind in range(m):\n",
    "        i = participants[i_ind]\n",
    "        j = proposals[j_ind]\n",
    "        affinities[i_ind][j_ind] = network.edges[(i,j)]['affinity']\n",
    "\n",
    "dims = (20, 5)\n",
    "fig, ax = plt.subplots(figsize=dims)\n",
    "\n",
    "sns.heatmap(affinities.T,\n",
    "            xticklabels=participants,\n",
    "            yticklabels=proposals,\n",
    "            square=True,\n",
    "            cbar=True,\n",
    "            ax=ax)\n",
    "\n",
    "plt.title('affinities between participants and proposals')\n",
    "plt.ylabel('proposal_id')\n",
    "plt.xlabel('participant_id')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run simulation\n",
    "\n",
    "Now we will create the final system configuration, append the genesis states we created, and run our simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from cadCAD.configuration import Experiment\n",
    "\n",
    "# Create configuration\n",
    "exp = Experiment()\n",
    "\n",
    "exp.append_configs(\n",
    "    sim_configs=sim_config,\n",
    "    initial_state=genesis_states,\n",
    "    seeds=seeds,\n",
    "    partial_state_update_blocks=partial_state_update_blocks\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "                  ___________    ____\n",
      "  ________ __ ___/ / ____/   |  / __ \\\n",
      " / ___/ __` / __  / /   / /| | / / / /\n",
      "/ /__/ /_/ / /_/ / /___/ ___ |/ /_/ /\n",
      "\\___/\\__,_/\\__,_/\\____/_/  |_/_____/\n",
      "by cadCAD\n",
      "\n",
      "Execution Mode: local_proc\n",
      "Configuration Count: 2\n",
      "Dimensions of the first simulation: (Timesteps, Params, Runs, Vars) = (100, 1, 1, 2)\n",
      "Execution Method: local_simulations\n",
      "SimIDs   : [0, 1]\n",
      "SubsetIDs: [0, 0]\n",
      "Ns       : [0, 0]\n",
      "ExpIDs   : [0, 0]\n",
      "Total execution time: 33.62s\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from model.model.conviction_helper_functions import *\n",
    "from model import run\n",
    "from cadCAD import configs\n",
    "pd.options.display.float_format = '{:.2f}'.format\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "# Pass in configuration to run\n",
    "df = run.run(configs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After the simulation has run successfully, we perform some postprocessing to extract node and edge values from the network object and add as columns to the pandas dataframe. For the rdf, we take only the values at the last substep of each timestep in the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "df,rdf = run.postprocessing(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 28524 characters]\n",
      "text/plain": [
       "<Figure size 1440x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "affinities_plot(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f4b57ec4690>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 23492 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "rdf.plot(x='timestep',y=['candidate_count','active_count','completed_count', 'killed_count', 'failed_count'])\n",
    "plt.title('Proposal Status')\n",
    "plt.ylabel('count of proposals')\n",
    "plt.legend(ncol = 3,loc='upper center', bbox_to_anchor=(0.5, -0.15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f4b391c6d90>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 26152 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "rdf.plot(x='timestep',y=['candidate_funds','active_funds','completed_funds', 'killed_funds', 'failed_funds'])\n",
    "plt.title('Proposal Status weighted by funds requested')\n",
    "plt.ylabel('Funds worth of proposals')\n",
    "plt.legend(ncol = 3,loc='upper center', bbox_to_anchor=(0.5, -0.15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "nets = rdf.network.values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:563: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if not cb.iterable(width):\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:569: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  and cb.iterable(edge_color) \\\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:579: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  for c in edge_color]):\n",
      "/home/aclarkdata/anaconda3/lib/python3.7/site-packages/networkx/drawing/nx_pylab.py:660: MatplotlibDeprecationWarning: \n",
      "The iterable function was deprecated in Matplotlib 3.1 and will be removed in 3.3. Use np.iterable instead.\n",
      "  if cb.iterable(node_size):  # many node sizes\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 109876 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "K = 3\n",
    "snap_plot(nets[K:K+1], size_scale = 1/300)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 135916 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "K = 56\n",
    "snap_plot(nets[K:K+1], size_scale = 1/300)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.LineCollection at 0x7f4b39c42110>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 46036 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "quantile_plot('timestep','conviction_share_of_trigger', rdf, .25)\n",
    "plt.hlines(1,0,df.timestep.values[-1], linestyle='--')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "We have created a simplified conviction voting model that illustrates the state objects, and provides descriptions of how the model fits together. In subsequent notebooks, we will expand the model to introduce additional complexity to more fit real world implementations. "
   ]
  }
 ],
 "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.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
