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: |
| 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 filemean
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 weekreserved
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 severalset_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-24summarize
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).