])\ .title("\nDKI Jakarta: Daily Cases")\ .xlabel("\ndate")\ .ylabel("cases\n")\ .annotate("\nBayesian training process on empirical data, with anomalies identified")\ .show() logger.info("district-level projections") district_cases = dkij.groupby(["district", "date_positiveresult"])["id"].count().sort_index() districts = dkij.district.unique() migration = np.zeros((len(districts), len(districts))) estimates = [] max_len = 1 + max(map(len, districts)) with tqdm(districts) as progress: for district in districts: progress.set_description(f"{district :<{max_len}}") (dates, RR_pred, RR_CI_upper, RR_CI_lower, *_) = analytical_MPVS(district_cases.loc[district], CI = CI, smoothing = smoothing, totals=False) estimates.append((district, RR_pred[-1], RR_CI_lower[-1], RR_CI_upper[-1], linear_projection(dates, RR_pred, window))) estimates = pd.DataFrame(estimates) estimates.columns = ["district", "Rt", "Rt_CI_lower", "Rt_CI_upper", "Rt_proj"] estimates.set_index("district", inplace=True) estimates.to_csv(data/"Jakarta_Rt_projections.csv") print(estimates) logger.info("generating choropleths") gdf = gdf.merge(estimates, left_on = "NAME_2", right_on = "district") plt.choropleth(gdf, lambda row: row["NAME_2"]+"\n")\ .adjust(left = 0.06)\ .title("\nDKI Jakarta: $R_t$ by District")\ .show()
def generate_report(state_code: str): print(f"Received request for {state_code}.") state = state_code_lookup[state_code] normalized_state = state.replace(" and ", " And ").replace(" & ", " And ") blobs = { f"pipeline/est/{state_code}_state_Rt.csv": f"/tmp/state_Rt_{state_code}.csv", f"pipeline/est/{state_code}_district_Rt.csv": f"/tmp/district_Rt_{state_code}.csv", f"pipeline/commons/maps/{state_code}.json": f"/tmp/state_{state_code}.geojson" } if normalized_state not in dissolved_states else { f"pipeline/est/{state_code}_state_Rt.csv": f"/tmp/state_Rt_{state_code}.csv", } for (blob_name, filename) in blobs.items(): bucket.blob(blob_name).download_to_filename(filename) print(f"Downloaded estimates for {state_code}.") state_Rt = pd.read_csv(f"/tmp/state_Rt_{state_code}.csv", parse_dates=["dates"], index_col=0) plt.close("all") dates = [pd.Timestamp(date).to_pydatetime() for date in state_Rt.dates] plt.Rt(dates, state_Rt.Rt_pred, state_Rt.Rt_CI_lower, state_Rt.Rt_CI_upper, CI)\ .axis_labels("date", "$R_t$")\ .title(f"{state}: $R_t$ over time", ha = "center", x = 0.5)\ .adjust(left = 0.11, bottom = 0.16) plt.gcf().set_size_inches(3840 / 300, 1986 / 300) plt.savefig(f"/tmp/{state_code}_Rt_timeseries.png") plt.close() print(f"Generated timeseries plot for {state_code}.") # check output is at least 50 KB timeseries_size_kb = os.stat( f"/tmp/{state_code}_Rt_timeseries.png").st_size / 1000 print(f"Timeseries artifact size: {timeseries_size_kb} kb") assert timeseries_size_kb > 50 bucket.blob( f"pipeline/rpt/{state_code}_Rt_timeseries.png").upload_from_filename( f"/tmp/{state_code}_Rt_timeseries.png", content_type="image/png") if normalized_state not in (island_states + dissolved_states): district_Rt = pd.read_csv(f"/tmp/district_Rt_{state_code}.csv", parse_dates=["dates"], index_col=0) latest_Rt = district_Rt[district_Rt.dates == district_Rt.dates.max( )].set_index("district")["Rt_pred"].to_dict() top10 = [(k, "> 3.0" if v > 3 else f"{v:.2f}") for (k, v) in sorted( latest_Rt.items(), key=lambda t: t[1], reverse=True)[:10]] gdf = gpd.read_file(f"/tmp/state_{state_code}.geojson") gdf["Rt"] = gdf.district.map(latest_Rt) fig, ax = plt.subplots() fig.set_size_inches(3840 / 300, 1986 / 300) plt.choropleth(gdf, title = None, mappable = plt.get_cmap(0.75, 2.5), fig = fig, ax = ax)\ .adjust(left = 0) plt.sca(fig.get_axes()[0]) plt.PlotDevice(fig).title(f"{state}: $R_t$ by district", ha="center", x=0.5) plt.axis('off') plt.savefig(f"/tmp/{state_code}_Rt_choropleth.png", dpi=300) plt.close() print(f"Generated choropleth for {state_code}.") # check output is at least 100 KB choropleth_size_kb = os.stat( f"/tmp/{state_code}_Rt_choropleth.png").st_size / 1000 print(f"Choropleth artifact size: {choropleth_size_kb} kb") assert choropleth_size_kb > 100 bucket.blob(f"pipeline/rpt/{state_code}_Rt_choropleth.png" ).upload_from_filename( f"/tmp/{state_code}_Rt_choropleth.png", content_type="image/png") else: print(f"Skipped choropleth for {state_code}.") if normalized_state not in dissolved_states: fig, ax = plt.subplots(1, 1) ax.axis('tight') ax.axis('off') table = ax.table(cellText=top10, colLabels=["district", "$R_t$"], loc='center', cellLoc="center") table.scale(1, 2) for (row, col), cell in table.get_celld().items(): if (row == 0): cell.set_text_props(fontfamily=plt.theme.label["family"], fontsize=plt.theme.label["size"], fontweight="semibold") else: cell.set_text_props(fontfamily=plt.theme.label["family"], fontsize=plt.theme.label["size"], fontweight="light") plt.PlotDevice().title(f"{state}: top districts by $R_t$", ha="center", x=0.5) plt.savefig(f"/tmp/{state_code}_Rt_top10.png", dpi=600) plt.close() print(f"Generated top 10 district listing for {state_code}.") # check output is at least 50 KB top10_size_kb = os.stat( f"/tmp/{state_code}_Rt_top10.png").st_size / 1000 print(f"Top 10 listing artifact size: {top10_size_kb} kb") assert top10_size_kb > 50 bucket.blob( f"pipeline/rpt/{state_code}_Rt_top10.png").upload_from_filename( f"/tmp/{state_code}_Rt_top10.png", content_type="image/png") else: print(f"Skipped top 10 district listing for {state_code}.") # sleep for 15 seconds to ensure the images finish saving time.sleep(15) print(f"Uploaded artifacts for {state_code}.") return "OK!"
)].set_index("district")["Rt_pred"].to_dict() plt.Rt(list(state_Rt.dates), state_Rt.Rt_pred, state_Rt.Rt_CI_lower, state_Rt.Rt_CI_upper, CI)\ .axis_labels("date", "$R_t$")\ .title("Maharashtra: $R_t$ over time", ha = "center", x = 0.5)\ .adjust(left = 0.11, bottom = 0.16) plt.gcf().set_size_inches(3840 / 300, 1986 / 300) plt.savefig("./MH_Rt_timeseries.png") plt.clf() gdf = gpd.read_file("data/maharashtra.json", dpi=600) gdf["Rt"] = gdf.district.map(latest_Rt) fig, ax = plt.subplots() fig.set_size_inches(3840 / 300, 1986 / 300) plt.choropleth(gdf, title = None, mappable = plt.get_cmap(0.75, 2.5), fig = fig, ax = ax)\ .adjust(left = 0) plt.sca(fig.get_axes()[0]) plt.PlotDevice(fig).title(f"{state}: $R_t$ by district", ha="center", x=0.5) plt.axis('off') plt.savefig(f"./{state_code}_Rt_choropleth.png", dpi=300) plt.clf() top10 = [ (k, "> 3.0" if v > 3 else f"{v:.2f}", v) for (k, v) in sorted(latest_Rt.items(), key=lambda t: t[1], reverse=True)[:10] ] fig, ax = plt.subplots(1, 1) ax.axis('tight') ax.axis('off')
smoothing=smoothing, totals=False) estimates.append( (regency, Rt_pred[-1], Rt_CI_lower[-1], Rt_CI_upper[-1], linear_projection(dates, Rt_pred, 7))) estimates = pd.DataFrame(estimates) estimates.columns = ["regency", "Rt", "Rt_CI_lower", "Rt_CI_upper", "Rt_proj"] estimates.set_index("regency", inplace=True) estimates.to_csv("data/SULSEL_Rt_projections.csv") print(estimates) gdf = gpd.read_file("data/gadm36_IDN_shp/gadm36_IDN_2.shp")\ .query("NAME_1 == 'Sulawesi Selatan'")\ .merge(estimates, left_on = "NAME_2", right_on = "regency") choro = plt.choropleth(gdf, mappable=plt.get_cmap(0.4, 1.4, "viridis")) for ax in choro.figure.axes[:-1]: plt.sca(ax) plt.xlim(left=119, right=122) plt.ylim(bottom=-7.56, top=-1.86) plt.show() logger.info("adaptive control") (dates, Rt_pred, Rt_CI_upper, Rt_CI_lower, T_pred, T_CI_upper, T_CI_lower, total_cases, new_cases_ts, anomalies, anomaly_dates)\ = analytical_MPVS(new_cases, CI = CI, smoothing = smoothing, totals = False) Rt = pd.DataFrame(data={"Rt": Rt_pred[1:]}, index=dates) Rt_current = Rt_pred[-1] Rt_m = np.mean(Rt[(Rt.index >= "April 21, 2020") & (Rt.index <= "May 22, 2020")])[0]
logger.info("generating choropleths") sm = mpl.cm.ScalarMappable(norm=mpl.colors.Normalize(vmin=0.9, vmax=1.4), cmap="viridis") gdf = gdf.merge(estimates, left_on="NAME_3", right_on="subdistrict") def labeller(): count = 0 def label(row): nonlocal count if row["Rt"] >= 1.3 or row["Rt_proj"] >= 1.3: letter = chr(67 - count) count += 1 print(letter, row["NAME_3"].title(), row["Rt"], row["Rt_proj"]) return f"({letter})\n" return "" return label plt.choropleth(gdf, label_fn = lambda _: "", mappable = sm)\ .adjust(left = 0.06)\ .show() # # crop to right # plt.choropleth(gdf, label_fn = None, Rt_col= "Rt_proj", Rt_proj_col= "Rt", titles = ["Projected $R_t$ (1 Week)", "Current $R_t$"], mappable = sm)\ # .adjust(left = 0.06)\ # .show()