Skip to main content

utils

utils

Numerical utilities and other helper functions

What is shared by the rest of the code, and doesn’t belong to any one part of it: named dictionaries of modules (ndict), warnings, cleaning input data, plotting arguments, and returning figures and tables.

Used with: agents and compartments; declared and coded modules

Classes

Name Description
Shrunk What shrink() puts in place of an attribute it removes, so that reading it says it was removed on purpose (rather than being None, or missing)
method_wrapper A method that Starsim wraps in a subclass (e.g. init(), see outermost); a subclass defines __call__(self, obj, *args, **kwargs), which calls self.func
ndict A dictionary of named items, such as a sim’s modules (sim.diseases), which can also be called for its values (sim.diseases())
outermost The outermost call to a sim’s init() (Sim’s, or a subclass’s that calls it) first keeps a copy of the sim as it is, which sim.new() copies
skipkey The name of a key for sc.search() to skip, which is equal only to a string of that name

Shrunk

utils.Shrunk(obj=None, attr=None)

What shrink() puts in place of an attribute it removes, so that reading it says it was removed on purpose (rather than being None, or missing)

Parameters

Name Type Description Default
obj object the object that was shrunken None
attr str the name of its attribute that was shrunken None

method_wrapper

utils.method_wrapper(func)

A method that Starsim wraps in a subclass (e.g. init(), see outermost); a subclass defines __call__(self, obj, *args, **kwargs), which calls self.func

It is a class rather than a closure so that a class defined in a script, which dill pickles by value (e.g. to send a sim to ss.parallel()‘s workers), pickles with its own method and not with the globals of the module that wrapped it: dill copies those, and with them, by value, any module not installed in site-packages (e.g. Sciris or Starsim installed as editable), which may not pickle at all (“cannot pickle’_thread._local’ object”).

ndict

utils.ndict(*args, type=None, **kwargs)

A dictionary of named items, such as a sim’s modules (sim.diseases), which can also be called for its values (sim.diseases())

Each item is added under its name (or the key given), and a key can be added only once, so that two modules can’t silently take the same name.

Parameters

Name Type Description Default
type type the type each item must be (a module of any type is also accepted) None
args list the items to add, each a named item, or a list or dict of them
kwargs dict more items to add, by key

Examples

networks = ndict(ss.SexualNet(), ss.PrenatalNet())
networks = ndict([ss.SexualNet(), ss.PrenatalNet()])
networks = ndict({'sexual':ss.SexualNet(), 'prenatal':ss.PrenatalNet()})

Methods

Name Description
append Add an item, or a list or dict of them
copy Shallow copy
extend Add new items to the ndict, by item, list, or dict
get Get an entry from this ndict
merge Merge another dictionary with this one
append
utils.ndict.append(arg, key=None)

Add an item, or a list or dict of them

Parameters
Name Type Description Default
arg Module / list / dict the item to add, or a list or dict of them required
key str the key to add it under (default: its name) None
copy
utils.ndict.copy()

Shallow copy

extend
utils.ndict.extend(*args, **kwargs)

Add new items to the ndict, by item, list, or dict

Parameters
Name Type Description Default
args list the items to add
kwargs dict more items to add, by key
get
utils.ndict.get(key, default=None, match_case=False)

Get an entry from this ndict

See also sim.get_module(). Note: if a type is supplied that matches more than one entry, this function only returns the first match. Use Sim.get_modules() to handle multiple matches.

Parameters
Name Type Description Default
key str / type the object to get, either a type (e.g. ss.SIR) or a string (e.g. 'sir') required
default obj what to return if not found (default None) None
match_case bool if False (default), ignore case with string matching False
Examples
sim = ss.Sim(diseases=ss.SIR(name='MySIR'), networks='random')
sim.run()

# All return sim.diseases.MySIR
sim.diseases.get('MySIR')
sim.diseases.get('mysir')
sim.diseases.get(ss.SIR)
merge
utils.ndict.merge(other)

Merge another dictionary with this one

Parameters
Name Type Description Default
other dict the dictionary to merge required

outermost

utils.outermost(func)

The outermost call to a sim’s init() (Sim’s, or a subclass’s that calls it) first keeps a copy of the sim as it is, which sim.new() copies

skipkey

utils.skipkey()

The name of a key for sc.search() to skip, which is equal only to a string of that name

sc.search() compares each key it meets with the keys to skip, so a plain name would be compared with every key of every dict in a module, including dates (e.g. an analyzer’s results by date), and a date compared with a string that is not a date raises (see ss.date). Use skipkeys(names) for a list of them.

Functions

Name Description
assigned_name The name of the variable an object being made is assigned to, e.g. “campaign” in campaign = ss.vaccinate(...),
call_fn Call a user function with the arguments it takes (see fn_args()), from those given by name
caller_names The names of the variables in the code that called the caller (depth levels above it), as a dict of the name of
copy_given The sim’s inputs merged and copied together, so the modules given are never run themselves and can be given to other sims, and refer to each other as given; with copy_modules=False, the rest is copied, but not the modules
fn_args The arguments a user function takes, in its order: those it names among names (by default self, the module whose
getframe The frame depth levels above the caller, or None if the stack is not that deep (e.g. when called from R via reticulate)
given_modules The modules among a sim’s inputs, alone or in lists or dicts (e.g. diseases=[sir, sis])
load Alias to Sciris sc.loadany(), for Starsim’s own objects
make_disease Transitions given to the sim (alone or in a list, among modules) as one disease, named from its states (e.g. “sir”), whose results are also at the top of the sim’s (sim.results.I)
named Name what is made inside by the variables of code in another language, as caller_names() does for Python’s
names_of The name of each object in some namespaces (dicts of objects by name), by its id, for an object bound to exactly one name in the last space that has it, not starting with _ (see caller_names())
nlist_to_dict Convert a list of named items (e.g. modules, states) to a dictionary; not for the user
num_str A time as text: a number (or a duration, by its value) without a needless decimal point (100, not 100.0), or a date
own_size The bytes needed to pickle a module, not counting its parameters or what it shares with the rest of the sim: the sim, its people, the other modules (e.g.
plot_args Split the keywords given to sim.plot() and other plotting functions among the parts of the plot they are for (the figure, the lines, the data, and so on)
resolve_data_col Find the column to use for a given data key, allowing for known synonyms
return_fig Do postprocessing on the figure: save it, show it, and return it; not for the user, but its arguments can be given to any plot of results
return_table Return a table to show it: in a notebook or at an interactive prompt, which show what is returned, it is only returned, so it
same_value Whether two settings have the same value (e.g. 10000 and 10000.0); False if they cannot be compared to one True or False
save Alias to Sciris sc.save()
show Show the figures made so far (plt.show()), e.g. at the end of a script that makes plots with ss.options.show = False
shrink Replace one or more object attributes in-place with an ss.utils.Shrunk() placeholder.
skipkeys Names of keys for sc.search(..., skip=dict(keys=...)) that are compared only with strings (see skipkey)
standardize_data Standardize formats of input data
takes_uids Whether a user function takes the agents (uids), so is a function of each agent, which exists only when run as agents (see fn_args())
time_str A time point as text, for what a run prints: a date as a date (without a time of day, e.g. 2020-01-08), a duration with its own unit (e.g. year 2000.02, as on a timeline in calendar years), or a number in the sim’s unit (e.g. day 27, or step 27 in a sim with no unit, whose times are days underneath)
warn Show a warning, as ss.options.warnings says: as a Python warning (default), printed, raised as an error, or not at all

assigned_name

utils.assigned_name(obj)

The name of the variable an object being made is assigned to, e.g. “campaign” in campaign = ss.vaccinate(...), read from the code that made it (the frame above its constructors) as the instruction after the call; None if the result is not stored straight in a variable (e.g. it is returned, put in a list, or passed on). It is read when the object is made, so the name is that of its first variable, whatever variable holds it later (e.g. in a loop)

call_fn

utils.call_fn(func, names=fn_names, positions=None, **values)

Call a user function with the arguments it takes (see fn_args()), from those given by name

Parameters

Name Type Description Default
func callable the function required
names tuple the arguments it can take by name fn_names
positions dict for each number of arguments, which they are by position None
values dict the value of each argument, e.g. self=mod, sim=sim, uids=uids

Example

ss.utils.call_fn(lambda self, sim: self.pars.beta*sim.people.n, self=sir, sim=sim) # Each argument is passed if it is named

caller_names

utils.caller_names(depth=1, skip=None)

The names of the variables in the code that called the caller (depth levels above it), as a dict of the name of each object by its id: its local variables, else its global ones, and only for an object bound to exactly one of them. A declared disease (ss.Disease(infection, recovery)) and a sim (ss.Sim(diseases=sir), sim.new(interventions=campaign)) look up the names of what they are given once, here; nothing else does. If the stack is not that deep (e.g. from R via reticulate), the names given by named(), if any. The code of the function skip, if that is the code above, does not count.

copy_given

utils.copy_given(*inputs, copy_modules=True)

The sim’s inputs merged and copied together, so the modules given are never run themselves and can be given to other sims, and refer to each other as given; with copy_modules=False, the rest is copied, but not the modules

fn_args

utils.fn_args(func, names=fn_names, positions=None)

The arguments a user function takes, in its order: those it names among names (by default self, the module whose function it is; sim; and uids, the agents it is for), so any of fn(sim), fn(self, sim), fn(sim, uids), fn(self, sim, uids) (or none) can be written; a function whose arguments have other names takes them by position (fn(s) is the sim, fn(s, u) the sim and the agents, fn(m, s, u) all three). Arguments with defaults (fn(sim, years=5)) are not counted. Worked out once for each function.

Parameters

Name Type Description Default
func callable the function required
names tuple the arguments it can take by name fn_names
positions dict for each number of arguments, which they are by position (by default, see fn_positions) None

getframe

utils.getframe(depth=1)

The frame depth levels above the caller, or None if the stack is not that deep (e.g. when called from R via reticulate)

given_modules

utils.given_modules(*inputs)

The modules among a sim’s inputs, alone or in lists or dicts (e.g. diseases=[sir, sis])

load

utils.load(filename, **kwargs)

Alias to Sciris sc.loadany(), for Starsim’s own objects

Since Starsim uses Sciris for saving objects, they can be loaded back using this function, e.g. a sim saved with ss.save('run.sim', sim). Another framework’s model is read with ss.import_from().

Parameters

Name Type Description Default
filename str / path the name of the file to load required
kwargs dict passed to sc.loadany()

Examples

sim = ss.load('run.sim') # A sim saved with ss.save()

make_disease

utils.make_disease(arg, names)

Transitions given to the sim (alone or in a list, among modules) as one disease, named from its states (e.g. “sir”), whose results are also at the top of the sim’s (sim.results.I)

named

utils.named(*spaces)

Name what is made inside by the variables of code in another language, as caller_names() does for Python’s

R-Starsim calls Starsim from R, whose variables Python can’t see, so it gives them here: e.g. Disease(infection, recovery) in R names the transitions infection and recovery, as in Python. Only a caller that is not Python (with no frame of its own) reads them.

Parameters

Name Type Description Default
spaces dict the objects by name, e.g. R’s global variables and then its local ones (the later ones win)

names_of

utils.names_of(*spaces)

The name of each object in some namespaces (dicts of objects by name), by its id, for an object bound to exactly one name in the last space that has it, not starting with _ (see caller_names())

nlist_to_dict

utils.nlist_to_dict(nlist, die=True)

Convert a list of named items (e.g. modules, states) to a dictionary; not for the user

num_str

utils.num_str(x)

A time as text: a number (or a duration, by its value) without a needless decimal point (100, not 100.0), or a date

own_size

utils.own_size(mod)

The bytes needed to pickle a module, not counting its parameters or what it shares with the rest of the sim: the sim, its people, the other modules (e.g. a delivery’s transitions, which belong to their disease), and results (its own too, which grow with its stratifications as well as with time); used by sim.shrink() to check that a module has let go of its arrays

plot_args

utils.plot_args(kwargs=None, _debug=False, **defaults)

Split the keywords given to sim.plot() and other plotting functions among the parts of the plot they are for (the figure, the lines, the data, and so on)

Note: the kwargs supplied to the parent function should be supplied as the first argument of this function; keyword arguments to this function are treated as default values that will be overwritten by user-supplied values in kwargs. The argument “_debug” is used internally to print debugging output, but is not typically set by the user.

Parameters

Name Type Description Default
fig_kw dict passed to sc.getrowscols(), then plt.subplots() and plt.figure()
plot_kw dict passed to plt.plot()
data_kw dict passed to plt.scatter(), for plotting the data
style_kw dict passed to sc.options.with_style(), for controlling the detailed plotting style
**kwargs dict parsed among the above dictionaries None

Returns

Name Type Description
A dict-of-dicts with plotting arguments, for use with subsequent plotting commands

Valid kwarg arguments are:

- fig: 'figsize', 'nrows', 'ncols', 'ratio', 'num', 'dpi', 'facecolor'
- plot: 'alpha', 'c', 'color', 'lw', 'linewidth', 'ls', 'linestyle', 'marker', 'markersize', 'ms'
- data: 'data_alpha', 'data_color', 'data_size'
- fill: 'fill_alpha', 'fill_color', 'fill_hatch', 'fill_lw'
- style: 'font', 'fontsize', 'interactive'
- return_fig: 'do_show', 'is_jupyter', 'filename' (see `ss.return_fig()`)

Examples

kw = ss.plot_args(kwargs, fig_kw=dict(figsize=(10,10))) # Explicit way to set figure size, passed to `plt.figure()` eventually
kw = ss.plot_args(kwargs, figsize=(10,10)) # Shortcut since known keyword

resolve_data_col

utils.resolve_data_col(data, key, col)

Find the column to use for a given data key, allowing for known synonyms

The configured column name always takes precedence; synonyms (see ss.utils.col_synonyms) are only consulted if it is absent from the data.

Parameters

Name Type Description Default
data dict the data, as a dict of columns required
key str the standardized key, e.g. “year” required
col str the configured column name, e.g. “Year” required

Returns

Name Type Description
The name of the column to use

return_fig

utils.return_fig(fig, given=False, **kwargs)

Do postprocessing on the figure: save it, show it, and return it; not for the user, but its arguments can be given to any plot of results

Parameters

Name Type Description Default
fig Figure the figure required
given bool whether the figure (or axes) was given by the caller, who then shows it, so it is not shown unless do_show=True False
do_show bool whether to show the figure (by default, ss.options.show, and in Jupyter, always)
is_jupyter bool whether in Jupyter (by default, ss.options.is_jupyter), where a figure that is shown is not also returned, so it is not displayed twice
filename str if given, save the figure to this file (with sc.savefig())

Returns the figure, unless it is shown in Jupyter; so in Jupyter, fig = sim.plot(do_show=False) gives the figure, without showing it.

return_table

utils.return_table(df, **kwargs)

Return a table to show it: in a notebook or at an interactive prompt, which show what is returned, it is only returned, so it isn’t shown twice; in a script, it is printed too (with df.to_string(**kwargs)). For summaries that print and return a table.

Parameters

Name Type Description Default
df dataframe the table required
kwargs dict passed to df.to_string()

same_value

utils.same_value(a, b)

Whether two settings have the same value (e.g. 10000 and 10000.0); False if they cannot be compared to one True or False

save

utils.save(filename, obj, **kwargs)

Alias to Sciris sc.save()

While some Starsim objects have their own save methods, this function can be used to save any arbitrary object. It can then be loaded with ss.load(). Another framework’s format is written by ss.export_to().

Parameters

Name Type Description Default
filename str / path the name of the file to save required
obj any the object to save required
kwargs dict passed to sc.save()

Examples

ss.save('run.sim', sim) # The sim, with its results

show

utils.show(**kwargs)

Show the figures made so far (plt.show()), e.g. at the end of a script that makes plots with ss.options.show = False

Parameters

Name Type Description Default
kwargs dict passed to plt.show()

shrink

utils.shrink(obj=None, attrs=None, verbose=False)

Replace one or more object attributes in-place with an ss.utils.Shrunk() placeholder.

Used to save memory or remove circular references, especially when running large numbers of sims. It is good practice to write shrink() methods for modules to remove any temporary arrays or other memory-intensive objects.

ss.utils.shrink() can be used to either manually replace an object, or replace multiple attributes of an object in-place. It is used rather than simply deleting attributes or setting them to None to make it clear that the attributes were intentionally removed.

Parameters

Name Type Description Default
obj object the object to shrink in-place (optional) None
attrs str / list the attributes of the object to shrink None
verbose bool if True, print warnings about missing attributes False

Examples

# "Shrink" (remove) the People object
sim = ss.Sim()
ss.utils.shrink(sim, 'people')

# Equivalent behavior, used manually
sim.people = ss.utils.shrink()

skipkeys

utils.skipkeys(names)

Names of keys for sc.search(..., skip=dict(keys=...)) that are compared only with strings (see skipkey)

standardize_data

utils.standardize_data(
    data=None,
    metadata=None,
    min_year=1800,
    out_of_range=0,
    default_age=0,
    default_year=2024,
)

Standardize formats of input data

Input data can arrive in many different forms. This function accepts a variety of data structures, and converts them into a Pandas Series containing one variable, based on specified metadata, or an ss.Dist if the data is already an ss.Dist object.

The metadata is a dictionary that defines columns of the dataframe or keys of the dictionary to use as indices in the output Series. It should contain:

  • metadata['data_cols']['value'] specifying the name of the column/key to draw values from
  • metadata['data_cols']['year'] optionally specifying the column containing year values; otherwise the default year will be used
  • metadata['data_cols']['age'] optionally specifying the column containing age values; otherwise the default age will be used
  • metadata['data_cols'][<arbitrary>] optionally specifying any other columns to use as indices. These will form part of the multi-index for the standardized Series output.

If a configured column is not present in the data, a known synonym is used instead if one is available (see ss.utils.col_synonyms); for example, year data labeled “Time” (as in UN World Population Prospects data) is used for a data column configured as “Year”. Explicitly configured column names always take precedence over synonyms.

If a sex column is part of the index, the metadata can also optionally specify a string mapping to convert the sex labels in the input data into the ‘m’/‘f’ labels used by Starsim. In that case, the metadata can contain an additional key like metadata['sex_keys'] = {'Female':'f','Male':'m'} which in this case would map the strings ‘Female’ and ‘Male’ in the original data into ‘m’/‘f’ for Starsim.

Parameters

Name Type Description Default
data (pandas.DataFrame, pandas.Series, dict, int, float) An associative array or a number, with the input data to be standardized. None
metadata dict Dictionary specifying index columns, the value column, and optionally mapping for sex labels None
min_year float Optionally specify a minimum year allowed in the data. Default is 1800. 1800
out_of_range float Value to use for negative ages - typically 0 is a reasonable choice but other values (e.g., np.inf or np.nan) may be useful depending on the calculation. This will automatically be added to the dataframe with an age of -np.inf 0
default_age float the age to use if the data has no age column 0
default_year float the year to use if the data has no year column 2024

Returns:

- A `pd.Series` for all supported formats of `data` *except* an `ss.Dist`. This series will contain index columns for 'year'
  and 'age' (in that order) and then subsequent index columns for any other variables specified in the metadata, in the order
  they appeared in the metadata (except for year and age appearing first).
- An `ss.Dist` instance - if the `data` input is an `ss.Dist`, that same object will be returned by this function

takes_uids

utils.takes_uids(func, **kwargs)

Whether a user function takes the agents (uids), so is a function of each agent, which exists only when run as agents (see fn_args())

time_str

utils.time_str(x, sim=None, plural=False)

A time point as text, for what a run prints: a date as a date (without a time of day, e.g. 2020-01-08), a duration with its own unit (e.g. year 2000.02, as on a timeline in calendar years), or a number in the sim’s unit (e.g. day 27, or step 27 in a sim with no unit, whose times are days underneath)

warn

utils.warn(msg, category=None, verbose=None, die=None)

Show a warning, as ss.options.warnings says: as a Python warning (default), printed, raised as an error, or not at all

Parameters

Name Type Description Default
msg str the text of the warning required
category Warning the type of warning (default: RuntimeWarning) None
verbose bool whether to print it, if ss.options.warnings is ‘print’ (default: ss.options.verbose) None
die bool if True, raise it as an error, whatever ss.options.warnings is None