def test_initialization_options(self): br = mundi.region("BR") it = mundi.region("IT") # Initialize with no region m = SIR() assert m.population == 1_000_000 assert m.region is None assert m.age_distribution is None assert m.age_pyramid is None # Use a region m = SIR(region="BR") assert m.population == br.population assert_series_equal(m.age_distribution, br.age_distribution, check_names=False) assert_frame_equal(m.age_pyramid, br.age_pyramid) # Mix parameters a region tol = 1e-6 m = SIR(region="BR", population=1000) assert m.population == 1000 assert abs(m.age_distribution.sum() - 1000) < tol assert abs(m.age_pyramid.sum().sum() - 1000) < tol ratio = br.age_distribution / m.age_distribution assert ((ratio - br.population / 1000).dropna().abs() < tol).all() # Mixed values: brazilian population with the age_distribution proportions # from Italy m = SIR(region="BR", age_distribution="IT") assert m.population == br.population assert m.age_distribution.sum() == approx(br.population) assert list(m.age_distribution / m.population) == approx( it.age_distribution / it.population )
def from_children( cls, region: Union[Region, str], model_cls: Type[Model], options=MappingProxyType({}), **kwargs, ) -> "ModelGroup": """ Create a group from children of the given Region. """ region: Region = mundi.region(region) children = region.children( **extract_keys(("deep", "type", "subtype", "which"), kwargs)) name = kwargs.pop("name", "{region.name}") group = [] if options: options = {mundi.region(k): v for k, v in options.items()} for child in children: opts = options.get(child, {}) if isinstance(name, str): opts["name"] = name.format(region=child, **kwargs, **opts) group.append(model_cls(region=child, **kwargs, **opts)) return ModelGroup(group)
def region_input(default: str, *, advanced=False, text=False, where=st, **kwargs) -> Region: """ Select region or sub-region based on mundi code. """ st = where kwargs["where"] = where default = mundi.code(default) if text or advanced and st.checkbox(_("Advanced selection"), value=False): try: code = st.text_input(_("Select mundi region"), value=default) return mundi.region(code) except LookupError: st.error(_("Region not found!")) return mundi.region(default) region = mundi.region(default) if region.id == "BR": return _br_region_input(**kwargs) elif len(default) == 2: return _from_sub_regions(region, _("Location"), where=where) else: raise NotImplementedError(f"Cannot select {default!r}")
def test_arbitrary_composite_region(self): bsb = region("BR-5300108") sp = region("BR-3550308") reg = CompositeRegion([bsb, sp]) assert reg.population == bsb.population + sp.population assert_series_equal(reg.age_distribution, bsb.age_distribution + sp.age_distribution)
def ibge_city(code): if code.isdigit(): if len(code) == 7: code = code[:-1] elif len(code) != 6: raise ValueError(_("invalid city code: {code}").format(code=code)) return mundi.region(country_code="BR", type="city", short_code=code) return mundi.region(code)
def _from_template(code, template, where=st) -> Region: """ Select a Brazilian region from country up to municipality. """ code = mundi.region(code) for label, type_, subtype in template: kwargs = {"type": type_} if subtype: kwargs["subtype"] = subtype new_code = _from_sub_regions(code, label, where=where, **kwargs) if new_code == code: return mundi.region(code) code = new_code return mundi.region(code)
def ask(self): """ Ask for user input and save values as properties in the app. """ self.where.header(("Options")) self.region = self.where.text_input(_("Mundi region code"), value="BR") try: self.region = mundi.region(self.region) except LookupError: self.where.error("Invalid mundi region code.") return options = { "model": _("A Pydemic Model"), "region": _("A Mundi Region"), "components": _("Input components"), } message = _("What do you want to explore?") option = self.where.radio(message, list(options), format_func=options.get) self.option = option self.object = self.handle_explore_option(option)
def get_confirmed_daily_cases_for_region(region, disease=covid19) -> int: """ Return the number of newly confirmed cases per day. """ region = mundi.region(region) df = region.pydemic.epidemic_curve(disease) return safe_int(df["cases"].diff().iloc[-7:].mean())
def test_epidemiological_params_advanced(self, en): br = mundi.region("BR") st = Driver([ out.header("Epidemiology"), ask.selectbox["custom"](...), out.subheader(...), ask.slider[2.0](...), # R0 ask.slider[3.0](...), # incubation period ask.slider[3.0](...), # infectious period ask.slider[50](...), # symptomatic cases out.subheader(...), ask.slider[5](...), # prob_severe ask.slider[25](...), # prob_critical ask.slider[10](...), # hospitalization_period ask.slider[7](...), # icu_period ]) assert input.epidemiological_params(br, where=st) == { "R0": 2.0, "severe_period": 10, "critical_period": 7, "incubation_period": 3.0, "infectious_period": 3.0, "prob_critical": 0.0125, "prob_severe": 0.05, "prob_symptoms": 0.5, } assert st.is_empty()
def __init(self, region=None, population=None, age_distribution=None, age_pyramid=None): if age_distribution is not None and age_pyramid is not None: msg = "cannot set age_pyramid and age_distribution simultaneously" raise ValueError(msg) # Set region if region is not None: self.region = mundi.region(region) population = population or self.region.population elif not hasattr(self, "region"): self.region = None # Set age_pyramid if age_pyramid is not None: self.age_pyramid = fallback_to_region(age_pyramid, "age_pyramid") elif hasattr(self, "age_pyramid"): pass elif self.region is not None: self.age_pyramid = fallback_to_region(self.region, "age_pyramid") else: self.age_pyramid = None # Set age_distribution if age_distribution is not None: value = fallback_to_region(age_distribution, "age_distribution") self.age_distribution = value elif hasattr(self, "age_distribution"): pass elif self.age_pyramid is not None: self.age_distribution = self.age_pyramid.sum(1) self.age_distribution.name = "age_distribution" self.age_distribution.index.names = ["age"] elif self.region is not None: self.age_distribution = fallback_to_region(self.region, "age_distribution") else: self.age_distribution = None # Set population and fix age_distribution and age_pyramid, if necessary if hasattr(self, "population"): pass elif population is not None: population = fallback_to_region(population, "population") self.population = population if self.age_distribution is not None: ratio = population / self.age_distribution.sum() if ratio != 1: self.age_distribution *= ratio if self.age_pyramid is not None: ratio = population / self.age_pyramid.sum().sum() if ratio != 1: self.age_pyramid *= ratio elif self.age_distribution is not None: self.population = self.age_distribution.sum() elif self.region is not None: self.population = self.region.population else: self.population = 1_000_000
def get_regions(self, **query): """ Get all children in region that have the same values of the parameters passed as keyword arguments. """ return [mundi.region(id_) for id_ in mundi.regions(**query).index]
def show_results( parent_region, regions, columns, targets, days, scenario, disease=covid19, transpose=False, ): """ Show results from user input. """ parent_region = mundi.region(parent_region) parent_region.ui.cases_and_deaths(disease=disease, grid=True, logy=True) if days and targets and columns: info = scenario["info"] info_cols = tuple(info) df = get_dataframe( regions, tuple(days), tuple(targets), tuple(columns), info_cols=info_cols ) get = {**COL_NAMES, **info}.get df.columns = pd.MultiIndex.from_tuples( [tuple(_(get(x, x) for x in t)) for t in df.columns.to_list()] ) if transpose: df = df.T st.subheader(_("Download results")) st.dataframe_download(df, name="report-brazil.{ext}")
def show(self): """ Show results from user input. """ parent_region = self.user_inputs["parent_region"] regions = self.user_inputs["regions"] columns = self.user_inputs["columns"] targets = self.user_inputs["targets"] days = self.user_inputs["days"] scenario = self.user_inputs["scenario"] transpose = self.user_inputs["transpose"] disease = self.user_inputs["disease"] parent_region = mundi.region(parent_region) parent_region.ui.cases_and_deaths(disease=disease, grid=True, logy=True) if days and targets and columns: info = scenario["info"] info_cols = tuple(info) df = self.get_dataframe( regions, tuple(days), tuple(targets), tuple(columns), info_cols=info_cols ) get = {**COL_NAMES, **info}.get df.columns = pd.MultiIndex.from_tuples( [tuple(_(get(x, x) for x in t)) for t in df.columns.to_list()] ) if transpose: df = df.T st.subheader(_("Download results")) st.dataframe_download(df, name="report-brazil.{ext}")
def region_name(code): """Region name from Mundi code.""" if code.startswith("*"): return _("{name} (everything)").format(name=region_name(code[1:])) reg = mundi.region(code) return _(reg["name"])
def _from_sub_regions(code, label, fastrack=False, where=st, **kwargs) -> Region: """ Select a region from a list that starts with the parent region and its children. """ region = mundi.region(code) regions = sub_regions(region.id, **kwargs) if len(regions) == 1 and fastrack: return regions[0] regions = ("*" + region.id, *regions) return mundi.region( where.selectbox(str(label), regions, format_func=region_name).lstrip("*"))
def sari_br_state_content(region: str) -> bytes: region = mundi.region(region) ref = region.short_code.lower() url = f"https://s3-sa-east-1.amazonaws.com/ckan.saude.gov.br/dados-{ref}.csv" log.info(f"[sari-br] Downloading data for {region}") response = requests.get(url) log.info(f"[sari-br] Download complete!") return response.content
def test_select_region(self, en): st = Driver([ out.header("Location"), ask.selectbox["BR-1"](...), ask.selectbox["*BR-1"](...), ]) assert input.region_input("BR", where=st) == mundi.region("BR-1") assert st.is_empty()
def _test_regional_model_to_json(self): m = SIR(region="BR") br = mundi.region("BR") assert m.info.to_dict() == { "demography.population": br.population, "demography.age_distribution": br.age_distribution, "demography.age_pyramid": br.age_pyramid, } assert m.info.to_dict(flat=True) == flatten_dict(m.info.to_dict())
def from_region(cls, transform, region, params=None, disease=None, **kwargs): """ Initialize data extracting curve from region. """ region = mundi.region(region) disease = diseases.disease(disease) data = disease.epidemic_curve(region) kwargs.setdefault("population", region.population) return cls(transform(data), params, **kwargs)
def from_region(cls, region, *, model_cls=None, init_cases=True, **kwargs): """ Initialize report from cases reported in region. """ region = mundi.region(region) init_kwargs = extract_keys(INIT_KEYS, kwargs) model = (model_cls or cls.model_cls)(region=region, **kwargs) if init_cases: model.set_cases() return cls(model, **init_kwargs)
def _fatality_ratio(self, col, age_distribution=None, source=None, region=None): table = self.mortality_table(source=source) if age_distribution is None and region: ages = mundi.region(region).age_distribution elif age_distribution is None: ages = world_age_distribution() else: ages = age_distribution return age_adjusted_average(ages, table[col])
def get_model(region): region = mundi.region(region) data = region.pydemic.epidemic_curve() empirical_CFR = (data["deaths"] / data["cases"]).mean() notification_rate = min(0.5, covid19.CFR(region=region) / empirical_CFR) m = SEAIR(region=region, R0=R0[region.id]) real_data = data.copy() real_data["cases"] /= notification_rate m.set_cases(real_data, save_observed=True) m.run(60) return m.clinical.overflow_model()
def test_info(self): approx = lambda x: _approx(x, rel=0.005) disease = get_disease("covid-19") m = SIR(disease="covid-19", region="BR") m.set_ic(cases=1e6) m.run(60) # Disease infectious_period = disease.infectious_period(region="BR") assert m.info["disease.CFR"] == approx(disease.CFR(region="BR")) assert m.info["disease.IFR"] == approx(disease.IFR(region="BR")) assert m.info["disease.infectious_period"] == approx(infectious_period) assert set(m.info["disease"]) == { "R0", "case_fatality_ratio", "critical_delay", "critical_period", "death_delay", "hospital_fatality_ratio", "hospitalization_overflow_bias", "hospitalization_period", "hospitalization_table", "icu_fatality_ratio", "icu_period", "incubation_period", "infection_fatality_ratio", "infectious_period", "mortality_table", "prob_aggravate_to_icu", "prob_critical", "prob_severe", "prob_symptoms", "rho", "serial_period", "severe_delay", "severe_period", "symptom_delay", } # Region br = mundi.region("BR") keys = { "population", "age_distribution", "age_pyramid", "hospital_capacity", "icu_capacity", } assert m.info["region.population"] == br.population assert all(m.info["region.age_distribution"] == br.age_distribution) assert all(m.info["region.age_pyramid"] == br.age_pyramid) assert set(m.info["region"]) == keys
def test_load_country(self): br = mundi.region("BR") assert isinstance(br, Region) assert br.id == "BR" assert br["name"] == "Brazil" assert br["type"] == "country" assert br["short_code"] == "BR" assert br["numeric_code"] == "076" assert br["long_code"] == "BRA" assert br["country_code"] is None assert br["parent_id"] == "XSA" ar = mundi.region("ar") assert isinstance(ar, Region) assert ar["name"] == "Argentina" assert ar["type"] == "country" assert ar["short_code"] == "AR" assert ar["numeric_code"] == "032" assert ar["long_code"] == "ARG" assert ar["country_code"] is None assert br["parent_id"] == "XSA"
def sari_br_state_dataframe(region: Region) -> pd.DataFrame: """ Return the full table of SARI hospital vigilance for the given region. """ region = mundi.region(region) content = sari_br_state_content(region.id) lines = content.splitlines() content = lines[0] + b"\n" + b"\n".join(lines[-1000:]) fd = io.BytesIO(content) with st.spinner(f"Converting to CSV ({region.name})"): chunks = [] date_columns = [ "dataNotificacao", "dataInicioSintomas", "dataNascimento", "dataEncerramento", "dataTeste", ] for df in pd.read_csv( fd, index_col=0, sep=";", parse_dates=date_columns, dtype=DTYPES, converters=CONVERTERS, engine="c", chunksize=1000, encoding="latin1", ): df: pd.DataFrame = (df.astype(DTYPES).rename( columns=RENAME).astype({ "status": Status.categories, "gender": Gender.categories, "evolution": Evolution.categories, "test_status": Test.categories, })) def localtime(x): if pd.isna(x): return x return x.time() df["notification_time"] = df["notification_date"].apply(localtime) df["notification_date"] = df["notification_date"].apply( lambda x: x if pd.isna(x) else x.date()) df.index.name = "id" chunks.append(df) df = pd.concat(chunks) return df
def show_results(parent_region, regions, columns, targets, days, disease=covid19): """ Show results from user input. """ parent_region = mundi.region(parent_region) ax = parent_region.plot.cases_and_deaths(disease=disease, logy=True, grid=True) st.pyplot(ax.get_figure()) if days and targets and columns: df = get_dataframe(regions, tuple(days), tuple(targets), tuple(columns), 61) st.subheader(_("Download results")) st.dataframe_download(df, name="report-brazil.{ext}")
def healthcare_params(region, title=__("Hospital capacity"), occupancy=0.75, where=st): """ Return a dictionary with hospital and icu capacities from user input. Returns: icu_capacity (float): surge system capacity of ICUs icu_full_capacity (float): total system capacity of ICUs hospital_capacity (float): surge system capacity of regular beds hospital_full_capacity (float): total system capacity of regular beds """ region = mundi.region(region) where.header(str(title)) def get(title, capacity, rate, key=None): where.subheader(title) total = where.number_input(_("Total capacity"), min_value=0, value=int(capacity), key=key + "_total") occupied = where.number_input(_("Occupied"), min_value=0, value=int(capacity * rate), key=key + "_used") if occupied > total: where.warning(_("Using more beds than total capacity")) msg = markdown( OCCUPANCY_MSG.format(n=fmt(total - occupied), rate=pc(occupied / total), globalrate=pc(rate))) html(f'<span style="font-size: smaller;">{msg}</span>', where=where) return max(total - occupied, 0) h_cap = safe_int(region.hospital_capacity) icu_cap = safe_int(region.icu_capacity) return { "icu_full_capacity": icu_cap, "hospital_full_capacity": h_cap, "icu_capacity": get(_("ICU beds"), icu_cap, occupancy, key="icu"), "hospital_capacity": get(_("Clinical beds"), h_cap, occupancy, key="hospital"), }
def test_clinical_model_uses_region_IFR(self, region="BR"): m = SEIR(region=region, disease=covid19) br = mundi.region("BR") m1 = m.clinical.crude_model() m2 = m.clinical.delay_model() m3 = m.clinical.overflow_model() IFR = covid19.IFR(region=region) CFR = covid19.CFR(region=region) for m in [m1, m2, m3]: assert m.region == br assert m.IFR == m.infection_fatality_ratio == IFR assert m.CFR == m.case_fatality_ratio == CFR
def test_simulation_params(self, en): br = mundi.region("BR") st = Driver([ out.header("Simulation options"), ask.slider[10](...), ask.date_input[today(10)](...), out.subheader("Cases"), ask.number_input[10](...), ask.slider[10](...), ]) assert input.simulation_params(br, where=st) == { "period": 70, "date": today(10), "daily_cases": 100, } assert st.is_empty()
def show(self): parent_region = self.__datahandler.user_inputs["parent_region"] columns = self.__datahandler.user_inputs["columns"] targets = self.__datahandler.user_inputs["targets"] days = self.__datahandler.user_inputs["days"] disease = self.__datahandler.user_inputs["disease"] parent_region = mundi.region(parent_region) axes = parent_region.plot.cases_and_deaths(disease=disease, logy=True, grid=True) st.pyplot(axes.get_figure()) if days and targets and columns: df = self.__datahandler.get_dataframe(tuple(days), tuple(targets), tuple(columns)) st.subheader(_("Download results")) st.dataframe_download(df, name="report-brazil.{ext}")