News 〉Releases

Helipad 0.7 has Stackplots and Parameter Sweeps

Helipad 0.7 is here with two big features: stackplots, and parameter sweeps.

Stackplots

If you’ve wanted to plot things where the total matters, or maybe where the values add up to a constant total and you’re interested in the relative proportions, stackplots can improve the visualization.

The Deme Selection sample model introduced in Helipad 0.6 is a good example (and see that page for the “before” screenshot): the top plot depicts the proportion of altruistic versus selfish phenotypes. But the plots are mirror images of one another. A stackplot eliminates the redundancy and makes it easier to scan the model output.

To turn a plot into a stackplot, just add a stack=True argument when calling model.addPlot().

Parameter Sweeps

A parameter sweep is a common way to exploring the sensitivity of an agent-based model to its parameter values by running the model repeatedly and systematically varying one or more parameters. In NetLogo, for example, this is called BehaviorSpace.

This is now possible with Helipad’s new paramSweep function. Because possible values of any parameter are nailed down when instantiated with the addParameter function, even for numerical variables (because the min, the max, and the step are set for sliders), all paramSweep needs to know is the variable(s) to sweep and how long to run each instance. The former can sweep n-dimensional parameter spaces (i.e. every combination of possible values from n different parameters), and the latter can specify either a fixed time, or a function with arbitrary stop conditions, for example if you’re trying to see if the variable affects how long it takes to get to equilibrium.

Sweeping hundreds or thousands of parameter combinations is a time-consuming task, so to make it as fast as possible, the parameter sweep bypasses the GUI and returns the results of each run as a Pandas dataframe, whose columns can optionally be narrowed just to the data of interest.

Other Changes

Helipad 0.7 has a new createNetwork function that automatically generates an undirected and unweighted network of a specific density among agents. Helipad’s support for network types means that multiple distinct networks can be created this way, even over the same agents.

More significantly, to support the new parameter sweep functionality and to simplify the internals, the way parameters are handled internally has changed. The upshot is two things:

  1. More consistency in how callbacks and updating parameters are handled. For example, updating a parameter value in code will always update the parameter value in the GUI, where previously this was not true for sliders due to a Tkinter inconsistency.
  2. A new pattern for identifying parameters to functions.

This second feature is backward-incompatible and entails a few function removals and signature changes. First, functions that need to identify a parameter (for example model.param, model.paramSweep, and Shocks.register) now all do so with a single tuple-argument pattern, rather than the ad hoc list of optional arguments like obj, prim, breed, good, and so on.

The new parameter identification pattern looks like this:

  • A global parameter can be identified using a string or a one-element tuple. model.param('pSmooth') retrieves the value of the global pSmooth parameter.
  • The parameter values for all items – for example a per-breed or a per-good parameter – can be retrieved using a two-element tuple. model.param(('productivity', 'good')) retrieves a dict of the productivity parameter values for all goods. Note that parameters cannot be set this way.
  • The parameter value for a particular item of a per-breed or per-good tuple can be referred to using a three-element tuple. model.param(('demand', 'breed', 'hobbit'), 50) sets the demand parameter for the hobbit breed to 50.
  • Finally, because breeds apply only to specific agent primitives, when there are multiple primitives, the relevant primitive is specified using a fourth element of the tuple (this is optional when there is only one primitive). The previous example could also be specified model.param(('demand', 'breed', 'hobbit', 'agent), 50).
  • The second case can also be achieved in the event of multiple primitives by putting None as the third element. model.param(('demand', 'breed', None, 'agent)) returns a dict of the demand breed parameter values for all breeds of the agent primitive.

This simplifies the internals a good bit, and standardizes the parameter interface across several different functions. It also obviates the goodParameter and breedParameter functions, which have been removed. Your code should replace them with the new and more powerful param function.

The full list of API changes follows.

API Changes in Version 0.7

  • ⚠️ GraphRemoved Graph.graph (the list of Matplotlib AxesSubplot objects) and Graph.series (the list of Matplotlib Line objects). These are now kept track of in the Plot objects stored in Graph.plots.
  • ⚠️ HelipadRemoved the updateVar, breedParam, and goodParam methods. The latter two are replaced by a more flexible param method that can take parameter ID tuples now.
  • ⚠️ CpanelRemoved the sliders property. Parameter widgets are now stored in Param.element.
  • ⚠️ ShockReplaced the var, paramType, and prim properties, which stored attributes of the parameter, with the param property, which stores the parameter object itself.
  • ⚠️ registerReplaced the var, paramType, and prim arguments with the param argument, a standard parameter identification tuple or string.
  • ⚠️ paramReplaced the name and several undocumented arguments with the param argument, to increase flexibility and accommodate the new parameter identification pattern.
  • ⚠️ GUICloseRenamed GUIPostLaunch to GUIClose to more accurately reflect the hook's place in the flow, and passed the model instead of the GUI object.
  • PlotKeep track of the Matplotlib AxesSubplot object here rather than in a separate list in Graph.
  • SeriesKeep track of the Matplotlib Line object here rather than in a separate list in Graph, and the output series here rather than in the Line object.
  • addSeriesReturns a Series object.
  • addPlotAdded the stack argument, and returns a Plot object.
  • addGoodReturns a Good object.
  • addBreedReturns a Breed object.
  • addItemReturns either a Good or a Breed object.
  • createNetworkIntroduced.
  • ParamAdded the obj, range, and element properties, and the get, set, reset, and addKey methods.
  • paramSweepIntroduced.