Skip to content

Commit

Permalink
sphinx set up
Browse files Browse the repository at this point in the history
  • Loading branch information
Jessica Garson committed May 6, 2019
1 parent d24b8fc commit ad862ab
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 242 deletions.
188 changes: 63 additions & 125 deletions docs/tutorials/adv_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,20 @@ Grid Visualization
^^^^^^^^^^^^^^^^^^

To start with, let's have a visualization where we can watch the agents
moving around the grid. For this, you will need to create a server that
will support visualization in a web browser. Set that up in ``server.py``.
moving around the grid. For this, you will need to put your model code
in a separate Python source file; for example, ``MoneyModel.py``. Next,
either in the same file or in a new one (e.g. ``MoneyModel_Viz.py``)
import the server class and the Canvas Grid class (so-called because it
uses HTML5 canvas to draw a grid). If you're in a new file, you'll also
need to import the actual model object.

Import the server class and the Canvas Grid class (so-called because it uses
HTML5 canvas to draw a grid). If you're in a new file, you'll also need to
import the actual model object.
.. code:: ipython3
.. code:: python
# server.py
from mesa.visualization.modules import CanvasGrid
from mesa.visualization.ModularVisualization import ModularServer
from model import MoneyModel
# If MoneyModel.py is where your code is:
# from MoneyModel import MoneyModel
``CanvasGrid`` works by looping over every cell in a grid, and
generating a portrayal for every agent it finds. A portrayal is a
Expand All @@ -56,9 +57,8 @@ a function which takes an agent, and returns a portrayal object. Here's
the simplest one: it'll draw each agent as a red, filled circle which
fills half of each cell.

.. code:: python
.. code:: ipython3
# server.py
def agent_portrayal(agent):
portrayal = {"Shape": "circle",
"Color": "red",
Expand All @@ -71,7 +71,7 @@ In addition to the portrayal method, we instantiate a canvas grid with
its width and height in cells, and in pixels. In this case, let's create
a 10x10 grid, drawn in 500 x 500 pixels.

.. code:: python
.. code:: ipython3
grid = CanvasGrid(agent_portrayal, 10, 10, 500, 500)
Expand All @@ -83,38 +83,31 @@ following arguments:
- A list of module objects to include in the visualization; here, just
``[grid]``
- The title of the model: "Money Model"
- A dictionary of arguments for the model itself. In this case, ``{"N": 100, "width": 10, "height": 10}``
- Any inputs or arguments for the model itself. In this case, 100
agents, and height and width of 10.

Once we create the server, we set the port for it to listen on (you can
treat this as just a piece of the URL you'll open in the browser).
Finally, when you're ready to run the visualization, use the server's
``launch()`` method.

.. code:: python
# server.py
server = ModularServer(MoneyModel,
[grid],
"Money Model",
{"N": 100, "width": 10, "height": 10})
Finally, when you're ready to run the visualization, use the server's
``launch()`` method, in ``run.py``. In this arrangmenet, ``run.py`` is
very short!

.. code:: python
# run.py
from server import server
100, 10, 10)
server.port = 8521 # The default
server.launch()
The full code should now look like:

.. code:: python
# server.py
from MoneyModel import *
from mesa.visualization.modules import CanvasGrid
from mesa.visualization.ModularVisualization import ModularServer
from model import MoneyModel
def agent_portrayal(agent):
portrayal = {"Shape": "circle",
Expand All @@ -128,16 +121,27 @@ The full code should now look like:
server = ModularServer(MoneyModel,
[grid],
"Money Model",
{"N": 100, "width": 10, "height": 10})
100, 10, 10)
server.port = 8521 # The default
server.launch()
Now run this file; this should launch the interactive visualization
server and open your web browser automatically. (If the browser doesn't
open automatically, try pointing it at http://127.0.0.1:8521 manually.
If this doesn't show you the visualization, something may have gone
wrong with the server launch.)

You should see something like the figure below: the model title, a grid with
red circles respresenting the agents, and the model controls at the top.
You should see something like the figure below: the model title, an
empty space where the grid will be, and a control panel off to the
right.

.. figure:: files/viz_empty.png
:alt: Empty Visualization

Empty Visualization

Click the 'reset' button on the control panel, and you should see the
grid fill up with red circles, representing agents.

.. figure:: files/viz_redcircles.png
:alt: Redcircles Visualization
Expand Down Expand Up @@ -167,7 +171,6 @@ to change the portrayal based on the agent properties.

.. code:: python
# server.py
def agent_portrayal(agent):
portrayal = {"Shape": "circle",
"Filled": "true",
Expand Down Expand Up @@ -202,7 +205,6 @@ provides.

.. code:: python
# server.py
from mesa.visualization.modules import ChartModule
The basic chart pulls data from the model's DataCollector, and draws it
Expand All @@ -219,15 +221,14 @@ chart will appear underneath the grid.

.. code:: python
# server.py
chart = ChartModule([{"Label": "Gini",
"Color": "Black"}],
data_collector_name='datacollector')
server = ModularServer(MoneyModel,
[grid, chart],
"Money Model",
{"N": 100, "width": 10, "height": 10})
100, 10, 10)
Launch the visualization and start a model run, and you'll see a line
chart underneath the grid. Every step of the model, the line chart
Expand All @@ -238,54 +239,9 @@ updates along with the grid. Reset the model, and the chart resets too.

Chart Visualization


Making a parameter interactive
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

One of the reasons we want to be able to watch a model run is to conduct ad-hoc
experiments -- for example, to get an idea of how the model changes with
different parameter values. Having to stop the simulation, edit a parameter
value, and relaunch isn't an ideal way to go about it. That's why Mesa lets you
set any parameter to be interactive, using the ``UserSettableParameter`` class.

For this example, we'll add a slider that controls how ``N``, many agents there
are in the model. To do this, we need to choose the starting value (let's keep
this at 100); the minimum parameter value we'll allow (let's do 2, since one
agent alone will have nobody to trade with) and the maximum (we'll say 200);
and the increment the slider will go in (set this to 1, since there's no such
thing as a fraction of an agent). This looks like this:

.. code:: python
from mesa.visualization.UserParam import UserSettableParameter
n_slider = UserSettableParameter('slider', "Number of Agents", 100, 2, 200, 1)
To incorporate it into the model visualization interface, we make the slider
one of the model inputs, replacing the static parameter:

.. code:: python
# server.py
chart = ChartModule([{"Label": "Gini",
"Color": "Black"}],
data_collector_name='datacollector')
server = ModularServer(MoneyModel,
[grid, chart],
"Money Model",
{"N": n_slider, "width": 10, "height": 10})
When you launch the model, you'll see a slider, labeled "Number of Agents", on
the left side of the interface. Try moving the slider around, then press Reset
to restart the model with the number of agents you set. Parameter changes don't
take effect until you reset the model.

.. figure:: files/viz_slider.png
:alt: User-settable slider for parameter

User-Settable Parameter Slider

**Note:** You might notice that the chart line only starts after a
couple of steps; this is due to a bug in Charts.js which will hopefully
be fixed soon.

Building your own visualization component
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -341,7 +297,6 @@ the class itself:

.. code:: javascript
// HistogramModule.js
var HistogramModule = function(bins, canvas_width, canvas_height) {
// The actual code will go here.
};
Expand All @@ -359,14 +314,13 @@ context, which is required for doing anything with it.

.. code:: javascript
// HistogramModule.js
var HistogramModule = function(bins, canvas_width, canvas_height) {
// Create the tag:
var canvas_tag = "<canvas width='" + canvas_width + "' height='" + canvas_height + "' ";
canvas_tag += "style='border:1px dotted'></canvas>";
// Append it to body:
var canvas = $(canvas_tag)[0];
$("#elements").append(canvas);
$("body").append(canvas);
// Create the context and the drawing controller:
var context = canvas.getContext("2d");
};
Expand All @@ -383,16 +337,10 @@ created, we can create the chart object.

.. code:: javascript
// HistogramModule.js
var HistogramModule = function(bins, canvas_width, canvas_height) {
// Create the elements
// Create the tag:
var canvas_tag = "<canvas width='" + canvas_width + "' height='" + canvas_height + "' ";
canvas_tag += "style='border:1px dotted; position:relative;'></canvas>";
// Append it to body:
var canvas = $(canvas_tag)[0];
$("#elements").append(canvas);
// Create the tag:
var canvas_tag = "<canvas width='" + canvas_width + "' height='" + canvas_height + "' ";
canvas_tag += "style='border:1px dotted'></canvas>";
// Append it to body:
Expand Down Expand Up @@ -425,11 +373,7 @@ created, we can create the chart object.
};
// Create the chart object
var chart = new Chart(context, {
type: 'bar',
data: data,
options: options
});
var chart = new Chart(context).Bar(data, options);
// Now what?
};
Expand All @@ -450,21 +394,17 @@ With that in mind, we can add these two methods to the class:

.. code:: javascript
// HistogramModule.js
var HistogramModule = function(bins, canvas_width, canvas_height) {
// ...Everything from above...
this.render = function(data) {
chart.config.data.datasets[0].data = data;
for (var i in data)
chart.datasets[0].bars[i].value = data[i];
chart.update();
};
this.reset = function() {
chart.destroy();
chart = new Chart(context, {
type: 'bar',
data: data,
options: options
});
chart = new Chart(context).Bar(data, options);
};
};
Expand All @@ -491,22 +431,21 @@ inherit from, and create the new visualization class.

.. code:: python
# server.py
from mesa.visualization.ModularVisualization import VisualizationElement
from mesa.visualization.ModularVisualization import VisualizationElement
class HistogramModule(VisualizationElement):
package_includes = ["Chart.min.js"]
local_includes = ["HistogramModule.js"]
def __init__(self, bins, canvas_height, canvas_width):
self.canvas_height = canvas_height
self.canvas_width = canvas_width
self.bins = bins
new_element = "new HistogramModule({}, {}, {})"
new_element = new_element.format(bins,
canvas_width,
canvas_height)
self.js_code = "elements.push(" + new_element + ");"
class HistogramModule(VisualizationElement):
package_includes = ["Chart.min.js"]
local_includes = ["HistogramModule.js"]
def __init__(self, bins, canvas_height, canvas_width):
self.canvas_height = canvas_height
self.canvas_width = canvas_width
self.bins = bins
new_element = "new HistogramModule({}, {}, {})"
new_element = new_element.format(bins,
canvas_width,
canvas_height)
self.js_code = "elements.push(" + new_element + ");"
There are a few things going on here. ``package_includes`` is a list of
JavaScript files that are part of Mesa itself that the visualization
Expand All @@ -532,7 +471,6 @@ general, but in this case we can hard-code it to our model.

.. code:: python
# server.py
import numpy as np
class HistogramModule(VisualizationElement):
Expand All @@ -555,12 +493,12 @@ Now, you can create your new HistogramModule and add it to the server:

.. code:: python
# server.py
histogram = HistogramModule(list(range(10)), 200, 500)
server = ModularServer(MoneyModel,
[grid, histogram, chart],
"Money Model",
{"N": n_slider, "width": 10, "height": 10})
histogram = HistogramModule(list(range(10)), 200, 500)
server = ModularServer(MoneyModel,
[grid, histogram, chart],
"Money Model",
100, 10, 10)
server.launch()
Run this code, and you should see your brand-new histogram added to the
visualization and updating along with the model!
Expand Down
Loading

0 comments on commit ad862ab

Please sign in to comment.