Update app.py
Browse files
app.py
CHANGED
|
@@ -607,7 +607,7 @@ def load_default_files(force=False):
|
|
| 607 |
# 6) FAKTOR WILAYAH (TOTAL) — hanya untuk faktor/target/pop/coverage
|
| 608 |
# ============================================================
|
| 609 |
|
| 610 |
-
def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_prov: pd.DataFrame, kew_value: str):
|
| 611 |
if df_filtered is None or df_filtered.empty:
|
| 612 |
return pd.DataFrame()
|
| 613 |
|
|
@@ -622,6 +622,7 @@ def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_p
|
|
| 622 |
target_field = "Target68_Total"
|
| 623 |
pop_field = "Pop_Total"
|
| 624 |
name_field = "Kab_Kota_Label"
|
|
|
|
| 625 |
elif "PROV" in kew_norm:
|
| 626 |
key_col = "prov_key"
|
| 627 |
label_col = "PROV_DISP"
|
|
@@ -630,6 +631,7 @@ def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_p
|
|
| 630 |
target_field = "Target68_Total_Prov"
|
| 631 |
pop_field = "Pop_Total_Prov"
|
| 632 |
name_field = "Provinsi_Label"
|
|
|
|
| 633 |
else:
|
| 634 |
key_col = "kab_key"
|
| 635 |
label_col = "KAB_DISP"
|
|
@@ -638,11 +640,13 @@ def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_p
|
|
| 638 |
target_field = "Target68_Total"
|
| 639 |
pop_field = "Pop_Total"
|
| 640 |
name_field = "Kab_Kota_Label"
|
|
|
|
| 641 |
|
| 642 |
base = df.groupby([key_col, label_col], dropna=False).agg(
|
| 643 |
n_total=("Indeks_Dasar_0_100", "size"),
|
| 644 |
).reset_index().rename(columns={key_col: "group_key", label_col: label_name})
|
| 645 |
|
|
|
|
| 646 |
target_vals, pop_vals, label_fix = [], [], []
|
| 647 |
for _, r in base.iterrows():
|
| 648 |
gk = r["group_key"]
|
|
@@ -660,33 +664,59 @@ def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_p
|
|
| 660 |
base["target_total_68"] = pd.to_numeric(pd.Series(target_vals), errors="coerce")
|
| 661 |
base["pop_total"] = pd.to_numeric(pd.Series(pop_vals), errors="coerce")
|
| 662 |
|
|
|
|
| 663 |
m = base["pop_total"].isna() & base["target_total_68"].notna() & (base["target_total_68"] > 0)
|
| 664 |
base.loc[m, "pop_total"] = base.loc[m, "target_total_68"] / float(FALLBACK_TARGET_RATIO)
|
| 665 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 666 |
base["faktor_penyesuaian"] = [
|
| 667 |
faktor_penyesuaian_total(n, t)
|
| 668 |
for n, t in zip(
|
| 669 |
pd.to_numeric(base["n_total"], errors="coerce").fillna(0).astype(float).tolist(),
|
| 670 |
-
pd.to_numeric(base["target_total_68"], errors="coerce").tolist()
|
| 671 |
)
|
| 672 |
]
|
| 673 |
|
|
|
|
| 674 |
base["coverage_total_%"] = [
|
| 675 |
(safe_div(n, p) * 100) if (p is not None and not pd.isna(p) and float(p) > 0) else np.nan
|
| 676 |
for n, p in zip(
|
| 677 |
pd.to_numeric(base["n_total"], errors="coerce").fillna(0).astype(float).tolist(),
|
| 678 |
-
base["pop_total"].tolist()
|
| 679 |
)
|
| 680 |
]
|
| 681 |
|
| 682 |
-
# =====
|
| 683 |
-
# 1) target_total_68 bulat
|
| 684 |
-
# 2) pop_total bulat
|
| 685 |
-
# 3) coverage_total_% 2 desimal
|
| 686 |
base["target_total_68"] = pd.to_numeric(base["target_total_68"], errors="coerce").fillna(0).round(0).astype(int)
|
| 687 |
-
base["pop_total"]
|
| 688 |
-
base["coverage_total_%"]
|
| 689 |
-
# tetap seperti sebelumnya:
|
| 690 |
base["faktor_penyesuaian"] = pd.to_numeric(base["faktor_penyesuaian"], errors="coerce").fillna(1.0).round(3)
|
| 691 |
|
| 692 |
return base
|
|
@@ -1495,7 +1525,7 @@ def run_calc(prov_value, kab_value, kew_value, df_all, df_raw, pop_kab, pop_prov
|
|
| 1495 |
return _empty_outputs("Tidak ada data untuk filter ini.")
|
| 1496 |
|
| 1497 |
# ==== PIPELINE BARU (KUNCI KONSISTENSI) ====
|
| 1498 |
-
faktor_wilayah = build_faktor_wilayah(df, pop_kab, pop_prov, kew_value or "(Semua)")
|
| 1499 |
agg_jenis_full = build_agg_wilayah_jenis(df, faktor_wilayah, pop_khusus, kew_value or "(Semua)")
|
| 1500 |
agg_total = build_agg_wilayah_total_from_jenis(agg_jenis_full, faktor_wilayah, pop_khusus, kew_value or "(Semua)")
|
| 1501 |
summary_jenis = build_summary_per_jenis(agg_jenis_full, agg_total)
|
|
|
|
| 607 |
# 6) FAKTOR WILAYAH (TOTAL) — hanya untuk faktor/target/pop/coverage
|
| 608 |
# ============================================================
|
| 609 |
|
| 610 |
+
def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_prov: pd.DataFrame, pop_khusus: pd.DataFrame, kew_value: str):
|
| 611 |
if df_filtered is None or df_filtered.empty:
|
| 612 |
return pd.DataFrame()
|
| 613 |
|
|
|
|
| 622 |
target_field = "Target68_Total"
|
| 623 |
pop_field = "Pop_Total"
|
| 624 |
name_field = "Kab_Kota_Label"
|
| 625 |
+
khusus_group_key = "kab_key"
|
| 626 |
elif "PROV" in kew_norm:
|
| 627 |
key_col = "prov_key"
|
| 628 |
label_col = "PROV_DISP"
|
|
|
|
| 631 |
target_field = "Target68_Total_Prov"
|
| 632 |
pop_field = "Pop_Total_Prov"
|
| 633 |
name_field = "Provinsi_Label"
|
| 634 |
+
khusus_group_key = "prov_key"
|
| 635 |
else:
|
| 636 |
key_col = "kab_key"
|
| 637 |
label_col = "KAB_DISP"
|
|
|
|
| 640 |
target_field = "Target68_Total"
|
| 641 |
pop_field = "Pop_Total"
|
| 642 |
name_field = "Kab_Kota_Label"
|
| 643 |
+
khusus_group_key = "kab_key"
|
| 644 |
|
| 645 |
base = df.groupby([key_col, label_col], dropna=False).agg(
|
| 646 |
n_total=("Indeks_Dasar_0_100", "size"),
|
| 647 |
).reset_index().rename(columns={key_col: "group_key", label_col: label_name})
|
| 648 |
|
| 649 |
+
# --- ambil target & pop dari POP_KAB / POP_PROV (existing) ---
|
| 650 |
target_vals, pop_vals, label_fix = [], [], []
|
| 651 |
for _, r in base.iterrows():
|
| 652 |
gk = r["group_key"]
|
|
|
|
| 664 |
base["target_total_68"] = pd.to_numeric(pd.Series(target_vals), errors="coerce")
|
| 665 |
base["pop_total"] = pd.to_numeric(pd.Series(pop_vals), errors="coerce")
|
| 666 |
|
| 667 |
+
# fallback pop dari target kalau pop kosong
|
| 668 |
m = base["pop_total"].isna() & base["target_total_68"].notna() & (base["target_total_68"] > 0)
|
| 669 |
base.loc[m, "pop_total"] = base.loc[m, "target_total_68"] / float(FALLBACK_TARGET_RATIO)
|
| 670 |
|
| 671 |
+
# =========================================================
|
| 672 |
+
# ✅ UPDATE LO: Tambahkan komponen KHUSUS dari POP_KHUSUS
|
| 673 |
+
# target_total_68 += target_khusus
|
| 674 |
+
# pop_total += pop_khusus
|
| 675 |
+
# =========================================================
|
| 676 |
+
if (pop_khusus is not None) and (not pop_khusus.empty):
|
| 677 |
+
pk = pop_khusus.copy()
|
| 678 |
+
|
| 679 |
+
# pastikan numeric
|
| 680 |
+
pk["Target68_Total_Jenis"] = pd.to_numeric(pk.get("Target68_Total_Jenis", 0), errors="coerce").fillna(0.0)
|
| 681 |
+
pk["Pop_Total_Jenis"] = pd.to_numeric(pk.get("Pop_Total_Jenis", 0), errors="coerce").fillna(0.0)
|
| 682 |
+
|
| 683 |
+
if khusus_group_key in pk.columns:
|
| 684 |
+
add_df = pk.groupby(khusus_group_key, as_index=False).agg(
|
| 685 |
+
add_target=("Target68_Total_Jenis", "sum"),
|
| 686 |
+
add_pop=("Pop_Total_Jenis", "sum"),
|
| 687 |
+
).rename(columns={khusus_group_key: "group_key"})
|
| 688 |
+
|
| 689 |
+
base = base.merge(add_df, on="group_key", how="left")
|
| 690 |
+
base["add_target"] = pd.to_numeric(base.get("add_target", 0), errors="coerce").fillna(0.0)
|
| 691 |
+
base["add_pop"] = pd.to_numeric(base.get("add_pop", 0), errors="coerce").fillna(0.0)
|
| 692 |
+
|
| 693 |
+
base["target_total_68"] = pd.to_numeric(base.get("target_total_68", 0), errors="coerce").fillna(0.0) + base["add_target"]
|
| 694 |
+
base["pop_total"] = pd.to_numeric(base.get("pop_total", 0), errors="coerce").fillna(0.0) + base["add_pop"]
|
| 695 |
+
|
| 696 |
+
base = base.drop(columns=[c for c in ["add_target", "add_pop"] if c in base.columns])
|
| 697 |
+
|
| 698 |
+
# faktor penyesuaian pakai TOTAL baru
|
| 699 |
base["faktor_penyesuaian"] = [
|
| 700 |
faktor_penyesuaian_total(n, t)
|
| 701 |
for n, t in zip(
|
| 702 |
pd.to_numeric(base["n_total"], errors="coerce").fillna(0).astype(float).tolist(),
|
| 703 |
+
pd.to_numeric(base["target_total_68"], errors="coerce").fillna(0).astype(float).tolist()
|
| 704 |
)
|
| 705 |
]
|
| 706 |
|
| 707 |
+
# coverage pakai TOTAL baru
|
| 708 |
base["coverage_total_%"] = [
|
| 709 |
(safe_div(n, p) * 100) if (p is not None and not pd.isna(p) and float(p) > 0) else np.nan
|
| 710 |
for n, p in zip(
|
| 711 |
pd.to_numeric(base["n_total"], errors="coerce").fillna(0).astype(float).tolist(),
|
| 712 |
+
pd.to_numeric(base["pop_total"], errors="coerce").fillna(0).astype(float).tolist()
|
| 713 |
)
|
| 714 |
]
|
| 715 |
|
| 716 |
+
# ===== display fix (sesuai permintaan lo sebelumnya) =====
|
|
|
|
|
|
|
|
|
|
| 717 |
base["target_total_68"] = pd.to_numeric(base["target_total_68"], errors="coerce").fillna(0).round(0).astype(int)
|
| 718 |
+
base["pop_total"] = pd.to_numeric(base["pop_total"], errors="coerce").fillna(0).round(0).astype(int)
|
| 719 |
+
base["coverage_total_%"]= pd.to_numeric(base["coverage_total_%"], errors="coerce").fillna(0.0).round(2)
|
|
|
|
| 720 |
base["faktor_penyesuaian"] = pd.to_numeric(base["faktor_penyesuaian"], errors="coerce").fillna(1.0).round(3)
|
| 721 |
|
| 722 |
return base
|
|
|
|
| 1525 |
return _empty_outputs("Tidak ada data untuk filter ini.")
|
| 1526 |
|
| 1527 |
# ==== PIPELINE BARU (KUNCI KONSISTENSI) ====
|
| 1528 |
+
faktor_wilayah = build_faktor_wilayah(df, pop_kab, pop_prov, pop_khusus, kew_value or "(Semua)")
|
| 1529 |
agg_jenis_full = build_agg_wilayah_jenis(df, faktor_wilayah, pop_khusus, kew_value or "(Semua)")
|
| 1530 |
agg_total = build_agg_wilayah_total_from_jenis(agg_jenis_full, faktor_wilayah, pop_khusus, kew_value or "(Semua)")
|
| 1531 |
summary_jenis = build_summary_per_jenis(agg_jenis_full, agg_total)
|