Пример #1
0
    def _brief(self):
        '''
        Return a one-line description of a sim -- used internally and by repr();
        see sim.brief() for the user version.
        '''
        # Try to get a detailed description of the sim...
        try:
            if self.results_ready:
                infections = self.summary['cum_infections']
                deaths = self.summary['cum_deaths']
                results = f'{infections:n}⚙, {deaths:n}☠'
            else:
                results = 'not run'

            # Set label string
            labelstr = f'"{self.label}"' if self.label else '<no label>'

            start = sc.date(self['start_day'], as_date=False)
            if self['end_day']:
                end = sc.date(self['end_day'], as_date=False)
            else:
                end = sc.date(self['n_days'], start_date=start)

            pop_size = self['pop_size']
            pop_type = self['pop_type']
            string   = f'Sim({labelstr}; {start} to {end}; pop: {pop_size:n} {pop_type}; epi: {results})'

        # ...but if anything goes wrong, return the default with a warning
        except Exception as E:
            string = sc.objectid(self)
            string += f'Warning, sim appears to be malformed:\n{str(E)}'

        return string
Пример #2
0
    def date(self, ind, *args, dateformat=None, as_date=False):
        '''
        Convert one or more integer days of simulation time to a date/list of dates --
        by default returns a string, or returns a datetime Date object if as_date is True.
        See also cv.date(), which provides a partly overlapping set of date conversion
        features.

        Args:
            ind (int, list, or array): the index day(s) in simulation time (NB: strings and date objects are accepted, and will be passed unchanged)
            args (list): additional day(s)
            dateformat (str): the format to return the date in
            as_date (bool): whether to return as a datetime date instead of a string

        Returns:
            dates (str, Date, or list): the date(s) corresponding to the simulation day(s)

        **Examples**::

            sim = cv.Sim()
            sim.date(34) # Returns '2020-04-04'
            sim.date([34, 54]) # Returns ['2020-04-04', '2020-04-24']
            sim.date([34, '2020-04-24']) # Returns ['2020-04-04', '2020-04-24']
            sim.date(34, 54, as_date=True) # Returns [datetime.date(2020, 4, 4), datetime.date(2020, 4, 24)]
        '''

        # Handle inputs
        if not isinstance(ind, list): # If it's a number, string, or dateobj, convert it to a list
            ind = sc.promotetolist(ind)
        ind.extend(args)
        if dateformat is None:
            dateformat = '%Y-%m-%d'

        # Do the conversion
        dates = []
        for raw in ind:
            if sc.isnumber(raw):
                date_obj = sc.date(self['start_day'], as_date=True) + dt.timedelta(days=int(raw))
            else:
                date_obj = sc.date(raw, as_date=True)
            if as_date:
                dates.append(date_obj)
            else:
                dates.append(date_obj.strftime(dateformat))

        # Return a string rather than a list if only one provided
        if len(ind)==1:
            dates = dates[0]

        return dates
Пример #3
0
def load_data(datafile, calculate=True, check_date=True, verbose=True, start_day=None, **kwargs):
    '''
    Load data for comparing to the model output, either from file or from a dataframe.

    Args:
        datafile (str or df): if a string, the name of the file to load (either Excel or CSV); if a dataframe, use directly
        calculate (bool): whether to calculate cumulative values from daily counts
        check_date (bool): whether to check that a 'date' column is present
        start_day (date): if the 'date' column is provided as integer number of days, consider them relative to this
        kwargs (dict): passed to pd.read_excel()

    Returns:
        data (dataframe): pandas dataframe of the loaded data
    '''

    # Load data
    if isinstance(datafile, Path): # Convert to a string
        datafile = str(datafile)
    if isinstance(datafile, str):
        df_lower = datafile.lower()
        if df_lower.endswith('csv'):
            data = pd.read_csv(datafile, **kwargs)
        elif df_lower.endswith('xlsx') or df_lower.endswith('xls'):
            data = pd.read_excel(datafile, **kwargs)
        elif df_lower.endswith('json'):
            data = pd.read_json(datafile, **kwargs)
        else:
            errormsg = f'Currently loading is only supported from .csv, .xls/.xlsx, and .json files, not "{datafile}"'
            raise NotImplementedError(errormsg)
    elif isinstance(datafile, pd.DataFrame):
        data = datafile
    else: # pragma: no cover
        errormsg = f'Could not interpret data {type(datafile)}: must be a string or a dataframe'
        raise TypeError(errormsg)

    # Calculate any cumulative columns that are missing
    if calculate:
        columns = data.columns
        for col in columns:
            if col.startswith('new'):
                cum_col = col.replace('new_', 'cum_')
                if cum_col not in columns:
                    data[cum_col] = np.cumsum(data[col])
                    if verbose:
                        print(f'  Automatically adding cumulative column {cum_col} from {col}')

    # Ensure required columns are present and reset the index
    if check_date:
        if 'date' not in data.columns:
            errormsg = f'Required column "date" not found; columns are {data.columns}'
            raise ValueError(errormsg)
        else:
            if data['date'].dtype == np.int64: # If it's integers, treat it as days from the start day
                data['date'] = sc.date(data['date'].values, start_date=start_day)
            else: # Otherwise, use Pandas to convert it
                data['date'] = pd.to_datetime(data['date']).dt.date
        data.set_index('date', inplace=True, drop=False) # Don't drop so sim.data['date'] can still be accessed

    return data
Пример #4
0
def date_formatter(start_day=None, dateformat=None, ax=None):
    '''
    Create an automatic date formatter based on a number of days and a start day.

    Wrapper for Matplotlib's date formatter. Note, start_day is not required if the
    axis uses dates already. To be used in conjunction with setting the x-axis
    tick label formatter.

    Args:
        start_day (str/date): the start day, either as a string or date object
        dateformat (str): the date format
        ax (axes): if supplied, automatically set the x-axis formatter for this axis

    **Example**::

        formatter = date_formatter(start_day='2020-04-04', dateformat='%Y-%m-%d')
        ax.xaxis.set_major_formatter(formatter)

    '''

    # Set the default -- "Mar-01"
    if dateformat is None:
        dateformat = '%b-%d'

    # Convert to a date object
    start_day = sc.date(start_day)

    @ticker.FuncFormatter
    def mpl_formatter(x, pos):
        if sc.isnumber(x):
            return (start_day + dt.timedelta(days=x)).strftime(dateformat)
        else:
            return x.strftime(dateformat)

    if ax is not None:
        ax.xaxis.set_major_formatter(mpl_formatter)

    return mpl_formatter
Пример #5
0
def date_formatter(start_day=None,
                   dateformat=None,
                   interval=None,
                   start=None,
                   end=None,
                   ax=None,
                   sim=None):
    '''
    Create an automatic date formatter based on a number of days and a start day.

    Wrapper for Matplotlib's date formatter. Note, start_day is not required if the
    axis uses dates already. To be used in conjunction with setting the x-axis
    tick label formatter.

    Args:
        start_day (str/date): the start day, either as a string or date object
        dateformat (str): the date format (default '%b-%d')
        interval (int): if supplied, the interval between ticks (must supply an axis also to take effect)
        start (str/int): if supplied, the lower limit of the axis
        end (str/int): if supplied, the upper limit of the axis
        ax (axes): if supplied, automatically set the x-axis formatter for this axis
        sim (Sim): if supplied, get the start day from this

    **Examples**::

        # Automatically configure the axis with default option
        cv.date_formatter(sim=sim, ax=ax)

        # Manually configure
        ax = pl.subplot(111)
        ax.plot(np.arange(60), np.random.random(60))
        formatter = cv.date_formatter(start_day='2020-04-04', interval=7, start='2020-05-01', end=50, dateformat='%Y-%m-%d', ax=ax)
        ax.xaxis.set_major_formatter(formatter)
    '''

    # Set the default -- "Mar-01"
    if dateformat is None:
        dateformat = '%b-%d'

    # Convert to a date object
    if start_day is None and sim is not None:
        start_day = sim['start_day']
    if start_day is None:
        errormsg = 'If not supplying a start day, you must supply a sim object'
        raise ValueError(errormsg)
    start_day = sc.date(start_day)

    @ticker.FuncFormatter
    def mpl_formatter(x, pos):
        return (start_day + dt.timedelta(days=int(x))).strftime(dateformat)

    # Set initial tick marks (intervals and limits)
    if ax is not None:

        # Handle limits
        xmin, xmax = ax.get_xlim()
        if start:
            xmin = sc.day(start, start_day=start_day)
        if end:
            xmax = sc.day(end, start_day=start_day)
        ax.set_xlim((xmin, xmax))

        # Set the x-axis intervals
        if interval:
            ax.set_xticks(np.arange(xmin, xmax + 1, interval))

        # Set the formatter
        ax.xaxis.set_major_formatter(mpl_formatter)

    return mpl_formatter