Example #1
0
    def plot_result(self, key, fig_args=None, plot_args=None):
        '''
        Simple method to plot a single result. Useful for results that aren't
        standard outputs.

        Args:
            key (str): the key of the result to plot
            fig_args (dict): passed to pl.figure()
            plot_args (dict): passed to pl.plot()

        **Example**
        ::

            sim.plot_result('doubling_time')
        '''
        fig_args = sc.mergedicts({'figsize': (16, 10)}, fig_args)
        plot_args = sc.mergedicts({'lw': 3, 'alpha': 0.7}, plot_args)
        fig = pl.figure(**fig_args)
        pl.subplot(111)
        tvec = self.results['t']
        res = self.results[key]
        y = res.values
        color = res.color
        pl.plot(tvec, y, c=color, **plot_args)
        return fig
Example #2
0
def plot_result(sim,
                key,
                fig_args=None,
                plot_args=None,
                axis_args=None,
                scatter_args=None,
                font_size=18,
                font_family=None,
                grid=False,
                commaticks=True,
                setylim=True,
                as_dates=True,
                dateformat=None,
                interval=None,
                color=None,
                label=None,
                fig=None):
    ''' Plot a single result -- see Sim.plot_result() for documentation '''

    # Handle inputs
    fig_args = sc.mergedicts({'figsize': (16, 8)}, fig_args)
    axis_args = sc.mergedicts({'top': 0.95}, axis_args)
    args = handle_args(fig_args, plot_args, scatter_args, axis_args)
    fig, figs, ax = create_figs(args,
                                font_size,
                                font_family,
                                sep_figs=False,
                                fig=fig)

    # Gather results
    res = sim.results[key]
    res_t = sim.results['t']
    if color is None:
        color = res.color

    # Reuse the figure, if available
    try:
        if fig.axes[0].get_label() == 'plot_result':
            ax = fig.axes[0]
    except:
        pass
    if ax is None:  # Otherwise, make a new one
        ax = pl.subplot(111, label='plot_result')

    # Do the plotting
    if label is None:
        label = res.name
    if res.low is not None and res.high is not None:
        ax.fill_between(res_t, res.low, res.high, color=color,
                        **args.fill)  # Create the uncertainty bound
    ax.plot(res_t, res.values, c=color, label=label, **args.plot)
    plot_data(sim, ax, key, args.scatter)  # Plot the data
    plot_interventions(sim, ax)  # Plot the interventions
    title_grid_legend(ax, res.name, grid, commaticks, setylim,
                      args.legend)  # Configure the title, grid, and legend
    reset_ticks(
        ax, sim, interval, as_dates
    )  # Optionally reset tick marks (useful for e.g. plotting weeks/months)

    return fig
Example #3
0
def handle_args(fig_args=None, plot_args=None, scatter_args=None, axis_args=None, fill_args=None,
                legend_args=None, date_args=None, show_args=None, mpl_args=None, **kwargs):
    ''' Handle input arguments -- merge user input with defaults; see sim.plot for documentation '''

    # Set defaults
    defaults = sc.objdict()
    defaults.fig     = sc.objdict(figsize=(10, 8))
    defaults.plot    = sc.objdict(lw=1.5, alpha= 0.7)
    defaults.scatter = sc.objdict(s=20, marker='s', alpha=0.7, zorder=0)
    defaults.axis    = sc.objdict(left=0.10, bottom=0.08, right=0.95, top=0.95, wspace=0.30, hspace=0.30)
    defaults.fill    = sc.objdict(alpha=0.2)
    defaults.legend  = sc.objdict(loc='best', frameon=False)
    defaults.date    = sc.objdict(as_dates=True, dateformat=None, interval=None, rotation=None, start_day=None, end_day=None)
    defaults.show    = sc.objdict(data=True, ticks=True, interventions=True, legend=True)
    defaults.mpl     = sc.objdict(dpi=None, fontsize=None, fontfamily=None) # Use Covasim global defaults

    # Handle directly supplied kwargs
    for dkey,default in defaults.items():
        keys = list(kwargs.keys())
        for kw in keys:
            if kw in default.keys():
                default[kw] = kwargs.pop(kw)

    # Merge arguments together
    args = sc.objdict()
    args.fig     = sc.mergedicts(defaults.fig,     fig_args)
    args.plot    = sc.mergedicts(defaults.plot,    plot_args)
    args.scatter = sc.mergedicts(defaults.scatter, scatter_args)
    args.axis    = sc.mergedicts(defaults.axis,    axis_args)
    args.fill    = sc.mergedicts(defaults.fill,    fill_args)
    args.legend  = sc.mergedicts(defaults.legend,  legend_args)
    args.date    = sc.mergedicts(defaults.date,    fill_args)
    args.show    = sc.mergedicts(defaults.show,    show_args)
    args.mpl     = sc.mergedicts(defaults.mpl,     mpl_args)

    # If unused keyword arguments remain, raise an error
    if len(kwargs):
        notfound = sc.strjoin(kwargs.keys())
        valid = sc.strjoin(sorted(set([k for d in defaults.values() for k in d.keys()]))) # Remove duplicates and order
        errormsg = f'The following keywords could not be processed:\n{notfound}\n\n'
        errormsg += f'Valid keywords are:\n{valid}\n\n'
        errormsg += 'For more precise plotting control, use fig_args, plot_args, etc.'
        raise sc.KeyNotFoundError(errormsg)

    # Handle what to show
    show_keys = defaults.show.keys()
    args.show = {k:True for k in show_keys}
    if show_args in [True, False]: # Handle all on or all off
        args.show = {k:show_args for k in show_keys}
    else:
        args.show = sc.mergedicts(args.show, show_args)

    # Handle global Matplotlib arguments
    args.mpl_orig = sc.objdict()
    for key,value in args.mpl.items():
        if value is not None:
            args.mpl_orig[key] = cvset.options.get(key)
            cvset.options.set(key, value)

    return args
Example #4
0
    def plot(self, windows=False, width=0.8, color='#F8A493', font_size=18, fig_args=None, axis_args=None, data_args=None):
        '''
        Simple method for plotting the histograms.

        Args:
            windows (bool): whether to plot windows instead of cumulative counts
            width (float): width of bars
            color (hex or rgb): the color of the bars
            font_size (float): size of font
            fig_args (dict): passed to pl.figure()
            axis_args (dict): passed to pl.subplots_adjust()
            data_args (dict): 'width', 'color', and 'offset' arguments for the data
        '''

        # Handle inputs
        fig_args = sc.mergedicts(dict(figsize=(24,15)), fig_args)
        axis_args = sc.mergedicts(dict(left=0.08, right=0.92, bottom=0.08, top=0.92), axis_args)
        d_args = sc.objdict(sc.mergedicts(dict(width=0.3, color='#000000', offset=0), data_args))
        pl.rcParams['font.size'] = font_size

        # Initialize
        n_plots = len(self.states)
        n_rows = np.ceil(np.sqrt(n_plots)) # Number of subplot rows to have
        n_cols = np.ceil(n_plots/n_rows) # Number of subplot columns to have
        figs = []

        # Handle windows and what to plot
        if windows:
            if self.window_hists is None:
                self.compute_windows()
            histsdict = self.window_hists
        else:
            histsdict = self.hists
        if not len(histsdict):
            errormsg = f'Cannot plot since no histograms were recorded (schuled days: {self.days})'
            raise ValueError(errormsg)

        # Make the figure(s)
        for date,hists in histsdict.items():
            figs += [pl.figure(**fig_args)]
            pl.subplots_adjust(**axis_args)
            bins = hists['bins']
            barwidth = width*(bins[1] - bins[0]) # Assume uniform width
            for s,state in enumerate(self.states):
                pl.subplot(n_rows, n_cols, s+1)
                pl.bar(bins, hists[state], width=barwidth, facecolor=color, label=f'Number {state}')
                if self.data and state in self.data:
                    data = self.data[state]
                    pl.bar(bins+d_args.offset, data, width=barwidth*d_args.width, facecolor=d_args.color, label='Data')
                pl.xlabel('Age')
                pl.ylabel('Count')
                pl.xticks(ticks=bins)
                pl.legend()
                preposition = 'from' if windows else 'by'
                pl.title(f'Number of people {state} {preposition} {date}')

        return figs
Example #5
0
def test_mergedicts():
    sc.heading('Test merging dictionaries')

    md = sc.mergedicts({'a': 1}, {'b': 2})  # Returns {'a':1, 'b':2}
    sc.mergedicts({
        'a': 1,
        'b': 2
    }, {
        'b': 3,
        'c': 4
    })  # Returns {'a':1, 'b':3, 'c':4}
    sc.mergedicts({
        'b': 3,
        'c': 4
    }, {
        'a': 1,
        'b': 2
    })  # Returns {'a':1, 'b':2, 'c':4}
    with pytest.raises(KeyError):
        sc.mergedicts({
            'b': 3,
            'c': 4
        }, {
            'a': 1,
            'b': 2
        }, overwrite=False)  # Raises exception
    with pytest.raises(TypeError):
        sc.mergedicts({'b': 3, 'c': 4}, None, strict=True)  # Raises exception

    return md
Example #6
0
File: run.py Project: willf/covasim
    def __init__(self,
                 sim=None,
                 metapars=None,
                 scenarios=None,
                 basepars=None,
                 filename=None):

        # For this object, metapars are the foundation
        default_pars = make_metapars()  # Start with default pars
        super().__init__(
            default_pars)  # Initialize and set the parameters as attributes

        # Handle filename
        self.created = sc.now()
        if filename is None:
            datestr = sc.getdate(obj=self.created,
                                 dateformat='%Y-%b-%d_%H.%M.%S')
            filename = f'covasim_scenarios_{datestr}.scens'
        self.filename = filename

        # Handle scenarios -- by default, create a baseline scenario
        if scenarios is None:
            scenarios = sc.dcp(cvd.default_scenario)
        self.scenarios = scenarios

        # Handle metapars
        self.metapars = sc.mergedicts({}, metapars)
        self.update_pars(self.metapars)

        # Create the simulation and handle basepars
        if sim is None:
            sim = cvsim.Sim()
        self.base_sim = sim
        self.basepars = sc.mergedicts({}, basepars)
        self.base_sim.update_pars(self.basepars)
        self.base_sim.validate_pars()
        self.base_sim.init_results()

        # Copy quantities from the base sim to the main object
        self.npts = self.base_sim.npts
        self.tvec = self.base_sim.tvec
        self.reskeys = self.base_sim.reskeys

        # Create the results object; order is: results key, scenario, best/low/high
        self.sims = sc.objdict()
        self.results = sc.objdict()
        for reskey in self.reskeys:
            self.results[reskey] = sc.objdict()
            for scenkey in scenarios.keys():
                self.results[reskey][scenkey] = sc.objdict()
                for nblh in ['name', 'best', 'low', 'high']:
                    self.results[reskey][scenkey][
                        nblh] = None  # This will get populated below
        return
Example #7
0
 def __init__(self,
              daily_tests,
              symp_test=100.0,
              quar_test=1.0,
              quar_policy=None,
              subtarget=None,
              ili_prev=None,
              sensitivity=1.0,
              loss_prob=0,
              test_delay=0,
              start_day=0,
              end_day=None,
              swab_delay=None,
              **kwargs):
     super().__init__(**kwargs)  # Initialize the Intervention object
     self._store_args(
     )  # Store the input arguments so the intervention can be recreated
     self.daily_tests = daily_tests  # Should be a list of length matching time
     self.symp_test = symp_test  # Set probability of testing symptomatics
     self.quar_test = quar_test  # Probability of testing people in quarantine
     self.quar_policy = quar_policy if quar_policy else 'start'
     self.subtarget = subtarget  # Set any other testing criteria
     self.ili_prev = ili_prev  # Should be a list of length matching time or a float or a dataframe
     self.sensitivity = sensitivity
     self.loss_prob = loss_prob
     self.test_delay = test_delay
     self.start_day = start_day
     self.end_day = end_day
     self.pdf = cvu.get_pdf(
         **sc.mergedicts(swab_delay)
     )  # If provided, get the distribution's pdf -- this returns an empty dict if None is supplied
     return
Example #8
0
def test_age_brackets_used_with_contact_matrix():
    """
    Test that the age brackets used in sp.Pop.generate() matches the contact matrices used.

    Note:
        This is a test to ensure that within sp.Pop.generate() uses the right age brackets. By default, without specifying nbrackets in sp.get_census_age_brackets(), the number of age brackets will not match the granularity of the contact matrix.

    """

    sp.logger.info(
        "Test that the age brackets used in sp.Pop.generate() with the contact matrices have the same number of bins as the contact matrices."
    )

    pop = sp.Pop(**pars)
    sheet_name = pop.sheet_name

    loc_pars = pop.loc_pars

    contact_matrices = sp.get_contact_matrices(sp.settings.datadir,
                                               sheet_name=sheet_name)
    contact_matrix_nbrackets = contact_matrices[list(
        contact_matrices.keys())[0]].shape[0]
    cm_age_brackets = sp.get_census_age_brackets(
        **sc.mergedicts(loc_pars, {'nbrackets': contact_matrix_nbrackets}))
    assert contact_matrix_nbrackets == len(
        cm_age_brackets
    ), f'Check failed, len(contact_matrix_nbrackets): {contact_matrix_nbrackets} does not match len(cm_age_brackets): {len(cm_age_brackets)}.'
    print(
        f'Check passed. The age brackets loaded match the number of age brackets for the contact matrices used for the location.'
    )
Example #9
0
 def __init__(self,
              symp_prob,
              asymp_prob=0.0,
              symp_quar_prob=None,
              asymp_quar_prob=None,
              quar_policy=None,
              subtarget=None,
              ili_prev=None,
              test_sensitivity=1.0,
              loss_prob=0.0,
              test_delay=0,
              start_day=0,
              end_day=None,
              swab_delay=None,
              **kwargs):
     super().__init__(**kwargs)  # Initialize the Intervention object
     self._store_args(
     )  # Store the input arguments so the intervention can be recreated
     self.symp_prob = symp_prob
     self.asymp_prob = asymp_prob
     self.symp_quar_prob = symp_quar_prob if symp_quar_prob is not None else symp_prob
     self.asymp_quar_prob = asymp_quar_prob if asymp_quar_prob is not None else asymp_prob
     self.quar_policy = quar_policy if quar_policy else 'start'
     self.subtarget = subtarget
     self.ili_prev = ili_prev
     self.test_sensitivity = test_sensitivity
     self.loss_prob = loss_prob
     self.test_delay = test_delay
     self.start_day = start_day
     self.end_day = end_day
     self.pdf = cvu.get_pdf(
         **sc.mergedicts(swab_delay)
     )  # If provided, get the distribution's pdf -- this returns an empty dict if None is supplied
     return
Example #10
0
def autolabel(ax, rects, h_offset=0, v_offset=0.3, **kwargs):
    """
    Attach a text label above each bar in *rects*, displaying its height.

    Args:
        ax                 : Matplotlib.axes object
        rects              : Matplotlib.container.BarContainer
        h_offset (float)   : The position x to place the text at.
        v_offset (float)   : The position y to place the text at.
        **fontsize (float) : Default fontsize

    Returns:
        None.

    Set the annotation according to the input parameters
    """
    method_defaults = dict(
        fontsize=10)  # in case kwargs does not have fontsize, add it
    kwargs = sc.mergedicts(method_defaults,
                           kwargs)  # let kwargs override method defaults
    kwargs = sc.objdict(kwargs)
    for rect in rects:
        height = rect.get_height()
        text = ax.annotate('{}'.format(round(height, 3)),
                           xy=(rect.get_x() + rect.get_width() / 2, height),
                           xytext=(h_offset, v_offset),
                           textcoords="offset points",
                           ha='center',
                           va='bottom')
        text.set_fontsize(kwargs.fontsize)
Example #11
0
def test_plot_school_sizes(do_show, do_save, artifact_dir):
    """
    Test that the school size distribution by type plotting method in sp.Pop
    class works for a large population. This will be a longer test that is
    run as part of our end-to-end testing suite.

    Visually show how the school size distribution generated compares to the
    data for the location being simulated.

    Notes:
        The larger the population size, the better the generated school size
        distributions by school type can match the expected data. If generated
        populations are too small, larger schools will be missed and in
        general there won't be enough schools generated to apply statistical
        tests.
    """
    sp.logger.info("Test that the school size distribution by type plotting method in sp.Pop class works. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations.")
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    if artifact_dir:
        kwargs.figdir = artifact_dir
    kwargs.screen_height_factor = 0.20
    kwargs.hspace = 0.8
    kwargs.bottom = 0.09
    kwargs.keys_to_exclude = ['uv']
    kwargs.cmap = cmr.get_sub_cmap('cmo.curl', 0.08, 1)

    fig, ax = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig, mplt.figure.Figure), 'End-to-end school sizes check failed.'
    print('Check passed. Figure made.')

    return fig, ax, pop
Example #12
0
    def __init__(self,
                 sims=None,
                 base_sim=None,
                 quantiles=None,
                 initialize=False,
                 **kwargs):

        # Handle inputs
        if base_sim is None:
            if isinstance(sims, cvs.Sim):
                base_sim = sims
                sims = None
            elif isinstance(sims, list):
                base_sim = sims[0]
            else:
                errormsg = f'If base_sim is not supplied, sims must be either a single sim (treated as base_sim) or a list of sims, not {type(sims)}'
                raise TypeError(errormsg)

        if quantiles is None:
            quantiles = make_metapars()['quantiles']

        # Set properties
        self.sims = sims
        self.base_sim = base_sim
        self.quantiles = quantiles
        self.run_args = sc.mergedicts(kwargs)
        self.results = None
        self.which = None  # Whether the multisim is to be reduced, combined, etc.

        # Optionally initialize
        if initialize:
            self.init_sims()

        return
Example #13
0
def test_household_head_ages_by_size(create_pop, do_show=False, do_save=False):
    """
    Test that the household head age distribution by household size comparison plotting method in sp.Pop class works.

    Args:
        do_show (bool) : If True, show the plot
        do_save (bool) : If True, save the plot to disk

    Returns:
        Matplotlib figure, axes, and pop object.
    """
    sp.logger.info(
        "Test the age distribution of household heads by the household size.")
    pop = create_pop
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_household_head_ages_by_size_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save

    if kwargs.do_show:
        plt.switch_backend(mplt_org_backend)
    fig, ax = pop.plot_household_head_ages_by_size(**kwargs)
    assert isinstance(
        fig, mplt.figure.Figure), 'Check failed. Figure not generated.'
    print('Check passed. Figure made.')

    return fig, ax, pop
Example #14
0
def test_plot_schools_sizes_without_types(do_show=False, do_save=False):
    """Test that without school types, all schools are put together in one group."""
    sp.logger.info(
        "Creating schools where school types are not specified. Test school size distribution plotting method without school types. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations."
    )
    pars.with_school_types = False  # need to rerun the population
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.datadir = sp.settings.datadir
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    kwargs.screen_width_factor = 0.30
    kwargs.screen_height_factor = 0.20
    kwargs.width = 5
    kwargs.height = 3.2
    kwargs.figname = f"test_all_school_size_distributions_{kwargs.location}_pop"
    fig, ax = pop.plot_school_sizes(**kwargs)

    enrollment_by_school_type = pop.count_enrollment_by_school_type()
    school_types = list(enrollment_by_school_type.keys())

    assert school_types[0] is None and len(
        school_types
    ) == 1, f"Check 3 failed. School types created: {school_types}."

    return fig, ax, pop
def test_plot_with_sppeople(create_pop, do_show=False, do_save=False):
    """
    Test plotting method works on synthpops.people.People object.

    Notes:
        With this pop type, you will need to supply more information to
        tell the method where to look for expected data.
    """
    sp.logger.info(
        "Test that the age comparison plotting method works on sp.people.People and plotting styles can be easily updated."
    )
    pop = create_pop
    people = pop.to_people()
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.datadir = sp.settings.datadir
    kwargs.figname = f"test_ages_{kwargs.location}_sppeople"
    kwargs.do_show = do_show
    kwargs.do_save = do_save

    # modify some plotting styles
    kwargs.color_1 = '#9966cc'
    kwargs.color_2 = 'indigo'
    kwargs.markersize = 4.5
    fig, ax = sp.plot_ages(people, **kwargs)
    # fig, ax = sp.plot_ages(people)  # to plot without extra information

    assert isinstance(fig, mplt.figure.Figure), 'Check failed.'
    print('Check passed. Figure made.')

    return fig, ax, people
def test_plot_ages(do_show=False, do_save=False):
    """
    Test that the age comparison plotting method in sp.Pop class works.

    Note:
        With any popdict, you will need to supply more information to
        tell the method where to look for expected data.
    """
    sp.logger.info(
        "Test that the age comparison plotting method with sp.Pop object.")
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_pop_ages_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    fig, ax = pop.plot_ages(**kwargs)
    # fig, ax = pop.plot_ages()  # to plot without extra information

    assert isinstance(fig, mplt.figure.Figure), 'Check 1 failed.'
    print('Check passed. Figure 1 made.')

    popdict = pop.to_dict()
    kwargs.datadir = sp.datadir  # extra information required
    kwargs.figname = f"test_popdict_ages_{kwargs.location}_popdict"
    kwargs.do_show = False
    fig2, ax2 = sp.plot_ages(popdict, **kwargs)
    # fig2, ax2 = sp.plot_ages(popdict)  # to plot without extra information
    if not kwargs.do_show:
        plt.close()
    assert isinstance(fig, mplt.figure.Figure), 'Check 2 failed.'
    print('Check passed. Figure 2 made.')
    return fig, ax, pop
Example #17
0
    def plot(self, sim, ax=None, **kwargs):
        '''
        Call function during plotting

        This can be used to do things like add vertical lines on days when
        interventions take place. Can be disabled by setting self.do_plot=False.

        Args:
            sim: the Sim instance
            ax: the axis instance
            kwargs: passed to ax.axvline()

        Returns:
            None
        '''
        line_args = sc.mergedicts(self.line_args, kwargs)
        if self.do_plot or self.do_plot is None:
            if ax is None:
                ax = pl.gca()
            for day in self.days:
                if day is not None:
                    if self.show_label:  # Choose whether to include the label in the legend
                        label = self.label
                    else:
                        label = None
                    ax.axvline(day, label=label, **line_args)
        return
Example #18
0
    def run(self, reduce=False, combine=False, **kwargs):
        '''
        Run the actual sims

        Args:
            reduce  (bool): whether or not to reduce after running (see reduce())
            combine (bool): whether or not to combine after running (see combine(), not compatible with reduce)
            kwargs  (dict): passed to multi_run()

        Returns:
            None (modifies MultiSim object in place)
        '''
        # Handle which sims to use -- same as init_sims()
        if self.sims is None:
            sims = self.base_sim
        else:
            sims = self.sims

        # Run
        kwargs = sc.mergedicts(self.run_args, kwargs)
        self.sims = multi_run(sims, **kwargs)

        # Reduce or combine
        if reduce:
            self.reduce()
        elif combine:
            self.combine()

        return
Example #19
0
def make_hybrid_contacts(pop_size,
                         ages,
                         contacts,
                         school_ages=None,
                         work_ages=None):
    '''
    Create "hybrid" contacts -- microstructured contacts for households and
    random contacts for schools and workplaces, both of which have extremely
    basic age structure. A combination of both make_random_contacts() and
    make_microstructured_contacts().
    '''

    # Handle inputs and defaults
    layer_keys = ['h', 's', 'w', 'c']
    contacts = sc.mergedicts({
        'h': 4,
        's': 20,
        'w': 20,
        'c': 20
    }, contacts)  # Ensure essential keys are populated
    if school_ages is None:
        school_ages = [6, 22]
    if work_ages is None:
        work_ages = [22, 65]

    # Create the empty contacts list -- a list of {'h':[], 's':[], 'w':[]}
    contacts_list = [{key: [] for key in layer_keys} for i in range(pop_size)]

    # Start with the household contacts for each person
    h_contacts, _, clusters = make_microstructured_contacts(
        pop_size, {'h': contacts['h']})

    # Make community contacts
    c_contacts, _ = make_random_contacts(pop_size, {'c': contacts['c']})

    # Get the indices of people in each age bin
    ages = np.array(ages)
    s_inds = sc.findinds((ages >= school_ages[0]) * (ages < school_ages[1]))
    w_inds = sc.findinds((ages >= work_ages[0]) * (ages < work_ages[1]))

    # Create the school and work contacts for each person
    s_contacts, _ = make_random_contacts(len(s_inds), {'s': contacts['s']})
    w_contacts, _ = make_random_contacts(len(w_inds), {'w': contacts['w']})

    # Construct the actual lists of contacts
    for i in range(pop_size):
        contacts_list[i]['h'] = h_contacts[i][
            'h']  # Copy over household contacts -- present for everyone
    for i, ind in enumerate(s_inds):
        contacts_list[ind]['s'] = s_inds[s_contacts[i]
                                         ['s']]  # Copy over school contacts
    for i, ind in enumerate(w_inds):
        contacts_list[ind]['w'] = w_inds[w_contacts[i]
                                         ['w']]  # Copy over work contacts
    for i in range(pop_size):
        contacts_list[i]['c'] = c_contacts[i][
            'c']  # Copy over community contacts -- present for everyone

    return contacts_list, layer_keys, clusters
Example #20
0
 def compute_gofs(self, **kwargs):
     ''' Compute the goodness-of-fit '''
     kwargs = sc.mergedicts(self.gof_kwargs, kwargs)
     for key in self.pair.keys():
         actual    = sc.dcp(self.pair[key].data)
         predicted = sc.dcp(self.pair[key].sim)
         self.gofs[key] = cvm.compute_gof(actual, predicted, **kwargs)
     return
 def __init__(self, label=None, show_label=True, do_plot=None, line_args=None):
     self.label = label # e.g. "Close schools"
     self.show_label = show_label # Show the label by default
     self.do_plot = do_plot if do_plot is not None else True # Plot the intervention, including if None
     self.line_args = sc.mergedicts(dict(linestyle='--', c=[0,0,0]), line_args) # Do not set alpha by default due to the issue of overlapping interventions
     self.days = [] # The start and end days of the intervention
     self.initialized = False # Whether or not it has been initialized
     return
Example #22
0
    def __init__(self, *args, **kwargs):
        """Class constructor for plotting_kwargs."""
        kwargs = sc.mergedicts(self.default_plotting_kwargs(), kwargs)

        self.update(kwargs)
        self.initialize()

        return
Example #23
0
def test_plot_school_sizes(do_show=False, do_save=False):
    """
    Test that the school size distribution by type plotting method in sp.Pop
    class works.

    Visually show how the school size distribution generated compares to the
    data for the location being simulated.

    Notes:
        The larger the population size, the better the generated school size
        distributions by school type can match the expected data. If generated
        populations are too small, larger schools will be missed and in
        general there won't be enough schools generated to apply statistical
        tests.

    """
    sp.logger.info(
        "Test that the school size distribution by type plotting method in sp.Pop class works. Note: For small population sizes, the expected and generated size distributions may not match very well given that the model is stochastic and demographics are based on much larger populations."
    )
    pop = sp.Pop(**pars)
    kwargs = sc.objdict(sc.mergedicts(pars, pop.loc_pars))
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_pop"
    kwargs.do_show = do_show
    kwargs.do_save = do_save
    kwargs.screen_height_factor = 0.20
    kwargs.hspace = 0.8
    kwargs.bottom = 0.09
    kwargs.keys_to_exclude = ['uv']
    kwargs.cmap = cmr.get_sub_cmap('cmo.curl', 0.08, 1)

    fig, ax = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig, mplt.figure.Figure), 'Check 1 failed.'
    print('Check passed. Figure 1 made.')

    # works on popdict
    sp.logger.info("Test school size distribution plotting method on popdict.")
    popdict = pop.popdict
    kwargs.datadir = sp.settings.datadir
    kwargs.do_show = False
    kwargs.figname = f"test_school_size_distributions_{kwargs.location}_popdict"
    fig2, ax2 = sp.plot_school_sizes(popdict, **kwargs)
    if not kwargs.do_show:
        plt.close()
    assert isinstance(fig2, mplt.figure.Figure), 'Check 2 failed.'
    print('Check passed. Figure 2 made.')

    sp.logger.info(
        "Test school size distribution plotting method with keys_to_exclude as a string and without comparison."
    )
    kwargs.keys_to_exclude = 'uv'
    kwargs.comparison = False
    fig3, ax3 = pop.plot_school_sizes(**kwargs)
    assert isinstance(fig3, mplt.figure.Figure), 'Check 3 failed.'
    print(
        'Check passed. Figure 3 made with keys_to_exclude as a string and without comparison.'
    )

    return fig, ax, pop
Example #24
0
def set_option(key=None, value=None, set_global=True, **kwargs):
    '''
    Set a parameter or parameters. Use ``cv.options.set('defaults')`` to reset all
    values to default, or ``cv.options.set(dpi='default')`` to reset one parameter
    to default. See ``cv.options.help()`` for more information.

    Args:
        key        (str):    the parameter to modify, or 'defaults' to reset eerything to default values
        value      (varies): the value to specify; use None or 'default' to reset to default
        set_global (bool):   if true (default), sets plotting options globally (rather than just for Covasim)
        kwargs     (dict):   if supplied, set multiple key-value pairs

    Options are (see also ``cv.options.help()``):

        - verbose:        default verbosity for simulations to use
        - font_size:      the font size used for the plots
        - font_family:    the font family/face used for the plots
        - dpi:            the overall DPI for the figure
        - show:           whether to show figures
        - close:          whether to close the figures
        - backend:        which Matplotlib backend to use

        - precision:      the arithmetic to use in calculations
        - numba_parallel: whether to parallelize Numba

    **Examples**::

        cv.options.set('font_size', 18)
        cv.options.set(font_size=18, show=False, backend='agg', precision=64)
        cv.options.set('defaults') # Reset to default options
    '''

    if key is not None:
        kwargs = sc.mergedicts(kwargs, {key: value})
    reload_required = False

    # Reset to defaults
    if key in ['default', 'defaults']:
        kwargs = orig_options  # Reset everything to default

    # Reset options
    for key, value in kwargs.items():
        if key not in options:
            keylist = orig_options.keys()
            keys = '\n'.join(keylist)
            errormsg = f'Option "{key}" not recognized; options are "defaults" or:\n{keys}\n\nSee help(cv.options.set) for more information.'
            raise sc.KeyNotFoundError(errormsg)
        else:
            if value in [None, 'default']:
                value = orig_options[key]
            options[key] = value
            if key in numba_keys:
                reload_required = True
            if key in matplotlib_keys and set_global:
                set_matplotlib_global(key, value)
    if reload_required:
        reload_numba()
    return
Example #25
0
    def __init__(self, sim, weights=None, keys=None, method=None, custom=None, compute=True, verbose=False, **kwargs):

        # Handle inputs
        self.weights    = weights
        self.custom     = sc.mergedicts(custom)
        self.verbose    = verbose
        self.weights    = sc.mergedicts({'cum_deaths':10, 'cum_diagnoses':5}, weights)
        self.keys       = keys
        self.gof_kwargs = kwargs

        # Copy data
        if sim.data is None:
            errormsg = 'Model fit cannot be calculated until data are loaded'
            raise RuntimeError(errormsg)
        self.data = sim.data

        # Copy sim results
        if not sim.results_ready:
            errormsg = 'Model fit cannot be calculated until results are run'
            raise RuntimeError(errormsg)
        self.sim_results = sc.objdict()
        for key in sim.result_keys() + ['t', 'date']:
            self.sim_results[key] = sim.results[key]
        self.sim_npts = sim.npts # Number of time points in the sim

        # Copy other things
        self.sim_dates = sim.datevec.tolist()

        # These are populated during initialization
        self.inds         = sc.objdict() # To store matching indices between the data and the simulation
        self.inds.sim     = sc.objdict() # For storing matching indices in the sim
        self.inds.data    = sc.objdict() # For storing matching indices in the data
        self.date_matches = sc.objdict() # For storing matching dates, largely for plotting
        self.pair         = sc.objdict() # For storing perfectly paired points between the data and the sim
        self.diffs        = sc.objdict() # Differences between pairs
        self.gofs         = sc.objdict() # Goodness-of-fit for differences
        self.losses       = sc.objdict() # Weighted goodness-of-fit
        self.mismatches   = sc.objdict() # Final mismatch values
        self.mismatch     = None # The final value

        if compute:
            self.compute()

        return
Example #26
0
def show_locations(location=None, output=False):
    '''
    Print a list of available locations.

    Args:
        location (str): if provided, only check if this location is in the list
        output (bool): whether to return the list (else print)

    **Examples**::

        cv.data.show_locations() # Print a list of valid locations
        cv.data.show_locations('lithuania') # Check if Lithuania is a valid location
        cv.data.show_locations('Viet-Nam') # Check if Viet-Nam is a valid location
    '''
    country_json = sc.dcp(cad.data)
    state_json = sc.dcp(sad.data)
    aliases = get_country_aliases()

    age_data = sc.mergedicts(
        state_json, country_json,
        aliases)  # Countries will overwrite states, e.g. Georgia
    household_data = sc.dcp(hsd.data)

    loclist = sc.objdict()
    loclist.age_distributions = sorted(list(age_data.keys()))
    loclist.household_size_distributions = sorted(list(household_data.keys()))

    if location is not None:
        age_available = location.lower() in [
            v.lower() for v in loclist.age_distributions
        ]
        hh_available = location.lower() in [
            v.lower() for v in loclist.household_size_distributions
        ]
        age_sugg = ''
        hh_sugg = ''
        age_sugg = f'(closest match: {sc.suggest(location, loclist.age_distributions)})' if not age_available else ''
        hh_sugg = f'(closest match: {sc.suggest(location, loclist.household_size_distributions)})' if not hh_available else ''
        print(f'For location "{location}":')
        print(
            f'  Population age distribution is available: {age_available} {age_sugg}'
        )
        print(
            f'  Household size distribution is available: {hh_available} {hh_sugg}'
        )
        return

    if output:
        return loclist
    else:
        print(
            f'There are {len(loclist.age_distributions)} age distributions and {len(loclist.household_size_distributions)} household size distributions.'
        )
        print('\nList of available locations (case insensitive):\n')
        sc.pp(loclist)
        return
Example #27
0
 def update_pars(self, pars=None, create=False, **kwargs):
     ''' Ensure that metaparameters get used properly before being updated '''
     pars = sc.mergedicts(pars, kwargs)
     if pars:
         if 'use_layers' in pars: # Reset layers
             cvpars.set_contacts(pars)
         if 'prog_by_age' in pars:
             pars['prognoses'] = cvpars.get_prognoses(by_age=pars['prog_by_age']) # Reset prognoses
         super().update_pars(pars=pars, create=create) # Call update_pars() for ParsObj
     return
Example #28
0
 def update_pars(self, pars=None, create=False, **kwargs):
     ''' Ensure that metaparameters get used properly before being updated '''
     pars = sc.mergedicts(pars, kwargs)
     if pars:
         if pars.get('pop_type'):
             cvpar.reset_layer_pars(pars, force=False)
         if pars.get('prog_by_age'):
             pars['prognoses'] = cvpar.get_prognoses(by_age=pars['prog_by_age']) # Reset prognoses
         super().update_pars(pars=pars, create=create) # Call update_pars() for ParsObj
     return
Example #29
0
def plot_compare(df, log_scale=True, fig_args=None, plot_args=None, axis_args=None, scatter_args=None,
                font_size=18, font_family=None, grid=False, commaticks=True, setylim=True,
                as_dates=True, dateformat=None, interval=None, color=None, label=None, fig=None):
    ''' Plot a MultiSim comparison -- see MultiSim.plot_compare() for documentation '''

    # Handle inputs
    fig_args  = sc.mergedicts({'figsize':(16,16)}, fig_args)
    axis_args = sc.mergedicts({'left': 0.16, 'bottom': 0.05, 'right': 0.98, 'top': 0.98, 'wspace': 0.50, 'hspace': 0.10}, axis_args)
    args = handle_args(fig_args, plot_args, scatter_args, axis_args)
    fig, figs, ax = create_figs(args, font_size, font_family, sep_figs=False, fig=fig)

    # Map from results into different categories
    mapping = {
        'cum': 'Cumulative counts',
        'new': 'New counts',
        'n': 'Number in state',
        'r': 'R_eff',
        }
    category = []
    for v in df.index.values:
        v_type = v.split('_')[0]
        if v_type in mapping:
            category.append(v_type)
        else:
            category.append('other')
    df['category'] = category

    # Plot
    for i,m in enumerate(mapping):
        not_r_eff = m != 'r'
        if not_r_eff:
            ax = fig.add_subplot(2, 2, i+1)
        else:
            ax = fig.add_subplot(8, 2, 10)
        dfm = df[df['category'] == m]
        logx = not_r_eff and log_scale
        dfm.plot(ax=ax, kind='barh', logx=logx, legend=False)
        if not(not_r_eff):
            ax.legend(loc='upper left', bbox_to_anchor=(0,-0.3))
        ax.grid(True)

    return fig
Example #30
0
    def set_font(self, *args, **font):
        """Set font styles."""
        default_font = dict(family=self.fontfamily,
                            style=self.fontstyle,
                            variant=self.fontvariant,
                            weight=self.fontweight,
                            size=self.fontsize)
        font = sc.mergedicts(default_font, font)
        mplt.rc('font', **font)

        return