You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
soil/examples/tutorial/soil_tutorial.ipynb

2238 lines
163 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-10-19T12:41:48.007238Z",
"start_time": "2017-10-19T14:41:47.980725+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"# Soil Tutorial"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-02T16:44:14.120953Z",
"start_time": "2017-07-02T18:44:14.117152+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"## Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {
"cell_style": "center",
"collapsed": true,
"hideCode": false,
"hidePrompt": false
},
"source": [
"This notebook is an introduction to the soil agent-based social network simulation framework.\n",
"In particular, we will focus on a specific use case: studying the propagation of news in a social network.\n",
"\n",
"The steps we will follow are:\n",
"\n",
"* Modelling the behavior of agents\n",
"* Running the simulation using different configurations\n",
"* Analysing the results of each simulation"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T13:38:48.052876Z",
"start_time": "2017-07-03T15:38:48.044762+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"But before that, let's import the soil module and networkx."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2017-11-03T10:58:13.451481Z",
"start_time": "2017-11-03T11:58:12.643469+01:00"
},
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"import soil\n",
"import networkx as nx\n",
" \n",
"%load_ext autoreload\n",
"%autoreload 2\n",
"\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T13:41:19.788717Z",
"start_time": "2017-07-03T15:41:19.785448+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"## Basic concepts"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"There are three main elements in a soil simulation:\n",
" \n",
"* The environment or model. It assigns agents to nodes in the network, and stores the environment parameters (shared state for all agents).\n",
"* The network topology. A simulation may use an existing NetworkX topology, or generate one on the fly.\n",
"* Agents. There are several types of agents, depending on their behavior and their capabilities. Some examples of built-in types of agents are:\n",
" - Network agents, which are linked to a node in the topology. They have additional methods to access their neighbors.\n",
" - FSM (Finite state machine) agents. Their behavior is defined in terms of states, and an agent will move from one state to another.\n",
" - Evented agents, an actor-based model of agents, which can communicate with one another through message passing.\n",
" - For convenience, a general `soil.Agent` class is provided, which inherits from Network, FSM and Evented at the same time.\n",
"\n",
"Soil provides several abstractions over events to make developing agents easier.\n",
"This means you can use events (timeouts, delays) in soil, but for the most part we will assume your models will be step-based o.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-02T15:55:12.933978Z",
"start_time": "2017-07-02T17:55:12.930860+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"## Modeling behaviour"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T13:49:31.269687Z",
"start_time": "2017-07-03T15:49:31.257850+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"Our first step will be to model how every person in the social network reacts to hearing a piece of disinformation (news).\n",
"We will follow a very simple model based on a finite state machine.\n",
"\n",
"A person may be in one of two states: **neutral** (the default state) and **infected**.\n",
"A neutral person may hear about a piece of disinformation either on the TV (with probability **prob_tv_spread**) or through their friends.\n",
"Once a person has heard the news, they will spread it to their friends (with a probability **prob_neighbor_spread**).\n",
"Some users do not have a TV, so they will only be infected by their friends.\n",
"\n",
"The spreading probabilities will change over time due to different factors.\n",
"We will represent this variance using an additional agent which will not be a part of the social network."
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Modelling Agents\n",
"\n",
"The following sections will cover the basics of developing agents in SOIL.\n",
"\n",
"For more advanced patterns, please check the **examples** folder in the repository."
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"#### Basic agents"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T14:03:07.171127Z",
"start_time": "2017-07-03T16:03:07.165779+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"The most basic agent in Soil is ``soil.BaseAgent``.\n",
"These agents implement their behavior by overriding the `step` method, which will be run in every simulation step.\n",
"Only one agent will be running at any given time, and it will be doing so until the `step` function returns.\n",
"\n",
"Agents can access their environment through their ``self.model`` attribute.\n",
"This is most commonly used to get access to the environment parameters and methods.\n",
"Here is a simple example of an agent:\n",
"\n",
"\n",
"```python\n",
"class ExampleAgent(BaseAgent):\n",
" def init(self):\n",
" self.is_infected = False\n",
" self.steps_neutral = 0\n",
" \n",
" def step(self):\n",
" # Implement agent logic\n",
" if self.is_infected:\n",
" ... # Do something, like infecting other agents\n",
" return self.die(\"No need to do anything else\") # Stop forever\n",
" else:\n",
" ... # Do something\n",
" self.steps_neutral += 1\n",
" if self.steps_neutral > self.model.max_steps_neutral:\n",
" self.is_infected = True\n",
"```\n",
"\n",
"\n",
"\n",
"Any kind of agent behavior can be implemented with this `step` function.\n",
"However, it has two main drawbacks: 1) complex behaviors can get difficult both write and understand; 2) these behaviors are not composable."
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T14:03:07.171127Z",
"start_time": "2017-07-03T16:03:07.165779+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"#### FSM agents\n",
"\n",
"One way to solve both issues is to model agents as **[Finite-state Machines](https://en.wikipedia.org/wiki/Finite-state_machine)** (FSM, for short).\n",
"FSM define a series of possible states for the agent, and changes between these states.\n",
"These states can be modelled and extended independently.\n",
"\n",
"This is modelled in Soil through the `soil.FSM` class.\n",
"Agents that inherit from ``soil.FSM`` do not need to specify a ``step`` method.\n",
"Instead, we describe each finite state with a function.\n",
"To change to another state, a function may return the new state, or the ``id`` of a state.\n",
"If no state is returned, the state remains unchanged.\n",
"\n",
"The current state of the agent can be checked with ``agent.state_id``.\n",
"That state id can be used to look for other agents in that specific state.\n",
"\n",
"Our previous example could be expressed like this:\n",
"\n",
"```python\n",
"class FSMExample(FSM):\n",
"\n",
" def init(self):\n",
" self.steps_neutral = 0\n",
" \n",
" @state(default=True)\n",
" def neutral(self):\n",
" ... # Do something\n",
" self.steps_neutral += 1\n",
" if self.steps_neutral > self.model.max_steps_neutral:\n",
" return self.infected # Change state\n",
"\n",
" @state\n",
" def infected(self):\n",
" ... # Do something\n",
" return self.die(\"No need to do anything else\")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"#### Generator-based agents\n",
"\n",
"Another design pattern that can be very useful in some cases is to model each step (or a specific state) using generators (the `yield` keyword).\n",
"\n",
"\n",
"\n",
"```python\n",
"class GenExample(BaseAgent):\n",
" def step(self):\n",
" for i in range(self.model.max_steps_neutral):\n",
" ... # Do something\n",
" yield # Signal the scheduler that this step is done for now\n",
" ... # Do something\n",
" return self.die(\"No need to do anything else\") \n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"#### Telling the scheduler when to wake up an agent\n",
"\n",
"By default, every agent will be called in every simulation step, and the time elapsed between two steps is controlled by the `interval` attribute in the environment.\n",
"\n",
"But agents may signal the scheduler when they expect to be called again.\n",
"This is especially useful when an agent is going to be dormant for a long time.\n",
"To do so, an agent can return (or `yield`) from a `step` or a `state` a value of type `soil.When` (absolute time), `soil.Delta` (relative time) or `soil.Cond`, telling the scheduler when the agent will be ready to run again.\n",
"If it returns nothing (i.e., `None`), the agent will be ready to run at the next simulation step."
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-02T12:22:53.931963Z",
"start_time": "2017-07-02T14:22:53.928340+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Environment agents"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"Environment agents allow us to control the state of the environment.\n",
"In this case, we will use an environment agent to simulate a very viral event.\n",
"\n",
"When the event happens, the agent will modify the probability of spreading the rumor."
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {
"ExecuteTime": {
"end_time": "2017-11-03T10:58:17.653736Z",
"start_time": "2017-11-03T11:58:17.612944+01:00"
},
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"import logging\n",
"\n",
"class EventGenerator(soil.BaseAgent):\n",
" level = logging.INFO\n",
" \n",
" def step(self):\n",
" # Do nothing until the time of the event\n",
" yield soil.When(self.model.event_time)\n",
" self.info(\"TV event happened\")\n",
" self.model.prob_tv_spread = 0.5\n",
" self.model.prob_neighbor_spread *= 2\n",
" self.model.prob_neighbor_spread = min(self.model.prob_neighbor_spread, 1)\n",
" yield\n",
" self.model.prob_tv_spread = 0\n",
"\n",
" while self.alive:\n",
" self.model.prob_neighbor_spread = self.model.prob_neighbor_spread * self.model.neighbor_factor\n",
" if self.model.prob_neighbor_spread < 0.01:\n",
" return self.die(\"neighbors can no longer spread the rumour\")\n",
" yield"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Environment (Model)\n",
"\n",
"Let's define a environment model to test our event generator agent.\n",
"This environment will have a single agent (the event generator).\n",
"We will also tell the environment to save the value of `prob_tv_spread` after every step:"
]
},
{
"cell_type": "code",
"execution_count": 112,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"class NewsEnv(soil.NetworkEnvironment):\n",
" \n",
" prob_tv_spread = 0.1\n",
" prob_neighbor_spread = 0.1\n",
" event_time = 10\n",
" tv_factor = 0.5\n",
" neighbor_factor = 0.9\n",
"\n",
" \n",
" def init(self):\n",
" self.add_model_reporter(\"prob_tv_spread\")\n",
" self.add_agent(EventGenerator)"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"Once the environment has been defined, we can run a simulation "
]
},
{
"cell_type": "code",
"execution_count": 102,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "1d73b3b3155f4132b863b3fb996ed1f1",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, description='NewsEnv', max=1, style=ProgressStyle(description_width='initi…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=1), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>step</th>\n",
" <th>agent_count</th>\n",
" <th>prob_tv_spread</th>\n",
" </tr>\n",
" <tr>\n",
" <th>time</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>1</td>\n",
" <td>0.1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>0.1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>2</td>\n",
" <td>1</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>3</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>4</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>5</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" step agent_count prob_tv_spread\n",
"time \n",
"0 0 1 0.1\n",
"10 1 1 0.1\n",
"11 2 1 0.5\n",
"12 3 1 0.0\n",
"13 4 1 0.0\n",
"14 5 1 0.0"
]
},
"execution_count": 102,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"it = NewsEnv.run(iterations=1, dump=False, max_time=14)\n",
"\n",
"it[0].model_df()"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"As we can see, the event occurred right after `t=10`, so by `t=11` the value of `prob_tv_spread` was already set to `1.0`.\n",
"\n",
"You may notice nothing happened between `t=0` and `t=1`.\n",
"That is because there aren't any other agents in the simulation, and our event generator explicitly waited until `t=10`."
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Network agents"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T14:03:07.171127Z",
"start_time": "2017-07-03T16:03:07.165779+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"In our disinformation scenario, we will model our agents as a FSM with two states: ``neutral`` (default) and ``infected``.\n",
"\n",
"Here's the code:"
]
},
{
"cell_type": "code",
"execution_count": 103,
"metadata": {
"ExecuteTime": {
"end_time": "2017-11-03T10:58:16.051690Z",
"start_time": "2017-11-03T11:58:16.006044+01:00"
},
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"class NewsSpread(soil.Agent):\n",
" has_tv = False\n",
" infected_by_friends = False\n",
" \n",
" @soil.state(default=True)\n",
" def neutral(self):\n",
" if self.infected_by_friends:\n",
" return self.infected\n",
" if self.has_tv:\n",
" if self.prob(self.model.prob_tv_spread):\n",
" return self.infected\n",
" \n",
" @soil.state\n",
" def infected(self):\n",
" for neighbor in self.iter_neighbors(state_id=self.neutral.id):\n",
" if self.prob(self.model.prob_neighbor_spread):\n",
" neighbor.infected_by_friends = True"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"We can check that our states are well defined, here:"
]
},
{
"cell_type": "code",
"execution_count": 104,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"data": {
"text/plain": [
"['dead', 'neutral', 'infected']"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"NewsSpread.states()"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Environment (Model)"
]
},
{
"cell_type": "markdown",
"metadata": {
"cell_style": "split",
"hideCode": false,
"hidePrompt": false
},
"source": [
"Let's modify our simple simulation.\n",
"We will add a network of agents of type NewsSpread.\n",
"\n",
"Only one agent (0) will have a TV (in blue)."
]
},
{
"cell_type": "code",
"execution_count": 105,
"metadata": {
"cell_style": "split",
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def generate_simple():\n",
" G = nx.Graph()\n",
" G.add_edge(0, 1)\n",
" G.add_edge(0, 2)\n",
" G.add_edge(2, 3)\n",
" G.add_node(4)\n",
" return G\n",
"\n",
"G = generate_simple()\n",
"pos = nx.spring_layout(G)\n",
"nx.draw_networkx(G, pos, node_color='red')\n",
"nx.draw_networkx(G, pos, nodelist=[0], node_color='blue')"
]
},
{
"cell_type": "code",
"execution_count": 106,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"class NewsEnv(soil.NetworkEnvironment):\n",
" \n",
" prob_tv_spread = 0\n",
" prob_neighbor_spread = 0.1\n",
" event_time = 10\n",
" tv_factor = 0.5\n",
" neighbor_factor = 0.9\n",
"\n",
" \n",
" def init(self):\n",
" self.add_agent(EventGenerator)\n",
" self.G = generate_simple()\n",
" self.populate_network(NewsSpread)\n",
" self.agent(node_id=0).has_tv = True\n",
" self.add_model_reporter('prob_tv_spread')\n",
" self.add_model_reporter('prob_neighbor_spread')"
]
},
{
"cell_type": "code",
"execution_count": 107,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "dc1e3d6242e24e009601774769b9525b",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, description='NewsEnv', max=1, style=ProgressStyle(description_width='initi…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=1), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>step</th>\n",
" <th>agent_count</th>\n",
" <th>prob_tv_spread</th>\n",
" <th>prob_neighbor_spread</th>\n",
" </tr>\n",
" <tr>\n",
" <th>time</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>4</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>5</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>6</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>7</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>8</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>9</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>10</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.100000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>11</td>\n",
" <td>6</td>\n",
" <td>0.5</td>\n",
" <td>0.200000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>12</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.180000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>13</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.162000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>14</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.145800</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>15</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.131220</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>16</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.118098</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>17</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.106288</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>18</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.095659</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>19</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.086093</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>20</td>\n",
" <td>6</td>\n",
" <td>0.0</td>\n",
" <td>0.077484</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" step agent_count prob_tv_spread prob_neighbor_spread\n",
"time \n",
"0 0 6 0.0 0.100000\n",
"1 1 6 0.0 0.100000\n",
"2 2 6 0.0 0.100000\n",
"3 3 6 0.0 0.100000\n",
"4 4 6 0.0 0.100000\n",
"5 5 6 0.0 0.100000\n",
"6 6 6 0.0 0.100000\n",
"7 7 6 0.0 0.100000\n",
"8 8 6 0.0 0.100000\n",
"9 9 6 0.0 0.100000\n",
"10 10 6 0.0 0.100000\n",
"11 11 6 0.5 0.200000\n",
"12 12 6 0.0 0.180000\n",
"13 13 6 0.0 0.162000\n",
"14 14 6 0.0 0.145800\n",
"15 15 6 0.0 0.131220\n",
"16 16 6 0.0 0.118098\n",
"17 17 6 0.0 0.106288\n",
"18 18 6 0.0 0.095659\n",
"19 19 6 0.0 0.086093\n",
"20 20 6 0.0 0.077484"
]
},
"execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"it = NewsEnv.run(max_time=20)\n",
"it[0].model_df()"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"In this case, notice that the inclusion of other agents (which run every step) means that the simulation did not skip to `t=10`.\n",
"\n",
"Now, let's look at the state of our agents in every step:"
]
},
{
"cell_type": "code",
"execution_count": 108,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEGCAYAAAB1iW6ZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAAsTAAALEwEAmpwYAAAs4UlEQVR4nO3deXhU5d3/8fc3ITEkIiRgEQXEBZEdJIItirghKnVvwR1xw5Xq06fa6s+6tE+19XGrqJUHiloVFDdErEtdKFaFgOyIoCKCG0LCkhCTwP3748wZhjCTTJKZM5Pk87quuZiZc+acm5Phy5373OdzzDmHiIg0fhmpboCIiCSGCrqISBOhgi4i0kSooIuINBEq6CIiTUSLVO24Xbt2rkuXLqnavYhIozRv3rwfnHN7R1uWsoLepUsXioqKUrV7EZFGycy+jLVMQy4iIk2ECrqISBOhgi4i0kSkbAw9msrKStauXUt5eXmqmyKNWE5ODh07diQrKyvVTREJVFoV9LVr19KqVSu6dOmCmaW6OdIIOefYsGEDa9eu5YADDkh1c0QCFdeQi5kNN7MVZrbKzG6Ksny0ma03swWhx6X1aUx5eTlt27ZVMZd6MzPatm2r3/KkWaq1h25mmcB44ARgLTDXzKY755ZVW3Wqc+6ahjZIxVwaSt8haa7i6aEPBFY55z53zlUAU4DTktsskcbp1UXfsLG0ItXNkGYqnoK+H/BVxOu1ofeqO8vMFpnZNDPrFG1DZna5mRWZWdH69evr0VyR9FVcWsHVT8/nuaKval9ZJAkSNW3xFaCLc64P8CbweLSVnHOPOecKnXOFe+8d9crVRm/PPfeMe93Jkyfz9ddfJ7E1yTF06FBd5RvFhtIfQ3+qhy6pEU9BXwdE9rg7ht4Lc85tcM79GHr5f8CAxDQvPW3fvj0h20lFQa+qqgp0f81JcVml96cKuqRIPNMW5wJdzewAvEI+Cjg3cgUz6+Cc+yb08lRgeUMbdvsrS1n29eaGbmYXPfbdi9//vGeN66xevZrhw4czYMAA5s+fT8+ePXniiSfo0aMHI0eO5M033+Q3v/kNzjn+53/+B+ccp5xyCnfffXd4G9dffz1vvPEG++yzD1OmTCHabyPTpk2jqKiI8847j5YtW/KnP/2JSZMm8dxzzwHw7rvvcs899zBjxozdPrt9+3YuueQSioqKMDPGjBnD9ddfz9ChQ+nbty/vvfceVVVVTJo0iYEDB3Lbbbfx2Wef8fnnn9O5c2cefPBBxo4dy5o1awC4//77GTx4MHPmzGHcuHGUl5fTsmVL/v73v9OtWze2bdvGxRdfzMKFCzn00EPZtm1bQ34MTZY/dl5cpoIuqVFrQXfOVZnZNcDrQCYwyTm31MzuAIqcc9OB68zsVKAK2AiMTmKbk27FihVMnDiRwYMHM2bMGB5++GEA2rZty/z58/n666854ogjmDdvHvn5+QwbNoyXXnqJ008/ndLSUgoLC7nvvvu44447uP3223nooYd228fZZ5/NQw89xD333ENhYSFVVVVcccUVlJaWkpeXx9SpUxk1alTU9i1YsIB169axZMkSAEpKSsLLysrKWLBgAbNmzWLMmDHhdZYtW8bs2bNp2bIl5557Ltdffz1HHnkka9as4cQTT2T58uUceuih/Pvf/6ZFixa89dZb/O53v+P555/nkUceITc3l+XLl7No0SIOO+ywBB/xpsHvmeukqKRKXBcWOedmAjOrvXdrxPPfAr9NZMNq60knU6dOnRg8eDAA559/Pg8++CAAI0eOBGDu3LkMHTo03PM+77zzmDVrFqeffjoZGRnh9c4//3zOPPPMuPbZokULhg8fziuvvMLZZ5/Nq6++yp///Oeo6x544IF8/vnnXHvttZxyyikMGzYsvOycc84BYMiQIWzevDlc7E899VRatmwJwFtvvcWyZTtnnW7evJmtW7eyadMmLrroIlauXImZUVnpDSHMmjWL6667DoA+ffrQp0+fuP5OzY0/5FIS+lMkaGl1pWi6qD6P2X+dl5fX4G3VZNSoUTz00EMUFBRQWFhIq1atoq6Xn5/PwoULef3113n00Ud59tlnmTRpUtxt37FjBx9++CE5OTm7rHvNNddwzDHH8OKLL7J69WqGDh0ad9tl51DLRg25SIoonCuKNWvW8MEHHwDw9NNPc+SRR+6yfODAgbz33nv88MMPbN++nWeeeYajjz4a8IrltGnTYn42UqtWrdiyZUv49dFHH838+fOZMGFCzOEWgB9++IEdO3Zw1lln8Yc//IH58+eHl02dOhWA2bNn07p1a1q3br3b54cNG8Zf//rX8OsFCxYAsGnTJvbbz5uROnny5PDyIUOG8PTTTwOwZMkSFi1aFLNtzZk/1LJpWyXbd7gUt0aaIxX0KLp168b48ePp3r07xcXFXHnllbss79ChA3fddRfHHHMMffv2ZcCAAZx2mnetVV5eHnPmzKFXr168/fbb3HrrrdF2AcDo0aMZO3Ys/fr1Y9u2bWRmZjJixAhee+01RowYEfNz69atY+jQofTr14/zzz+fP/3pT+FlOTk59O/fn7FjxzJx4sSon3/wwQcpKiqiT58+9OjRg0cffRSA3/zmN/z2t7+lf//+u8yGufLKK9m6dSvdu3fn1ltvZcCAJj2Jqd5KQj1z57yiLhI0cy41PYnCwkJXfS7z8uXL6d69e0ra41u9ejUjRowIn0xsTIYOHRo+ydrcpeK7dObD7zN/TQkAb91wNAf/JP5rEkTiZWbznHNR/5Grhy6SIMVllbTJzQo91zi6BE8nRavp0qVLwnvnV199Ne+///4u740bN46LL7641s8OGjSIH3/8cZf3nnzySXr37r3buu+++26D2ikNs7G0goN/sifzvizW1EVJCRX0AIwfP77en/3oo48S2BJJlqrtO9hcXsmB7fKY92VxeDxdJEgachFJgE3bKnEODtzbGzffWKqTohI8FXSRBPDHzPdtk8MeLTI0hi4poYIukgD+VaIFednk52YroEtSQgVdJAH8k6D5udnk52Wrhy4poYKeYHXJQ6+rr7/+mrPPPrvebRg9enT4KtamIpnHuy78HnlBXjYFeVma5SIpoYJeD4nKQ6+rfffdN2UFORk56k0pm93Pb8nPDQ25KKBLUiB9py2+dhN8uzix29ynN5x0V42rBJWHDt6VnYMGDeKdd96hpKSEiRMnctRRR7F9+3Zuuukm3n33XX788Ueuvvpqrrjiil2uYi0rK2P06NEsWbKEbt268fXXXzN+/PjwVaI333wzM2bMoGXLlrz88su0b98e8JIW77rrLjZv3sy9997LiBEjKC8v58orr6SoqIgWLVpw7733cswxxzB58mReeOEFtm7dyvbt23nvvfd2+zt88803jBw5ks2bN1NVVcUjjzzCUUcdxZ577slll12223HwIwtmz57NOeecw9ChQ7nhhhvYunUr7dq1Y/LkyXTo0IEJEybw2GOPUVFRwcEHH8yTTz5Jbm4uX3zxBeeeey5bt24Nxy2kg5KySnKyMmiZnRkq6OqhS/DUQ49ixYoVXHXVVSxfvpy99tprtzz0IUOGcOONN/L222+zYMEC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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"soil.analysis.plot(it[0])"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"hideCode": false,
"hidePrompt": false,
"run_control": {
"frozen": true
}
},
"source": [
"## Running in more scenarios\n",
"\n",
"In real life, you probably want to run several simulations, varying some of the parameters so that you can compare and answer your research questions.\n",
"\n",
"For instance:\n",
" \n",
"* Does the outcome depend on the structure of our network? We will use different generation algorithms to compare them (Barabasi-Albert and Erdos-Renyi)\n",
"* How does neighbor spreading probability affect my simulation? We will try probability values in the range of [0, 0.4], in intervals of 0.1."
]
},
{
"cell_type": "code",
"execution_count": 109,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"class NewsEnvComplete(soil.Environment):\n",
" prob_tv = 0.05\n",
" prob_tv_spread = 0\n",
" prob_neighbor_spread = 0\n",
" event_time = 10\n",
" tv_factor = 0\n",
" neighbor_factor = 0.5\n",
" generator = \"erdos_renyi_graph\"\n",
" n = 100\n",
"\n",
" def init(self):\n",
" self.add_agent(EventGenerator)\n",
" if not self.G:\n",
" opts = {\"n\": self.n}\n",
" if self.generator == \"erdos_renyi_graph\":\n",
" opts[\"p\"] = 0.5\n",
" elif self.generator == \"barabasi_albert_graph\":\n",
" opts[\"m\"] = 4\n",
" self.create_network(generator=self.generator, **opts)\n",
"\n",
" self.populate_network([NewsSpread,\n",
" NewsSpread.w(has_tv=True)],\n",
" [1-self.prob_tv, self.prob_tv])\n",
" self.add_model_reporter('prob_tv_spread')\n",
" self.add_model_reporter('prob_neighbor_spread')\n",
" self.add_agent_reporter('state_id')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since we do not care about previous results, we will set`overwrite=True`."
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[INFO ][17:29:24] Output directory: /mnt/data/home/j/git/lab.gsi/soil/soil/examples/tutorial/soil_output\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "5528388b3491489caecc160a2d19ee7a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, description='newspread', max=10, style=ProgressStyle(description_width='in…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = erdos_renyi_graph\n",
"\r",
"prob_neighbor_spread = 0\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = erdos_renyi_graph\n",
"\r",
"prob_neighbor_spread = 0.25\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = erdos_renyi_graph\n",
"\r",
"prob_neighbor_spread = 0.5\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = erdos_renyi_graph\n",
"\r",
"prob_neighbor_spread = 0.75\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = erdos_renyi_graph\n",
"\r",
"prob_neighbor_spread = 1.0\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = barabasi_albert_graph\n",
"\r",
"prob_neighbor_spread = 0\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = barabasi_albert_graph\n",
"\r",
"prob_neighbor_spread = 0.25\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = barabasi_albert_graph\n",
"\r",
"prob_neighbor_spread = 0.5\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = barabasi_albert_graph\n",
"\r",
"prob_neighbor_spread = 0.75\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
"n = 100\n",
"\r",
"generator = barabasi_albert_graph\n",
"\r",
"prob_neighbor_spread = 1.0\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(IntProgress(value=0, max=5), HTML(value='')))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"s = soil.Simulation(model=NewsEnvComplete, iterations=5, max_time=30, dump=True, overwrite=True)\n",
"N = 100\n",
"probabilities = [0, 0.25, 0.5, 0.75, 1.0]\n",
"generators = [\"erdos_renyi_graph\", \"barabasi_albert_graph\"]\n",
"\n",
"\n",
"it = s.run(name=f\"newspread\", matrix=dict(n=[N], generator=generators, prob_neighbor_spread=probabilities))"
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"assert len(it) == len(probabilities) * len(generators) * s.iterations"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T11:05:18.043194Z",
"start_time": "2017-07-03T13:05:18.034699+02:00"
},
"cell_style": "center",
"hideCode": false,
"hidePrompt": false
},
"source": [
"The results are conveniently stored in sqlite (history of agent and environment state) and the configuration is saved in a YAML file.\n",
"\n",
"You can also export the results to GEXF format (dynamic network) and CSV using .`run(dump=['gexf', 'csv'])` or the command line flags `--graph --csv`."
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {
"ExecuteTime": {
"end_time": "2017-11-01T14:05:56.404540Z",
"start_time": "2017-11-01T15:05:56.122876+01:00"
},
"cell_style": "split",
"hideCode": false,
"hidePrompt": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[01;34msoil_output\u001b[00m\n",
"└── \u001b[01;34mnewspread\u001b[00m\n",
" ├── newspread_1681989837.124865.dumped.yml\n",
" ├── newspread_1681990513.1584163.dumped.yml\n",
" ├── newspread_1681990524.5204282.dumped.yml\n",
" ├── newspread_1681990796.858183.dumped.yml\n",
" ├── newspread_1682002299.544348.dumped.yml\n",
" ├── newspread_1682003721.597205.dumped.yml\n",
" ├── newspread_1682003784.1948986.dumped.yml\n",
" ├── newspread_1682003812.4626257.dumped.yml\n",
" ├── newspread_1682004020.182087.dumped.yml\n",
" ├── newspread_1682004044.6837814.dumped.yml\n",
" ├── newspread_1682004398.267355.dumped.yml\n",
" ├── newspread_1682004564.1052232.dumped.yml\n",
" └── newspread.sqlite\n",
"\n",
"1 directory, 13 files\n",
"21M\tsoil_output/newspread\n"
]
}
],
"source": [
"!tree soil_output\n",
"!du -xh soil_output/*"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-02T10:40:14.384177Z",
"start_time": "2017-07-02T12:40:14.381885+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"### Analysing the results"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"#### Loading data"
]
},
{
"cell_type": "markdown",
"metadata": {
"hideCode": false,
"hidePrompt": false
},
"source": [
"Once the simulations are over, we can use soil to analyse the results.\n",
"\n",
"There are two main ways: directly using the iterations returned by the `run` method, or loading up data from the results database.\n",
"This is particularly useful to store data between sessions, and to accumulate results over multiple runs.\n",
"\n",
"The mainThe main method to load data from the database is `read_sql`, which can be used in two ways:\n",
"\n",
"* `analysis.read_sql(<sqlite_file>)` to load all the results from a sqlite database . e.g. `read_sql('my_simulation/file.db.sqlite')`\n",
"* `analysis.read_sql(name=<simulation name>)` will look for the default path for a simulation named `<simulation name>`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The result in both cases is a named tuple with four dataframes:\n",
"\n",
"* `configuration`, which contains configuration parameters per simulation\n",
"* `parameters`, which shows the parameters used **in every iteration** of every simulation\n",
"* `env`, with the data collected from the model in each iteration (as specified in `model_reporters`)\n",
"* `agents`, like `env`, but for `agent_reporters`"
]
},
{
"cell_type": "markdown",
"metadata": {
"ExecuteTime": {
"end_time": "2017-07-03T14:44:30.978223Z",
"start_time": "2017-07-03T16:44:30.971952+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"source": [
"Let's see it in action by loading the stored results into a pandas dataframe:"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"ExecuteTime": {
"end_time": "2017-10-19T15:57:44.101253Z",
"start_time": "2017-10-19T17:57:44.039710+02:00"
},
"hideCode": false,
"hidePrompt": false
},
"outputs": [],
"source": [
"res = soil.read_sql(name=\"newspread\", include_agents=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Plotting data\n",
"\n",
"Once we have loaded the results from the file, we can use them just like any other dataframe.\n",
"\n",
"Here is an example of plotting the ratio of infected users in each of our simulations:"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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z+HDh3nooYc4dOgQ7dq1s2uWzJw5kx07drB//35KS0tZt26d/RiDwcDOnTt57LHHuPzyy/n999/ZvXs3kyZN4qWXXrL77d27l40bN7J161YWLFjA2bNn8fDwYM2aNezatYtNmzbx2GOPIaXk22+/pWPHjiQnJ7N//36uu+66esX//PPPs3PnTvbu3ctPP/3E3r17a/gUFxczaNAgDhw4wFVXXWVP+vfffz+LFi0iKSmJV155hYceOr+EQ2pqKr/99htffPEFDz74ILNnz2bPnj1VkjlcmG76tGnTiIuL45///CdNLbWiKnRFk5G1+ygaocGzowflZUZ0uvPjzvdlfo/FXMIYHmnBCC8SnFXUbl7O7d5B9arIq9O5c2dGjBgBwF133cXrr7/O448/zqZNm3jppZcoKSkhJyeHqKgobrrpJsCqh15BamoqEydOJC0tDYPBQEREhN02btw4PD098fT0ZNSoUWzfvp2xY8fy9NNP8/PPP6PRaDhz5gzp6elER0fz2GOP8eSTT3LjjTfWSJy18emnn/LOO+9gMplIS0vj4MGDxMTEVPHRaDT2mO+66y5uvfVWioqK+O2337j99vO/esrLzz+cv/322xslH1ydFStW0KlTJwoLC7ntttv46KOPuOeee+o+sIGoCl3RZBQcPgeAf4B1VRl9h452WxC5WIRr15JU1B9RbWFXIQRlZWU89NBDrF69mn379nHfffdRVlZm96msXz5r1ixmzpzJvn37ePvtt6v4OWp7xYoVZGZmkpSUxJ49e2jfvj1lZWX07t2bXbt2ER0dzTPPPMOCBQvqjP3EiRO88sor/Pjjj+zdu5exY8dWOb+za7ZYLPj7+7Nnzx7736FDhxxeozPqq5tesc/X15c77riD7du316v9hqISuqLJMJ8ro9RShHux9aeorlNXu61D4HBuiPgbOSdOtVR4lzSnTp1i61brxK6PP/6Yyy+/3J4Ug4ODKSoqYvXq1bUen5+fb09WH3zwQRXb2rVrKSsrIzs7m82bNzN48GDy8/MJDQ1Fr9ezadMmu/762bNn8fLy4q677mLOnDm1jhapTEFBAd7e3vj5+ZGens769esd+lksFvs1VFxju3btiIiIsGu7SylJTk52eLyvry+FhYUObfXRTTeZTGRlZQFgNBpZt25dk40uqkAldEWTcSIvmYx2ZzGdSQFA16WX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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"for (g, group) in res.env.dropna().groupby(\"params_id\"):\n",
" params = res.parameters.query(f'params_id == \"{g}\"').iloc[0]\n",
" title = f\"{params.generator.rstrip('_graph')} {params.prob_neighbor_spread}\"\n",
" prob = group.groupby(by=[\"step\"]).prob_neighbor_spread.mean()\n",
" line = \"-\"\n",
" if \"barabasi\" in params.generator:\n",
" line = \"--\"\n",
" prob.rename(title).fillna(0).plot(linestyle=line)\n",
"plt.title(\"Mean probability for each configuration\")\n",
"plt.legend();"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"hideCode": false,
"hidePrompt": false,
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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48Zyz+GMnQ6HQ1577bVy+/bt5+0HyM8//1xKKeVLL70kH374YSmllAMGDJD79++XUkq5bt062b9/fymllKNHj5Y333yzdDgcnnM5c13O5eabb5a///675/OAAQPKtPfaa6+VHTt2lJ07d5ZTp071XLOqUta9AmyS5fjVSnvoUkoH8AiwHNiLNptltxBiqhBiiLva48B4IcR24Eu3c78iQyoVcWTRErJ9vPCLLz82vvbEWgA1IKqoUWJiYujbV7sP7777bv744w8AVqxYQUJCAnFxcfz666/s3r3bs8/w4cM975OTkxk0aBBxcXG8/vrrpeoNHToUb29vQkND6d+/Pxs2bEBKybPPPkunTp247rrrSElJ4dSpU8TFxfHTTz/x1FNP8fvvv3t0zyvjq6++omvXrnTp0oXdu3eXGW/X6XQem8+cY35+PmvWrOHOO+8kPj6eBx98sFTP+s4777wk+eBzmTNnDjt37uT333/n999/57PPPqu2tsuiSoEwKeUytMHOktteKPF+D6BG8CrAmZND8pH9EBHMgJvKD7esPrGaYK9g2ga3rUXrFFca547fCCGwWq089NBDbNq0iZiYGKZMmYLVavXUKalfPnHiRP7+978zZMgQVq5cyZQpUypse86cOaSlpbF582aMRiPNmjXDarXSunVrtmzZwrJly3juuedITEzkhRdeoCIOHz7MG2+8wcaNGwkKCmLMmDGl7KzonF0uF4GBgWzbtq3MOiXPsSKqqpt+Zpufnx933XUXGzZs4N577z2vXnWhMkVribxfV3AywEKxOYj2bZuXWcclXaw9sZbekb3RCfXVKGqOY8eOsXat9jT4xRdfcNVVV3mcYmhoKPn5+cyfP7/c/XNycjzO6pNPPilVtmjRIqxWKxkZGaxcuZIePXqQk5NDeHg4RqORFStWePTXT5w4gcVi4e6772by5MnlzhYpSW5uLj4+PgQEBHDq1Cm+//77Muu5XC7POZw5R39/f2JjYz3a7lJKtm/fXub+fn5+5OXllVlWFd10h8NBeno6AHa7naVLl9bY7KIzKK9RSxxdvJgcixc+FYRb9mXuI9OaSd9I9bCjqFnatGnDzJkzadeuHVlZWUyYMIHAwEDGjx9Px44dGTRokGeJurKYMmUKd955J926dSM0tPT8h06dOtG/f3969erF888/T2RkJKNGjWLTpk3E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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"for (g, group) in res.agents.dropna().groupby(\"params_id\"):\n",
" params = res.parameters.query(f'params_id == \"{g}\"').iloc[0]\n",
" title = f\"{params.generator.rstrip('_graph')} {params.prob_neighbor_spread}\"\n",
" counts = group.groupby(by=[\"step\", \"state_id\"]).value_counts().unstack()\n",
" line = \"-\"\n",
" if \"barabasi\" in params.generator:\n",
" line = \"--\"\n",
" (counts.infected/counts.sum(axis=1)).rename(title).fillna(0).plot(linestyle=line)\n",
"plt.legend()\n",
"plt.xlim([9, None]);\n",
"plt.title(\"Ratio of infected users\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Data format"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Parameters\n",
"\n",
"The `parameters` dataframe has three keys:\n",
"\n",
"* The identifier of the simulation. This will be shared by all iterations launched in the same run\n",
"* The identifier of the parameters used in the simulation. This will be shared by all iterations that have the exact same set of parameters.\n",
"* The identifier of the iteration. Each row should have a different iteration identifier\n",
"\n",
"There will be a column per each parameter passed to the environment. In this case, that's three: **generator**, **n** and **prob_neighbor_spread**."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th>key</th>\n",
" <th>generator</th>\n",
" <th>n</th>\n",
" <th>prob_neighbor_spread</th>\n",
" </tr>\n",
" <tr>\n",
" <th>iteration_id</th>\n",
" <th>params_id</th>\n",
" <th>simulation_id</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"5\" valign=\"top\">0</th>\n",
" <th>39063f8</th>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>erdos_renyi_graph</td>\n",
" <td>100</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5db645d</th>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>barabasi_albert_graph</td>\n",
" <td>100</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8f26adb</th>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>barabasi_albert_graph</td>\n",
" <td>100</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>cb3dbca</th>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>erdos_renyi_graph</td>\n",
" <td>100</td>\n",
" <td>0.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>d1fe9c1</th>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>barabasi_albert_graph</td>\n",
" <td>100</td>\n",
" <td>1.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
"key generator \\\n",
"iteration_id params_id simulation_id \n",
"0 39063f8 newspread_1682002299.544348 erdos_renyi_graph \n",
" 5db645d newspread_1682002299.544348 barabasi_albert_graph \n",
" 8f26adb newspread_1682002299.544348 barabasi_albert_graph \n",
" cb3dbca newspread_1682002299.544348 erdos_renyi_graph \n",
" d1fe9c1 newspread_1682002299.544348 barabasi_albert_graph \n",
"\n",
"key n prob_neighbor_spread \n",
"iteration_id params_id simulation_id \n",
"0 39063f8 newspread_1682002299.544348 100 1.0 \n",
" 5db645d newspread_1682002299.544348 100 0.0 \n",
" 8f26adb newspread_1682002299.544348 100 0.5 \n",
" cb3dbca newspread_1682002299.544348 100 0.5 \n",
" d1fe9c1 newspread_1682002299.544348 100 1.0 "
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"res.parameters.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Configuration\n",
"\n",
"This dataset is indexed by the identifier of the simulation, and there will be a column per each attribute of the simulation.\n",
"For instance, there is one for the number of processes used, another one for the path where the results were stored, etc."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>index</th>\n",
" <th>version</th>\n",
" <th>source_file</th>\n",
" <th>name</th>\n",
" <th>description</th>\n",
" <th>group</th>\n",
" <th>backup</th>\n",
" <th>overwrite</th>\n",
" <th>dry_run</th>\n",
" <th>dump</th>\n",
" <th>...</th>\n",
" <th>num_processes</th>\n",
" <th>exporters</th>\n",
" <th>model_reporters</th>\n",
" <th>agent_reporters</th>\n",
" <th>tables</th>\n",
" <th>outdir</th>\n",
" <th>exporter_params</th>\n",
" <th>level</th>\n",
" <th>skip_test</th>\n",
" <th>debug</th>\n",
" </tr>\n",
" <tr>\n",
" <th>simulation_id</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>newspread_1682002299.544348</th>\n",
" <td>0</td>\n",
" <td>2</td>\n",
" <td>None</td>\n",
" <td>newspread</td>\n",
" <td></td>\n",
" <td>None</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>...</td>\n",
" <td>1</td>\n",
" <td>[&lt;class 'soil.exporters.default'&gt;]</td>\n",
" <td>{}</td>\n",
" <td>{}</td>\n",
" <td>{}</td>\n",
" <td>/mnt/data/home/j/git/lab.gsi/soil/soil/example...</td>\n",
" <td>{}</td>\n",
" <td>20</td>\n",
" <td>False</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>1 rows × 29 columns</p>\n",
"</div>"
],
"text/plain": [
" index version source_file name description \\\n",
"simulation_id \n",
"newspread_1682002299.544348 0 2 None newspread \n",
"\n",
" group backup overwrite dry_run dump ... \\\n",
"simulation_id ... \n",
"newspread_1682002299.544348 None False True False True ... \n",
"\n",
" num_processes exporters \\\n",
"simulation_id \n",
"newspread_1682002299.544348 1 [<class 'soil.exporters.default'>] \n",
"\n",
" model_reporters agent_reporters tables \\\n",
"simulation_id \n",
"newspread_1682002299.544348 {} {} {} \n",
"\n",
" outdir \\\n",
"simulation_id \n",
"newspread_1682002299.544348 /mnt/data/home/j/git/lab.gsi/soil/soil/example... \n",
"\n",
" exporter_params level skip_test debug \n",
"simulation_id \n",
"newspread_1682002299.544348 {} 20 False False \n",
"\n",
"[1 rows x 29 columns]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"res.config.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Model reporters\n",
"\n",
"The `env` dataframe includes the data collected from the model.\n",
"The keys in this case are the same as `parameters`, and an additional one: **step**."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>agent_count</th>\n",
" <th>time</th>\n",
" <th>prob_tv_spread</th>\n",
" <th>prob_neighbor_spread</th>\n",
" </tr>\n",
" <tr>\n",
" <th>simulation_id</th>\n",
" <th>params_id</th>\n",
" <th>iteration_id</th>\n",
" <th>step</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"5\" valign=\"top\">newspread_1682002299.544348</th>\n",
" <th rowspan=\"5\" valign=\"top\">fcfc955</th>\n",
" <th rowspan=\"5\" valign=\"top\">0</th>\n",
" <th>0</th>\n",
" <td>101</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>101</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>101</td>\n",
" <td>2</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>101</td>\n",
" <td>3</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>101</td>\n",
" <td>4</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" agent_count time \\\n",
"simulation_id params_id iteration_id step \n",
"newspread_1682002299.544348 fcfc955 0 0 101 0 \n",
" 1 101 1 \n",
" 2 101 2 \n",
" 3 101 3 \n",
" 4 101 4 \n",
"\n",
" prob_tv_spread \\\n",
"simulation_id params_id iteration_id step \n",
"newspread_1682002299.544348 fcfc955 0 0 0.0 \n",
" 1 0.0 \n",
" 2 0.0 \n",
" 3 0.0 \n",
" 4 0.0 \n",
"\n",
" prob_neighbor_spread \n",
"simulation_id params_id iteration_id step \n",
"newspread_1682002299.544348 fcfc955 0 0 0.0 \n",
" 1 0.0 \n",
" 2 0.0 \n",
" 3 0.0 \n",
" 4 0.0 "
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"res.env.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Agent reporters\n",
"\n",
"This dataframe reflects the data collected for all the agents in the simulation, in every step where data collection was invoked.\n",
"\n",
"The key in this dataframe is similar to the one in the `parameters` dataframe, but there will be two more keys: the `step` and the `agent_id`.\n",
"There will be a column per each agent reporter added to the model. In our case, there is only one: `state_id`."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>state_id</th>\n",
" </tr>\n",
" <tr>\n",
" <th>simulation_id</th>\n",
" <th>params_id</th>\n",
" <th>iteration_id</th>\n",
" <th>step</th>\n",
" <th>agent_id</th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"5\" valign=\"top\">newspread_1682002299.544348</th>\n",
" <th rowspan=\"5\" valign=\"top\">fcfc955</th>\n",
" <th rowspan=\"5\" valign=\"top\">0</th>\n",
" <th rowspan=\"5\" valign=\"top\">0</th>\n",
" <th>0</th>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>neutral</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" state_id\n",
"simulation_id params_id iteration_id step agent_id \n",
"newspread_1682002299.544348 fcfc955 0 0 0 None\n",
" 1 neutral\n",
" 2 neutral\n",
" 3 neutral\n",
" 4 neutral"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"res.agents.head()"
]
}
],
"metadata": {
"hide_code_all_hidden": false,
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.8.10"
},
"toc": {
"colors": {
"hover_highlight": "#DAA520",
"navigate_num": "#000000",
"navigate_text": "#333333",
"running_highlight": "#FF0000",
"selected_highlight": "#FFD700",
"sidebar_border": "#EEEEEE",
"wrapper_background": "#FFFFFF"
},
"moveMenuLeft": true,
"nav_menu": {
"height": "31px",
"width": "252px"
},
"navigate_menu": true,
"number_sections": true,
"sideBar": true,
"threshold": 4,
"toc_cell": false,
"toc_position": {
"height": "867px",
"left": "0px",
"right": "1670px",
"top": "106px",
"width": "250px"
},
"toc_section_display": "block",
"toc_window_display": false,
"widenNotebook": false
},
"vscode": {
"interpreter": {
"hash": "3581132406f7320837865a422f37590c78ed7dabfbcb5bc7771b9d116b13a5cf"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}