Skip to main content

results

results

Results: the values a sim records at each time point (ss.Result), the containers that hold them (ss.Results), and how they are compared with data (ss.SimData)

These exist so that a result knows its own time points, scale, and how to resample and plot itself, whichever solver wrote it.

Used with: agents and compartments; declared and coded modules

Classes

Name Description
Result Array-like container for holding sim results.
Results The results of a module (or of the sim, whose results also hold each module’s), by name; a result can be found however it is spelled (see find())
SimData Data to compare with a sim’s results, matched by name: each column is named like the result it corresponds to
Summary The table of sim.summarize() and msim.summarize(): a dataframe, shown with its numbers rounded to sensible units (see format_value()); its values are not rounded
SummarySeries A row or column of a Summary, shown the same way

Result

results.Result(
    name=None,
    label=None,
    dtype=float,
    shape=None,
    scale='auto',
    auto_plot=True,
    module=None,
    values=None,
    timevec=None,
    low=None,
    high=None,
    kind='auto',
    summarize_by='auto',
    columns=None,
    runs=None,
    groups=False,
    **kwargs,
)

Array-like container for holding sim results.

Parameters

Name Type Description Default
module str the name or label of the parent module, e.g. ‘SIR’ None
name str the name of this result, e.g. ‘infection’ None
shape int / tuple the shape of the result array (usually module.npts) None
scale bool whether the result scales with the population (by pop_scale, the people each agent stands for): by default (‘auto’), by its kind, so a flow or stock (a count, e.g. infections) does, and a ratio (e.g. prevalence) does not 'auto'
auto_plot bool whether sim.plot() shows it by default; False keeps a result that is rarely wanted (e.g. a cumulative total) out of the default plots True
label str a human-readable label for the result None
values array prepopulate the Result with these values None
timevec array an array of time points None
low array values for the lower bound None
high array values for the upper bound None
kind str what the result is, which decides how it behaves: ‘flow’ (a number of events in each step, e.g. new infections; it has a cumulative total, and is summed over each period of data it is compared with), ‘stock’ (a quantity at each time point, e.g. the number infected), ‘ratio’ (one quantity divided by another, e.g. prevalence or a mean; one that keeps its numerator and denominator sums each over a period, then divides), or None for a result with no meaning over time. The kind also sets the default scale and summarize_by. By default (‘auto’) it is guessed from summarize_by if only that is given, or else from the name (new_... is a flow; n_..., cum_..., and cumulative are stocks; and ...prevalence is a ratio), or else from the dtype: an integer is a count, guessed to be a flow, a dtype that is not numbers (e.g. list) has none, and anything else is a ratio; a guess from the dtype is warned about, so give kind= for any other name (e.g. ss.Result('vaccinated', dtype=int, kind='stock')). The results of a declared module are made with their kind 'auto'
summarize_by str how the result is summarized over time (and resampled), if not as its kind is: by default (‘auto’), ‘sum’ for a flow, ‘last’ for a stock, ‘mean’ for a ratio, and None for none; or another way, e.g. ‘mean’ to average a flow over time, or any other key of ss.Result.summarizers 'auto'
columns list if provided, make a 2D result of shape (npts, len(columns)), with these names for the columns, e.g. ['wild', 'alpha'] None
runs dataframe for a result across the runs of a MultiSim: one row per run, with its scenario (and the values of any parameters swept); the values then have a run axis first, of shape (n_runs, npts) None
groups bool for a module written as code in a stratified sim: keep the values by group too, so they can be selected (res.select(sex='female'), res.by('age')) as a declared module’s are; set them with set_groups() False

In most cases, ss.Result behaves exactly like np.array(), except with the additional fields listed above. To see everything in a result, use result.disp().

For a 2D result, res.alpha, res['alpha'], or res.select(column='alpha') returns a 1D result for that column (which shares data with the 2D result), and res[ti] returns the row for that timestep. The columns of a result split by a dimension (res.by('age')) are selected by it, e.g. res.by('age').select(age=0).

Examples

res = ss.Result('infection', kind='flow', columns=['wild', 'alpha'], shape=10)
res[3] = [20, 5] # Set the values for timestep 3
res['alpha'][4] = 8 # Set one value for timestep 4
res['alpha'].label # Returns 'infection (alpha)'

A result across the runs of a MultiSim (msim.results.sir.I) is the same result with a run axis first: select() also takes run= (a position), scenario=, and the parameters swept; quantiles(), median(), and mean() summarize over the runs of each scenario; and plot() draws the median and a 95% interval of each scenario (lines=True draws every run).

```python
msim = ss.parallel(sim, n_runs=10)
I = msim.results.sir.I # Runs by time points
I.select(run=3) # One run, as a result of one sim
low, mid, high = I.quantiles([0.025, 0.5, 0.975])
I.median().plot()
```

Attributes

Name Description
column_dim The dimension of the columns of a 2D result, for select(): the one it was split by (see by()), else column
cum The cumulative total of a flow over time, e.g. sim.results.sir.infection.cum (a stock; computed when asked for)
full_label The full label of the result: :
group_timevec The time points of the values by group: every one, or the end of every few steps (see select())
has_dates Whether the time points are dates (rather than numbers)
initialized True if values have been set
key The unique key of the result: ., e.g. “hiv.infection”
n_runs The number of runs, for a result across the runs of a MultiSim; None for a result of one run
t_axis The axis of the time points: 0, or 1 for a result across runs

Methods

Name Description
axes The dimensions of this result, whichever way they are kept, for select() and by(): for each, its levels, and a function that gives the result for a list of them
by Split a stratified result by one dimension, summing over the rest; returns a 2D result with one column per level
diff The difference of each other scenario from the baseline, run by run (the runs are paired by position), for a result across runs
disp Print every attribute of the result
map Draw the result on a map of its places: its summary over the run (as summarize() gives it), at given times, at several, or as an animation
mean For a result across runs, the mean over the runs of each scenario (as a result of one run, if there is one scenario); otherwise the mean of the values
median For a result across runs, the median over the runs of each scenario (as a result of one run, if there is one scenario); otherwise the median of the values
periods Which period of a longer time unit each time point is in; see resample()
plot Plot the result, with one line per column for a 2D result
quantiles Quantiles over the runs of each scenario, for a result across the runs of a MultiSim
resample Resample the result to a longer time unit, by its summarize_by (which by default follows its kind)
reserved The attributes of every result, which a destination’s flow (res.cin.X) cannot be named like
scenarios The positions of the runs of each scenario, in order
select Select groups of a stratified result by name: keeps the given levels of each dimension, and sums over the rest
set_groups Set the value at time point ti from values by group (one for each of sim.groups, e.g. from sim.groups.count()), and keep them, for a result made with groups=True
summarize The result over the whole run, by its summarize_by: the total of a flow (‘sum’), the final value of a stock (‘last’),
take Some of the runs of a result across runs: a result of one run for a position, or across runs for a list of them
to_df The result as a dataframe, with columns for the time, value, and (if it has them) low and high bounds
to_series The result as a pandas Series, with the time points as the index
to_str The result as one line of text (see __str__())
update Set attributes of the result, and make its values if it has none yet
axes
results.Result.axes()

The dimensions of this result, whichever way they are kept, for select() and by(): for each, its levels, and a function that gives the result for a list of them

A result has the destinations of a transition with several (to), the parts of a treatment of several diseases or transitions (disease, edge), the scenarios and parameters of a result across runs, the groups of a stratified result, and the columns of a 2D result (by the dimension it was split by with by(), else column). The values themselves have only the axes of t_axis and columns.

by
results.Result.by(dim)

Split a stratified result by one dimension, summing over the rest; returns a 2D result with one column per level

Parameters
Name Type Description Default
dim str the dimension, e.g. ‘age’; or, for the results of a treatment of several diseases or transitions, ‘disease’ or ‘edge’ required

For a result across runs, the columns come after the runs and time points, so res.by('age').young is a result across runs. For strains carried together (ss.Strains(max_strains=2)), the columns are the strains, and a person who carries several is in each, so the columns add up to more than the total; select() takes the sets of strains carried (e.g. select(strain='A+B')), each person once.

diff
results.Result.diff(baseline)

The difference of each other scenario from the baseline, run by run (the runs are paired by position), for a result across runs

Parameters
Name Type Description Default
baseline str the label of the baseline scenario required

Returns a dict of results across runs, one per scenario other than the baseline.

disp
results.Result.disp()

Print every attribute of the result

map
results.Result.map(
    t=None,
    animate=False,
    shapes=None,
    names=None,
    cmap='Reds',
    vmin=0,
    vmax=None,
    n=None,
    fps=8,
    ax=None,
    **kwargs,
)

Draw the result on a map of its places: its summary over the run (as summarize() gives it), at given times, at several, or as an animation

The result needs to be stratified by place, with a geography (sir.stratify(patch=ss.geo.geography(...))). Each place is drawn as its shape, if the geography has one, or else as a point sized by its population, and colored by the result there. Since places differ in size, a fraction (e.g. prevalence) usually shows the spread better than a count.

Parameters
Name Type Description Default
t date / list the time (or times) to draw, e.g. '2025-03-01'; by default, one map of the summary of each place over the run (the total of a flow, the mean of a ratio, the final value of a stock) None
animate bool draw an animation instead; in a notebook it is shown with controls to play it, and otherwise returned (a Matplotlib FuncAnimation) False
shapes bool whether to draw shapes (see ss.geo.geography.plot()) None
names bool whether to label the places by name (by default, on a single map with 15 places or fewer) None
cmap str the colormap 'Reds'
vmin float the value at the bottom of the color scale 0
vmax float the value at the top of the color scale (by default, the largest value drawn) None
n int the number of times to draw, evenly across the period when anything happens, instead of the summary (e.g. n=6); for an animation, 60 frames by default None
fps int for an animation, the frames per second 8
ax Axes for a single map or an animation, draw into these axes None
kwargs dict passed to ss.plot_args(), e.g. figsize, or filename to save it (for an animation, e.g. ‘spread.gif’ or ‘spread.mp4’, which needs ffmpeg)
Examples
towns = ss.geo.geography(names=['a', 'b', 'c'], populations=[50_000, 30_000, 20_000], x=[0, 0, 40], y=[0, 30, 0])
S, I, R = ss.states(3)
sir = ss.Disease(S >> I @ 0.3*I, I >> R @ ss.days(10), init_n=dict(I=ss.by(patch=[10, 0, 0])))
sir.stratify(patch=ss.levels(towns, mobility=ss.geo.gravity(away=0.01)))
sim = ss.Sim(sir, start='2025-01-01', stop='2025-07-01').run()
sim.results.sir.prevalence.map() # The mean prevalence in each town over the run
sim.results.sir.prevalence.map(n=6) # Six maps, from the start of the outbreak to its end
sim.results.sir.prevalence.map(animate=True, filename='spread.gif') # As an animation, saved to a file
mean
results.Result.mean(*args, **kwargs)

For a result across runs, the mean over the runs of each scenario (as a result of one run, if there is one scenario); otherwise the mean of the values

Parameters
Name Type Description Default
args list passed to the mean of the values, for a result not across runs
kwargs dict passed to the mean of the values, for a result not across runs
median
results.Result.median(*args, **kwargs)

For a result across runs, the median over the runs of each scenario (as a result of one run, if there is one scenario); otherwise the median of the values

Parameters
Name Type Description Default
args list passed to np.median(), for a result not across runs
kwargs dict passed to np.median(), for a result not across runs
periods
results.Result.periods(new_unit)

Which period of a longer time unit each time point is in; see resample()

Returns the period of each time point (a non-decreasing array of integers from 0); for calendar months and years, the date each period starts (the first day of its month or year; else None); and whether each period is whole, i.e. its steps cover it (to within half a step).

Parameters
Name Type Description Default
new_unit str / dur the new unit; see resample() required
plot
results.Result.plot(
    fig=None,
    ax=None,
    label=None,
    lines=False,
    log=False,
    **kwargs,
)

Plot the result, with one line per column for a 2D result

For a result across runs, plot the median and a 95% interval of each scenario, or every run if lines=True; for quantiles, the middle one and the interval between the outer ones.

Parameters
Name Type Description Default
fig Figure if provided, plot into this figure’s current axes (made if it has none) None
ax Axes if provided, plot into these axes None
label str the label of the line (shown in a legend, if given) None
lines bool for a result across runs, plot every run instead of the median and interval False
log bool if True, use a log scale for the y axis False
kwargs dict known arguments (e.g. figsize, color, lw, font, plot_kw, do_show, or filename) split between the plotting dicts; see ss.plot_args()

Returns the figure, unless it is shown in Jupyter (see ss.return_fig()). A figure or axes given are the caller’s, so the figure is not shown (unless do_show=True), and other results can be plotted into it.

Examples
sim = ss.Sim(diseases='sis', networks='random').run()
sim.results.sis.prevalence.plot(color='k')

# Two results on the same axes, saved to a file
fig = sim.results.sis.I.plot(label='Infectious', do_show=False)
sim.results.sis.S.plot(fig=fig, label='Susceptible', log=True, filename='sis.png')
quantiles
results.Result.quantiles(q=(0.025, 0.5, 0.975))

Quantiles over the runs of each scenario, for a result across the runs of a MultiSim

Parameters
Name Type Description Default
q list the quantiles (0.025, 0.5, 0.975)

Returns a result with one row per quantile, e.g. low, mid, high = res.quantiles(). With several scenarios, there is a row for each quantile and scenario, the quantile first, so the same unpacking gives a result for each quantile with a row per scenario (low.select(scenario='vaccine')).

resample
results.Result.resample(new_unit=None, summarize_by=None, use_years=False)

Resample the result to a longer time unit, by its summarize_by (which by default follows its kind)

A flow is summed over each period, a stock takes its value at the start of each period (a cumulative total, e.g. res.infection.cum, its value at the end), and a ratio sums its numerator and denominator over each period (by group, if it has them) and divides them (one with no parts is averaged over the period). Periods start at the sim’s start and include their start, as for data, as each time point holds the step that starts there; calendar months and years are used instead for a sim with dates. Each period is labeled by its start: for calendar months and years, the first day of the month or year (so a year of weekly steps is labeled 1 January, not the first week of the year), or the start of the run if later; otherwise its first time point. Only whole periods are kept: a monthly run from 2000 to 2020 has 20 years, as its last step (from 2020) is one month of 2020, while a yearly one has 21 (unless no period is whole, when all are kept). The values by group (select() and by()) are resampled too.

Parameters
Name Type Description Default
new_unit str / dur the new unit: ‘day’, ‘week’, ‘month’, ‘year’, or a duration, e.g. ss.weeks(2) None
summarize_by str resample this way instead of by the result’s own, e.g. ‘mean’ to average a stock over each period None
use_years bool label the periods by their year (as integers) False
Returns
Name Type Description
Result a new Result with resampled values
Examples
res = sim.results.sir
res.infection.resample('week') # Weekly totals
res.I.resample('week') # The number infected at the start of each week
reserved
results.Result.reserved()

The attributes of every result, which a destination’s flow (res.cin.X) cannot be named like

scenarios
results.Result.scenarios()

The positions of the runs of each scenario, in order

select
results.Result.select(run=None, **dims)

Select groups of a stratified result by name: keeps the given levels of each dimension, and sums over the rest

A list of levels gives one result, their total (e.g. coarser age groups). For strains carried together (ss.Strains(max_strains=2)), the levels are the sets of strains carried ('A', 'B', 'A+B'; ordered by when each was acquired, e.g. 'B+A' as well, if there are more strains than can be carried at once), so each person is counted once; by() has a column for each strain instead, counting a person who carries several in each.

The values by group are kept at every time point, or, if that would take too much memory, every few steps (see ss.solvers.group_rows() and the sim parameter group_results); then the result has a value at the start of each of these periods, which for a flow is its total over the period.

For a result across the runs of a MultiSim, also select runs: by position (run=3, a result of one run), by scenario (scenario='vaccine'), or by the value of a parameter swept (beta=0.3).

Parameters
Name Type Description Default
run int / list for a result across runs, the position of a run (or a list of them) None
dims dict the dimension and the level (or list of levels) to keep, by label or by position, e.g. age=0 or risk='high'; or a scenario or parameter value, for a result across runs
Examples
res = sim.results.sir
res.I.select(age=0) # The youngest age group
res.I.select(age=[0, 1]) # The first two age groups, added up (e.g. under 15, with stratify(age=[0, 10, 15]))
res.I.select(strain=['A', 'A+B']) # Those who carry strain A, with ss.Strains(['A', 'B'], max_strains=2), each counted once
res.I.select(sex='female', risk='high')
msim.results.sir.I.select(beta=0.3).quantiles() # The runs with beta = 0.3
res.cin.select(to='X') # The flow to one destination of a transition with several, as res.cin.X is
res.syndromic.cured.select(disease='ct') # A treatment's results for one disease (or edge=) of several
set_groups
results.Result.set_groups(ti, vals, denom=None)

Set the value at time point ti from values by group (one for each of sim.groups, e.g. from sim.groups.count()), and keep them, for a result made with groups=True

The value is their total; or, given the denominator of each group, a ratio: the total of the values over the total of the denominators (e.g. the prevalence among everyone), with both kept, so that selecting groups adds up each before dividing.

Parameters
Name Type Description Default
ti int the time point required
vals array the value of each group (for a ratio, its numerator) required
denom array for a ratio, the denominator of each group None
Examples
# In a module written as code, in a sim stratified by sex and age
def init_results(self):
    super().init_results()
    self.define_results(ss.Result('n_infected', groups=True), ss.Result('prevalence', scale=False, groups=True))

def record_states(self):
    super().record_states()
    alive, infected = self.sim.groups.count(), self.sim.groups.count(self.infected)
    self.results.n_infected.set_groups(self.ti, infected)
    self.results.prevalence.set_groups(self.ti, infected, alive)

sim.results.sis.prevalence.select(sex='female', age='15-24') # Women aged 15-24 infected, over all women aged 15-24
summarize
results.Result.summarize()

The result over the whole run, by its summarize_by: the total of a flow (‘sum’), the final value of a stock (‘last’), and the mean of a ratio (‘mean’; over time, of its numerator and denominator if it has them, each summed and then divided); one for each run, for a result across runs (and with several scenarios, a dict of these by scenario, as diff() gives); and for a result by group (res.by('age')), a pandas Series labeled by group

take
results.Result.take(inds)

Some of the runs of a result across runs: a result of one run for a position, or across runs for a list of them

Parameters
Name Type Description Default
inds int / list the position or positions of the runs required
to_df
results.Result.to_df(
    sep='_',
    col_names='vlh',
    bounds=True,
    resample=None,
    set_date_index=False,
    quantiles=None,
    **kwargs,
)

The result as a dataframe, with columns for the time, value, and (if it has them) low and high bounds

For a result across runs, a long dataframe instead: one row per run and time point (columns run, scenario, any parameters swept, time, and value), or with quantiles=, one row per scenario, quantile, and time point (columns scenario, time, quantile, and value).

Parameters
Name Type Description Default
sep str separator for the column names '_'
col_names str or None the names of the columns: ‘vlh’ (default) for value, low, and high; None for the name of the result (e.g. infection and infection_low); or another name to use instead 'vlh'
bounds bool include the low and high bounds, if the result has them True
resample str if provided, resample the data to this unit first (see resample()), e.g. ‘year’ None
set_date_index bool if True, use the times as the index False
quantiles list for a result across runs, the quantiles over the runs of each scenario None
kwargs dict passed to resample(), if resample is given

For a 2D result, there is one set of dataframe columns per result column, e.g. alpha and alpha_low (or infection_alpha and infection_alpha_low if col_names='infection').

to_series
results.Result.to_series(set_name=False, resample=None, sep='_', **kwargs)

The result as a pandas Series, with the time points as the index

Parameters
Name Type Description Default
set_name bool whether to name the series after the result False
resample str if provided, resample the data to this unit first (see resample()), e.g. ‘year’ None
sep str the separator between the name and column in each column of a 2D result '_'
kwargs dict passed to resample()

For a 2D result, return a dataframe with one column per result column, e.g. infection_alpha.

to_str
results.Result.to_str(label=True)

The result as one line of text (see __str__())

Parameters
Name Type Description Default
label bool whether to include the label True
update
results.Result.update(*args, **kwargs)

Set attributes of the result, and make its values if it has none yet

Parameters
Name Type Description Default
args list the attributes to update, as a dict
kwargs dict the attributes to update, by name

Results

results.Results(module=None, *args, **kwargs)

The results of a module (or of the sim, whose results also hold each module’s), by name; a result can be found however it is spelled (see find())

Parameters

Name Type Description Default
module Module / str the module the results belong to, or its name None
args list passed to ss.ndict
kwargs dict passed to ss.ndict

Attributes

Name Description
all_results Iterator over all results, skipping any nested values

Methods

Name Description
append This is activated by adding as well, e.g. results += result
disp Print the results in full
find A result, however it is spelled: by its name ('I'), with its module ('seir.I'), or as a column of to_df() ('seir_I', or 'sis_infection_alpha' for a column of a 2D result), in any case; a flow’s name followed by .cum ('sis.infection.cum') is its cumulative total
flatten Turn from a nested dictionary into a flat dictionary, keeping only results by default; keys keep their case, as in to_df() (e.g. sis_I)
matches The results a name could be, by their names in to_df(): those that have this name in full (seir.I, seir_I, or a column, sis_infection_alpha), else those of the sim’s one disease, else those of any module; see find()
plot Plot the results, each in its own axes; see sim.plot() and msim.plot()
resample Resample all the results to a longer time unit (e.g. ‘year’), each by its summarize_by, returning a new Results object; see ss.Result.resample(); results not summarized over time (summarize_by=None) are left out, as in sim.summarize()
scenario_colors For results across the runs of several scenarios, the color of each scenario, from the colors of the current style, so that each has the same color in every axes; else None
to_df All the results, as one dataframe with a column for each: e.g. alive for the sim’s own, sir_prevalence for a module’s,
walk Each result, as (module name, key, result), with the module None for the sim’s own results
append
results.Results.append(arg, key=None)

This is activated by adding as well, e.g. results += result

Parameters
Name Type Description Default
arg Result / list / tuple the result, or the arguments to make one required
key str the key to add it under (default: its name) None
disp
results.Results.disp(*args, **kwargs)

Print the results in full

Parameters
Name Type Description Default
args list passed to str() of the ss.ndict
kwargs dict passed to str() of the ss.ndict
find
results.Results.find(name, die=True)

A result, however it is spelled: by its name ('I'), with its module ('seir.I'), or as a column of to_df() ('seir_I', or 'sis_infection_alpha' for a column of a 2D result), in any case; a flow’s name followed by .cum ('sis.infection.cum') is its cumulative total

The name without its module is enough if it names one result, or one of the sim’s one disease (the one it made or named, else its only one; see ss.Sim.init_results()). This is what sim.results[name], sim.plot(name), sim.summarize(name), and a column of data all go through.

Parameters
Name Type Description Default
name str the name of the result required
die bool whether to raise an error if the name is not of exactly one result, saying which it could be; otherwise, None True
flatten
results.Results.flatten(
    sep='_',
    only_results=True,
    only_auto=False,
    columns=False,
    **kwargs,
)

Turn from a nested dictionary into a flat dictionary, keeping only results by default; keys keep their case, as in to_df() (e.g. sis_I)

If columns=True, split each 2D result into one 1D result per column, e.g. sis_infection_alpha.

Parameters
Name Type Description Default
sep str the separator between the parts of each key '_'
only_results bool whether to keep only results True
only_auto bool whether to keep only results that are plotted by default False
columns bool whether to split each 2D result into one per column False
kwargs dict resample= to resample each result, with any other keywords for ss.Result.resample()
matches
results.Results.matches(name)

The results a name could be, by their names in to_df(): those that have this name in full (seir.I, seir_I, or a column, sis_infection_alpha), else those of the sim’s one disease, else those of any module; see find()

Across the runs of a MultiSim, the sim’s one disease is each sim’s, even if their names differ (see ss.run.MultiResults.from_sims()).

Parameters
Name Type Description Default
name str the name, in any case required
plot
results.Results.plot(
    key=None,
    fig=None,
    data=None,
    label=None,
    title=None,
    lines=False,
    legend=True,
    show_skipped=False,
    annualize=False,
    log=False,
    marks=None,
    **kwargs,
)

Plot the results, each in its own axes; see sim.plot() and msim.plot()

A result across runs is plotted as the median and a 95% interval of each scenario, or every run if lines=True.

Parameters
Name Type Description Default
key str / list the result (e.g. 'sir.I') or results to plot (by default, those plotted automatically); a module’s name plots its results; if a list, plot exactly those, with the results in a list within it in the same axes (e.g. [['sir.S', 'sir.I'], 'sir.infection']) None
fig Figure if provided, plot into an existing figure None
data dict data to plot with the results: the times and values for each result, by the result’s module and name (see sim.plot()) None
label str the label of the lines of a result of one run (e.g. the sim’s) None
title str the title of the figure None
lines bool for a result across runs, plot every run instead of the median and interval False
legend bool whether to label the scenarios, if there is more than one True
show_skipped bool show even results that are not plotted by default False
annualize bool if True, resample the results to annual values first (each by its summarize_by; see ss.Result.resample()) False
log bool if True, use a log scale for the y axes False
marks dict times to mark on each axes, by scenario (None for those of every scenario, in gray): a time as a dashed line, a (start, stop) pair as a shaded span (see intervention_marks()) None
kwargs dict known arguments (e.g. figsize, font, do_show, or filename) split between the plotting dicts; see ss.plot_args()

Returns the figure, unless it is shown in Jupyter (see ss.return_fig()); a figure given is not shown, unless do_show=True.

resample
results.Results.resample(new_unit, **kwargs)

Resample all the results to a longer time unit (e.g. ‘year’), each by its summarize_by, returning a new Results object; see ss.Result.resample(); results not summarized over time (summarize_by=None) are left out, as in sim.summarize()

Parameters
Name Type Description Default
new_unit str / dur the new unit; see ss.Result.resample() required
kwargs dict passed to ss.Result.resample()
scenario_colors
results.Results.scenario_colors()

For results across the runs of several scenarios, the color of each scenario, from the colors of the current style, so that each has the same color in every axes; else None

to_df
results.Results.to_df(sep='_', set_date_index=False, **kwargs)

All the results, as one dataframe with a column for each: e.g. alive for the sim’s own, sir_prevalence for a module’s, and bysex_n_infected_male for each column of a 2D result

If the modules have different time points (e.g. different time steps), a dict of dataframes instead, one for the sim’s own results and one for each module; resampled, one dataframe of the periods they all have (e.g. 50 whole years for a monthly module in a yearly sim from 2000 to 2050, as its year from 2050 is one month).

Parameters
Name Type Description Default
sep str separator for the column names '_'
set_date_index bool if True, use the times as the index rather than as the column time False
kwargs dict passed to ss.Result.resample(), e.g. resample='year'
walk
results.Results.walk()

Each result, as (module name, key, result), with the module None for the sim’s own results

SimData

results.SimData(source, aliases=None, ignore_extra=False)

Data to compare with a sim’s results, matched by name: each column is named like the result it corresponds to

Parameters

Name Type Description Default
source str / df a file name or a dataframe, with a time column (date, year, t, or time) and one column per data series; an integer year column is calendar years, each row compared with the whole year it names required
aliases dict for headers that do not match: the result (or time-column) name, and the column that holds it None
ignore_extra bool if True, drop columns that match no result (otherwise they are noted, and an error when a fit compares them with the results) False

Examples

data = ss.SimData('kenya_2020.csv', aliases=dict(cases='Reported Cases (weekly)', date='Week ending'), ignore_extra=True)
sim = ss.Sim(sir, data=data, start='2020-01-01', stop='2020-12-31')

Methods

Name Description
drop_extra Drop the columns that match no result of the sim
load The data as a dataframe: read from the file (or copied from the dataframe given), with the columns of aliases renamed, and with ignore_extra, the columns that match no result of the sim left out
drop_extra
results.SimData.drop_extra(sim, df)

Drop the columns that match no result of the sim

load
results.SimData.load(sim=None)

The data as a dataframe: read from the file (or copied from the dataframe given), with the columns of aliases renamed, and with ignore_extra, the columns that match no result of the sim left out

Parameters
Name Type Description Default
sim Sim the sim the data is for (needed to leave out columns with ignore_extra) None

Summary

results.Summary()

The table of sim.summarize() and msim.summarize(): a dataframe, shown with its numbers rounded to sensible units (see format_value()); its values are not rounded

SummarySeries

results.SummarySeries()

A row or column of a Summary, shown the same way

Functions

Name Description
add_count Add the number of agents uids to result res at time index ti, each by their weight if agents’ weights differ (see agent_weights()), as a module written as code counts e.g. its new infections
agent_weights Each agent’s weight (people.scale), by UID, if agents’ weights differ; else None. A module written as code counts each agent by its weight when they differ, as alive does
as_float Make a count result hold floats (a sum of agents’ weights need not be whole), keeping its values; returns it
by_year Whether the data is by calendar year: an integer year column, so each row is the year it names, not 1 January of it
check_data Check that every data column matches a result, and that the data overlaps the simulated period
column_levels The levels of a stratum as ss.Result.select() takes them: by label, or by position if no label matches
compare Line up a sim’s results with its data
cumulative Whether a stock is a cumulative total (res.infection.cum, or named cum_... or cumulative), which counts the steps up to and including its own, so is resampled by its value at the end of each period
data_times The times of the data, on the sim’s own time axis (the result timevec as numbers), or on the timeline of a result whose module has a timestep of its own
date_years Dates as years, kept for the next call with the same dates (each evaluation of a fit compares with the same data)
distinct The different values of a column of runs, in order; told apart by how they print, since a rate (ss.peryear) cannot be hashed
draw_marks Mark times on axes: a time as a dashed line, a (start, stop) pair as a shaded span, in each scenario’s color (gray for those of every scenario; see Results.plot())
flow_at_data For a flow with data at a longer period than the sim’s step (e.g. weekly cases from a daily model): the rows of
flow_periods For plotting a flow with data at a longer period than the step (see flow_at_data()): the times of each period of the run at the
format_axes Standard formatting for axis results: commas on the y axis, and the result as the title, with its module if the label is short; not for the user
format_value A number as a summary shows it: a whole number of people, or one of 100 or more, to the nearest whole number with commas (e.g. 19,536); a smaller one to 3 significant figures (e.g. 0.136)
get_ax The axes to plot a result into: those given, else the figure’s current axes (made if it has none), else those of a new figure
given_data The sim’s data, or data given to compare with it, with its time column (e.g. year) as the index, as the sim’s own data has
in_people Mark results as written in people, so they are not scaled again at the end
intervention_marks When the interventions and modifiers of a sim act, for marking on plots: those with fixed times (see ss.Event.marks() and ss.modify.marks(); an intervention written as code can define its own marks()); a (start, stop) span as its start time, unless fill=True
lineup The matrix that lines up each result that has data with its data, which compare() uses
log_scale A log scale for the y axis, down to at most decades powers of 10 below its top, since a model’s values can fall to 1e-20 (e.g. the number infectious in an ODE between epidemics)
match_column Find the result that a data column corresponds to: “cases”, or “sir.cases” if the name is used by more than one module, or the sum over some groups, “cases[age=0-15]”
match_name The result a column corresponds to, by name; see match_column() and ss.Results.find()
match_result_keys The results named by a key or list of keys (see ss.Results.find()), or all of a module’s, or with no key, every one that is plotted by default (or every one, with show_skipped), by their names in to_df()
parse_column A column’s result and stratum: “cases[age=0-15]” gives “cases” and {‘age’: ‘0-15’}
people_scale What a declared result is multiplied by when written: the people each agent stands for, or 1
period_totals What the totals of a flow over the periods of its data are, for the titles of plots: e.g. ‘weekly totals, as in the data’
plot_data The data of a sim, by the result each column matches, for ss.Results.plot(): its times and values, and for a flow with
resamplable Whether a result can be resampled as part of all the results: not if it is not summarized over time and no summarize_by= is given
set_scale A log scale for the y axis, if asked for (see log_scale()); otherwise, keep the axis from going negative if the result doesn’t (see ss.Result._floor())
spellings Each result, however deep (and each column of a 2D result), as a tuple: its name in to_df(), that name without its module, its module, and the result
split_columns Results by name, with each 2D result split into one 1D result per column, e.g. sis_infection_alpha
sum_steps The values of a result (by time, or by run and time) summed with the weights of lineup(): only the steps used, so a value missing elsewhere is not read
summary_funcs The functions of how= in sim.summarize() and msim.summarize(), by the key of each result in results.flatten(sep='_', columns=True)
time_weights The weights of the steps for each data time (see lineup()), and which data times are inside the simulated period
validate_sim_data Data to compare with the sim’s results (e.g. for calibration), as a dataframe with its time column as the index, and times written as dates (e.g. ‘2020-01-08’) as ss.dates, so they can be plotted against the sim’s
widen_data Data in long form, with columns that say which stratum each row is for (named after dimensions of the sim, e.g. age), as one column for each result and stratum, e.g. cases[age=0-15]

add_count

results.add_count(res, ti, uids, sim)

Add the number of agents uids to result res at time index ti, each by their weight if agents’ weights differ (see agent_weights()), as a module written as code counts e.g. its new infections

agent_weights

results.agent_weights(sim)

Each agent’s weight (people.scale), by UID, if agents’ weights differ; else None. A module written as code counts each agent by its weight when they differ, as alive does

as_float

results.as_float(res)

Make a count result hold floats (a sum of agents’ weights need not be whole), keeping its values; returns it

by_year

results.by_year(df)

Whether the data is by calendar year: an integer year column, so each row is the year it names, not 1 January of it

check_data

results.check_data(sim, df, die=False)

Check that every data column matches a result, and that the data overlaps the simulated period

A column that matches no result is noted (data on a sim can be just for plotting, or read by a fit’s own loss=); with die=True, as when a fit compares every column with its result, it is an error.

Parameters

Name Type Description Default
sim Sim the sim required
df dataframe the data required
die bool whether a column that matches no result is an error False

column_levels

results.column_levels(sim, dims)

The levels of a stratum as ss.Result.select() takes them: by label, or by position if no label matches

compare

results.compare(sim, data=None)

Line up a sim’s results with its data

A flow (new infections, reported cases) is summed over the interval starting at each data time; a stock or ratio (a count, a prevalence) is interpolated at the data’s time. Data by calendar year (an integer year column) is compared with the year each row names: a flow summed over the year, a stock or ratio averaged over it. A column that matches no result is left out (see check_data()).

Returns a dict of {column: (data values, model values)}.

Parameters

Name Type Description Default
sim Sim the sim required
data dataframe the data (default: the sim’s) None

cumulative

results.cumulative(name)

Whether a stock is a cumulative total (res.infection.cum, or named cum_... or cumulative), which counts the steps up to and including its own, so is resampled by its value at the end of each period

data_times

results.data_times(sim, df, res=None)

The times of the data, on the sim’s own time axis (the result timevec as numbers), or on the timeline of a result whose module has a timestep of its own

date_years

results.date_years(dates)

Dates as years, kept for the next call with the same dates (each evaluation of a fit compares with the same data)

distinct

results.distinct(column)

The different values of a column of runs, in order; told apart by how they print, since a rate (ss.peryear) cannot be hashed

draw_marks

results.draw_marks(ax, marks, colors=None)

Mark times on axes: a time as a dashed line, a (start, stop) pair as a shaded span, in each scenario’s color (gray for those of every scenario; see Results.plot())

flow_at_data

results.flow_at_data(sim, col, res=None, weights=False)

For a flow with data at a longer period than the sim’s step (e.g. weekly cases from a daily model): the rows of the data it is compared at, and the model’s totals over the same periods, as compare() lines them up, so a plot shows the model as the fit compares it (rather than per step, which looks seven times too low against weekly data). None for any other result, or data at the step. With weights=True, the matrix that sums the steps (see sum_steps()) instead of the totals.

flow_periods

results.flow_periods(sim, col, res, x)

For plotting a flow with data at a longer period than the step (see flow_at_data()): the times of each period of the run at the data’s period (those of the data inside the run, and as many whole periods before and after them as the run has, e.g. a projection), and the matrix that sums the steps of each (see sum_steps()). x is the data’s times as they are plotted. None for any other result.

format_axes

results.format_axes(ax, res)

Standard formatting for axis results: commas on the y axis, and the result as the title, with its module if the label is short; not for the user

format_value

results.format_value(v)

A number as a summary shows it: a whole number of people, or one of 100 or more, to the nearest whole number with commas (e.g. 19,536); a smaller one to 3 significant figures (e.g. 0.136)

get_ax

results.get_ax(fig, ax, kw)

The axes to plot a result into: those given, else the figure’s current axes (made if it has none), else those of a new figure

given_data

results.given_data(sim, data=None)

The sim’s data, or data given to compare with it, with its time column (e.g. year) as the index, as the sim’s own data has

in_people

results.in_people(*results)

Mark results as written in people, so they are not scaled again at the end

intervention_marks

results.intervention_marks(sim, fill=False)

When the interventions and modifiers of a sim act, for marking on plots: those with fixed times (see ss.Event.marks() and ss.modify.marks(); an intervention written as code can define its own marks()); a (start, stop) span as its start time, unless fill=True

lineup

results.lineup(sim, data=None)

The matrix that lines up each result that has data with its data, which compare() uses

For a flow, it sums the steps of the interval that starts at each data time (up to the next); for a stock or ratio, it interpolates linearly between the steps either side of each data time (see time_weights()). A result of a module with a timestep of its own is lined up on that module’s timeline.

Returns a dict of {column: (W, data values, rows)}, where the model’s values at the data (those that are inside the simulated period and not missing, which are at these rows of the data) are W @ the result. A column that matches no result is left out.

log_scale

results.log_scale(ax, decades=6)

A log scale for the y axis, down to at most decades powers of 10 below its top, since a model’s values can fall to 1e-20 (e.g. the number infectious in an ODE between epidemics)

match_column

results.match_column(sim, col)

Find the result that a data column corresponds to: “cases”, or “sir.cases” if the name is used by more than one module, or the sum over some groups, “cases[age=0-15]”

match_name

results.match_name(sim, col)

The result a column corresponds to, by name; see match_column() and ss.Results.find()

match_result_keys

results.match_result_keys(results, key, show_skipped=False)

The results named by a key or list of keys (see ss.Results.find()), or all of a module’s, or with no key, every one that is plotted by default (or every one, with show_skipped), by their names in to_df()

parse_column

results.parse_column(col)

A column’s result and stratum: “cases[age=0-15]” gives “cases” and {‘age’: ‘0-15’}

people_scale

results.people_scale(sim)

What a declared result is multiplied by when written: the people each agent stands for, or 1

As agents, the results of declared modules and deliveries are scaled when written, so they are people when read during a run, and capacities and counts given to deliveries are people.

period_totals

results.period_totals(times)

What the totals of a flow over the periods of its data are, for the titles of plots: e.g. ‘weekly totals, as in the data’

plot_data

results.plot_data(sim)

The data of a sim, by the result each column matches, for ss.Results.plot(): its times and values, and for a flow with data at a longer period than the step, the times of each period of the run and the weights that sum the model over them (see flow_periods()), so the model is shown as the fit compares it with the data, over the whole run

resamplable

results.resamplable(res, kwargs=None)

Whether a result can be resampled as part of all the results: not if it is not summarized over time and no summarize_by= is given

set_scale

results.set_scale(ax, res, log=False)

A log scale for the y axis, if asked for (see log_scale()); otherwise, keep the axis from going negative if the result doesn’t (see ss.Result._floor())

spellings

results.spellings(results, prefix='', top=None)

Each result, however deep (and each column of a 2D result), as a tuple: its name in to_df(), that name without its module, its module, and the result

split_columns

results.split_columns(flat, sep='_')

Results by name, with each 2D result split into one 1D result per column, e.g. sis_infection_alpha

sum_steps

results.sum_steps(W, values)

The values of a result (by time, or by run and time) summed with the weights of lineup(): only the steps used, so a value missing elsewhere is not read

summary_funcs

results.summary_funcs(how, results)

The functions of how= in sim.summarize() and msim.summarize(), by the key of each result in results.flatten(sep='_', columns=True) (’’ for every result): each is given by name (‘mean’, ‘median’, ‘sum’, ‘last’, ‘max’, or ‘min’) or as a function of a run’s values. A result is named as for key= (e.g. ‘sir_I’ or ‘sir.I’), and a 2D result’s functions are those of each of its columns; a name that matches no result raises.

time_weights

results.time_weights(sim_t, data_t, flow, annual=False)

The weights of the steps for each data time (see lineup()), and which data times are inside the simulated period

A value of a flow at a time point is what happened over the step that starts there, as data at a time is the count over the period it starts (e.g. the cases of a week, dated by its first day). Data at a time is compared with: for a flow, the sum over the interval up to the next data time; for a stock or ratio, the value interpolated at that time. Data by calendar year (annual; see by_year()) is compared with the year it names: a flow summed over it, and a stock or ratio averaged over it.

validate_sim_data

results.validate_sim_data(data=None, die=None)

Data to compare with the sim’s results (e.g. for calibration), as a dataframe with its time column as the index, and times written as dates (e.g. ‘2020-01-08’) as ss.dates, so they can be plotted against the sim’s

Parameters

Name Type Description Default
data df / dict a dataframe (or dict) of data, with a time column (see ss.SimData) plus one column per result, e.g. “cases” or “hiv.infection” None
die bool whether to raise an error if the data cannot be converted (by default, yes); False prints the error instead, e.g. to look at data that will not load. With True, no data (None) is an error too None

widen_data

results.widen_data(sim, df)

Data in long form, with columns that say which stratum each row is for (named after dimensions of the sim, e.g. age), as one column for each result and stratum, e.g. cases[age=0-15]

A level is given by its label (or its position).