Update app.py
Browse files
app.py
CHANGED
|
@@ -1053,153 +1053,153 @@ def build_agg_wilayah_total_from_jenis(agg_jenis: pd.DataFrame, faktor_wilayah_j
|
|
| 1053 |
|
| 1054 |
# ============================================================
|
| 1055 |
# 9) SUMMARY (PER JENIS) + KESELURUHAN
|
| 1056 |
-
# Ringkasan
|
|
|
|
|
|
|
| 1057 |
# ============================================================
|
| 1058 |
|
| 1059 |
-
def build_summary_per_jenis(agg_jenis: pd.DataFrame, agg_total: pd.DataFrame
|
| 1060 |
jenis_list = ["sekolah", "umum", "khusus"]
|
| 1061 |
|
| 1062 |
-
def _row_default(
|
| 1063 |
return {
|
| 1064 |
-
"Jenis":
|
| 1065 |
"Jumlah_Wilayah": 0,
|
| 1066 |
"Total_Perpus": 0,
|
| 1067 |
|
|
|
|
| 1068 |
"Pop_Total_Jenis": 0,
|
| 1069 |
"Target68_Total_Jenis": 0,
|
| 1070 |
"Terkumpul_Jenis": 0,
|
| 1071 |
"Coverage_Target68_Jenis_%": 0.0,
|
| 1072 |
|
| 1073 |
-
|
| 1074 |
-
"Rata2_sub_sdm": 0.0,
|
| 1075 |
-
"Rata2_sub_pelayanan": 0.0,
|
| 1076 |
-
"Rata2_sub_pengelolaan": 0.0,
|
| 1077 |
-
"Rata2_dim_kepatuhan": 0.0,
|
| 1078 |
-
"Rata2_dim_kinerja": 0.0,
|
| 1079 |
-
|
| 1080 |
"Indeks_Dasar_0_100": 0.0,
|
| 1081 |
"Indeks_Final_Disesuaikan_0_100": 0.0,
|
| 1082 |
"Penyesuaian_Poin": 0.0,
|
| 1083 |
}
|
| 1084 |
|
| 1085 |
-
|
| 1086 |
|
| 1087 |
-
# 1) isi indeks & subdimensi dari agg_jenis
|
| 1088 |
if agg_jenis is not None and not agg_jenis.empty:
|
| 1089 |
a = agg_jenis.copy()
|
| 1090 |
a["Jenis"] = a["Jenis"].astype(str).str.lower().str.strip()
|
| 1091 |
|
| 1092 |
-
|
| 1093 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1094 |
if sub.empty:
|
| 1095 |
continue
|
| 1096 |
|
| 1097 |
-
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
rows_by[j].update({
|
| 1101 |
-
"Jumlah_Wilayah": int(sub.shape[0]),
|
| 1102 |
-
"Total_Perpus": int(pd.to_numeric(sub.get("Jumlah", 0), errors="coerce").fillna(0).sum()),
|
| 1103 |
-
|
| 1104 |
-
"Rata2_sub_koleksi": float(pd.to_numeric(sub.get("Rata2_sub_koleksi", 0), errors="coerce").fillna(0).mean()),
|
| 1105 |
-
"Rata2_sub_sdm": float(pd.to_numeric(sub.get("Rata2_sub_sdm", 0), errors="coerce").fillna(0).mean()),
|
| 1106 |
-
"Rata2_sub_pelayanan": float(pd.to_numeric(sub.get("Rata2_sub_pelayanan", 0), errors="coerce").fillna(0).mean()),
|
| 1107 |
-
"Rata2_sub_pengelolaan": float(pd.to_numeric(sub.get("Rata2_sub_pengelolaan", 0), errors="coerce").fillna(0).mean()),
|
| 1108 |
-
"Rata2_dim_kepatuhan": float(pd.to_numeric(sub.get("Rata2_dim_kepatuhan", 0), errors="coerce").fillna(0).mean()),
|
| 1109 |
-
"Rata2_dim_kinerja": float(pd.to_numeric(sub.get("Rata2_dim_kinerja", 0), errors="coerce").fillna(0).mean()),
|
| 1110 |
-
|
| 1111 |
-
"Indeks_Dasar_0_100": dasar,
|
| 1112 |
-
"Indeks_Final_Disesuaikan_0_100": final,
|
| 1113 |
-
"Penyesuaian_Poin": final - dasar,
|
| 1114 |
-
})
|
| 1115 |
-
|
| 1116 |
-
# 2) isi Pop/Target/Terkumpul dari faktor_wilayah_jenis (ini kunci KHUSUS match Excel)
|
| 1117 |
-
if faktor_wilayah_jenis is not None and not faktor_wilayah_jenis.empty:
|
| 1118 |
-
fw = faktor_wilayah_jenis.copy()
|
| 1119 |
-
fw["Jenis"] = fw["Jenis"].astype(str).str.lower().str.strip()
|
| 1120 |
-
|
| 1121 |
-
for j in jenis_list:
|
| 1122 |
-
sub = fw[fw["Jenis"] == j].copy()
|
| 1123 |
-
if sub.empty:
|
| 1124 |
-
continue
|
| 1125 |
-
|
| 1126 |
-
pop = int(pd.to_numeric(sub.get("pop_total_jenis", 0), errors="coerce").fillna(0).sum())
|
| 1127 |
-
tgt = int(pd.to_numeric(sub.get("target_total_68_jenis", 0), errors="coerce").fillna(0).sum())
|
| 1128 |
-
terk = int(pd.to_numeric(sub.get("n_jenis", 0), errors="coerce").fillna(0).sum())
|
| 1129 |
-
cov = (terk / tgt * 100.0) if tgt > 0 else 0.0
|
| 1130 |
-
|
| 1131 |
-
rows_by[j].update({
|
| 1132 |
-
"Pop_Total_Jenis": pop,
|
| 1133 |
-
"Target68_Total_Jenis": tgt,
|
| 1134 |
-
"Terkumpul_Jenis": terk,
|
| 1135 |
-
"Coverage_Target68_Jenis_%": cov,
|
| 1136 |
-
})
|
| 1137 |
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
|
| 1141 |
-
|
| 1142 |
-
|
|
|
|
| 1143 |
|
| 1144 |
-
|
| 1145 |
-
tgt_all = int(rows_by["sekolah"]["Target68_Total_Jenis"] + rows_by["umum"]["Target68_Total_Jenis"] + rows_by["khusus"]["Target68_Total_Jenis"])
|
| 1146 |
-
terk_all = int(rows_by["sekolah"]["Terkumpul_Jenis"] + rows_by["umum"]["Terkumpul_Jenis"] + rows_by["khusus"]["Terkumpul_Jenis"])
|
| 1147 |
-
cov_all = (terk_all / tgt_all * 100.0) if tgt_all > 0 else 0.0
|
| 1148 |
|
| 1149 |
-
|
| 1150 |
-
|
| 1151 |
|
| 1152 |
-
|
| 1153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1154 |
|
| 1155 |
rows.append({
|
| 1156 |
"Jenis": "keseluruhan",
|
| 1157 |
"Jumlah_Wilayah": jumlah_wilayah_all,
|
| 1158 |
-
"Total_Perpus":
|
| 1159 |
|
| 1160 |
"Pop_Total_Jenis": pop_all,
|
| 1161 |
-
"Target68_Total_Jenis":
|
| 1162 |
-
"Terkumpul_Jenis":
|
| 1163 |
-
"Coverage_Target68_Jenis_%":
|
| 1164 |
-
|
| 1165 |
-
"
|
| 1166 |
-
"
|
| 1167 |
-
"
|
| 1168 |
-
"Rata2_sub_pengelolaan": _avg3("Rata2_sub_pengelolaan"),
|
| 1169 |
-
"Rata2_dim_kepatuhan": _avg3("Rata2_dim_kepatuhan"),
|
| 1170 |
-
"Rata2_dim_kinerja": _avg3("Rata2_dim_kinerja"),
|
| 1171 |
-
|
| 1172 |
-
"Indeks_Dasar_0_100": dasar_all,
|
| 1173 |
-
"Indeks_Final_Disesuaikan_0_100": final_all,
|
| 1174 |
-
"Penyesuaian_Poin": final_all - dasar_all,
|
| 1175 |
})
|
| 1176 |
|
| 1177 |
out = pd.DataFrame(rows)
|
| 1178 |
|
| 1179 |
-
#
|
| 1180 |
-
|
| 1181 |
-
for c in
|
| 1182 |
if c in out.columns:
|
| 1183 |
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0).round(0).astype(int)
|
| 1184 |
|
| 1185 |
-
|
| 1186 |
-
|
| 1187 |
-
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(2)
|
| 1188 |
-
|
| 1189 |
-
for c in [
|
| 1190 |
-
"Rata2_sub_koleksi","Rata2_sub_sdm","Rata2_sub_pelayanan","Rata2_sub_pengelolaan",
|
| 1191 |
-
"Rata2_dim_kepatuhan","Rata2_dim_kinerja"
|
| 1192 |
-
]:
|
| 1193 |
-
if c in out.columns:
|
| 1194 |
-
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(3)
|
| 1195 |
-
|
| 1196 |
-
for c in ["Indeks_Dasar_0_100","Indeks_Final_Disesuaikan_0_100","Penyesuaian_Poin"]:
|
| 1197 |
if c in out.columns:
|
| 1198 |
-
|
|
|
|
|
|
|
|
|
|
| 1199 |
|
| 1200 |
return out
|
| 1201 |
|
| 1202 |
|
|
|
|
| 1203 |
# ============================================================
|
| 1204 |
# 10) DETAIL ENTITAS: Final menempel dari agg_total (wilayah)
|
| 1205 |
# ============================================================
|
|
|
|
| 1053 |
|
| 1054 |
# ============================================================
|
| 1055 |
# 9) SUMMARY (PER JENIS) + KESELURUHAN
|
| 1056 |
+
# - Ringkasan selalu 4 baris: sekolah, umum, khusus, keseluruhan
|
| 1057 |
+
# - Pop/Target/Terkumpul/Coverage diisi per jenis (SUM lintas wilayah)
|
| 1058 |
+
# - Keseluruhan: indeks = avg3 (tetap ÷3), Pop/Target/Terkumpul = SUM 3 jenis
|
| 1059 |
# ============================================================
|
| 1060 |
|
| 1061 |
+
def build_summary_per_jenis(agg_jenis: pd.DataFrame, agg_total: pd.DataFrame):
|
| 1062 |
jenis_list = ["sekolah", "umum", "khusus"]
|
| 1063 |
|
| 1064 |
+
def _row_default(jenis):
|
| 1065 |
return {
|
| 1066 |
+
"Jenis": jenis,
|
| 1067 |
"Jumlah_Wilayah": 0,
|
| 1068 |
"Total_Perpus": 0,
|
| 1069 |
|
| 1070 |
+
# === POP/TARGET/TERKUMPUL/COVERAGE (PER JENIS) ===
|
| 1071 |
"Pop_Total_Jenis": 0,
|
| 1072 |
"Target68_Total_Jenis": 0,
|
| 1073 |
"Terkumpul_Jenis": 0,
|
| 1074 |
"Coverage_Target68_Jenis_%": 0.0,
|
| 1075 |
|
| 1076 |
+
# === NILAI INDEKS (PER JENIS) ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1077 |
"Indeks_Dasar_0_100": 0.0,
|
| 1078 |
"Indeks_Final_Disesuaikan_0_100": 0.0,
|
| 1079 |
"Penyesuaian_Poin": 0.0,
|
| 1080 |
}
|
| 1081 |
|
| 1082 |
+
rows_by_jenis = {j: _row_default(j) for j in jenis_list}
|
| 1083 |
|
|
|
|
| 1084 |
if agg_jenis is not None and not agg_jenis.empty:
|
| 1085 |
a = agg_jenis.copy()
|
| 1086 |
a["Jenis"] = a["Jenis"].astype(str).str.lower().str.strip()
|
| 1087 |
|
| 1088 |
+
# pastikan kolom numeric aman
|
| 1089 |
+
for c in [
|
| 1090 |
+
"Jumlah",
|
| 1091 |
+
"Indeks_Dasar_Agregat_0_100",
|
| 1092 |
+
"Indeks_Final_Agregat_0_100",
|
| 1093 |
+
"pop_total_jenis",
|
| 1094 |
+
"target_total_68_jenis",
|
| 1095 |
+
]:
|
| 1096 |
+
if c in a.columns:
|
| 1097 |
+
a[c] = pd.to_numeric(a[c], errors="coerce").fillna(0)
|
| 1098 |
+
|
| 1099 |
+
for jenis in jenis_list:
|
| 1100 |
+
sub = a[a["Jenis"] == jenis].copy()
|
| 1101 |
if sub.empty:
|
| 1102 |
continue
|
| 1103 |
|
| 1104 |
+
# jumlah wilayah = banyak baris wilayah untuk jenis tsb
|
| 1105 |
+
jumlah_wilayah = int(sub.shape[0])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1106 |
|
| 1107 |
+
# terkumpul = total entitas yang masuk (Jumlah per wilayah dijumlahkan)
|
| 1108 |
+
terkumpul = int(pd.to_numeric(sub.get("Jumlah", 0), errors="coerce").fillna(0).sum())
|
| 1109 |
|
| 1110 |
+
# POP & TARGET per jenis: SUM lintas wilayah
|
| 1111 |
+
pop_total = int(pd.to_numeric(sub.get("pop_total_jenis", 0), errors="coerce").fillna(0).sum())
|
| 1112 |
+
target68 = int(pd.to_numeric(sub.get("target_total_68_jenis", 0), errors="coerce").fillna(0).sum())
|
| 1113 |
|
| 1114 |
+
coverage = (terkumpul / target68 * 100.0) if target68 > 0 else 0.0
|
|
|
|
|
|
|
|
|
|
| 1115 |
|
| 1116 |
+
dasar = float(pd.to_numeric(sub.get("Indeks_Dasar_Agregat_0_100", 0), errors="coerce").fillna(0).mean())
|
| 1117 |
+
final = float(pd.to_numeric(sub.get("Indeks_Final_Agregat_0_100", 0), errors="coerce").fillna(0).mean())
|
| 1118 |
|
| 1119 |
+
rows_by_jenis[jenis] = {
|
| 1120 |
+
"Jenis": jenis,
|
| 1121 |
+
"Jumlah_Wilayah": jumlah_wilayah,
|
| 1122 |
+
"Total_Perpus": terkumpul,
|
| 1123 |
+
|
| 1124 |
+
"Pop_Total_Jenis": pop_total,
|
| 1125 |
+
"Target68_Total_Jenis": target68,
|
| 1126 |
+
"Terkumpul_Jenis": terkumpul,
|
| 1127 |
+
"Coverage_Target68_Jenis_%": float(coverage),
|
| 1128 |
+
|
| 1129 |
+
"Indeks_Dasar_0_100": float(dasar),
|
| 1130 |
+
"Indeks_Final_Disesuaikan_0_100": float(final),
|
| 1131 |
+
"Penyesuaian_Poin": float(final - dasar),
|
| 1132 |
+
}
|
| 1133 |
+
|
| 1134 |
+
# ===== susun 3 baris jenis =====
|
| 1135 |
+
rows = [rows_by_jenis[j] for j in jenis_list]
|
| 1136 |
+
|
| 1137 |
+
# ===== baris keseluruhan (FIX) =====
|
| 1138 |
+
# indeks keseluruhan = avg3 (tetap ÷3, missing=0)
|
| 1139 |
+
dasar_all = (rows_by_jenis["sekolah"]["Indeks_Dasar_0_100"]
|
| 1140 |
+
+ rows_by_jenis["umum"]["Indeks_Dasar_0_100"]
|
| 1141 |
+
+ rows_by_jenis["khusus"]["Indeks_Dasar_0_100"]) / 3.0
|
| 1142 |
+
|
| 1143 |
+
final_all = (rows_by_jenis["sekolah"]["Indeks_Final_Disesuaikan_0_100"]
|
| 1144 |
+
+ rows_by_jenis["umum"]["Indeks_Final_Disesuaikan_0_100"]
|
| 1145 |
+
+ rows_by_jenis["khusus"]["Indeks_Final_Disesuaikan_0_100"]) / 3.0
|
| 1146 |
+
|
| 1147 |
+
# Pop/Target/Terkumpul keseluruhan = SUM 3 jenis
|
| 1148 |
+
pop_all = int(rows_by_jenis["sekolah"]["Pop_Total_Jenis"]
|
| 1149 |
+
+ rows_by_jenis["umum"]["Pop_Total_Jenis"]
|
| 1150 |
+
+ rows_by_jenis["khusus"]["Pop_Total_Jenis"])
|
| 1151 |
+
|
| 1152 |
+
target_all = int(rows_by_jenis["sekolah"]["Target68_Total_Jenis"]
|
| 1153 |
+
+ rows_by_jenis["umum"]["Target68_Total_Jenis"]
|
| 1154 |
+
+ rows_by_jenis["khusus"]["Target68_Total_Jenis"])
|
| 1155 |
+
|
| 1156 |
+
terkumpul_all = int(rows_by_jenis["sekolah"]["Terkumpul_Jenis"]
|
| 1157 |
+
+ rows_by_jenis["umum"]["Terkumpul_Jenis"]
|
| 1158 |
+
+ rows_by_jenis["khusus"]["Terkumpul_Jenis"])
|
| 1159 |
+
|
| 1160 |
+
coverage_all = (terkumpul_all / target_all * 100.0) if target_all > 0 else 0.0
|
| 1161 |
+
|
| 1162 |
+
jumlah_wilayah_all = int(agg_total.shape[0]) if (agg_total is not None and not agg_total.empty) else int(
|
| 1163 |
+
max(rows_by_jenis["sekolah"]["Jumlah_Wilayah"],
|
| 1164 |
+
rows_by_jenis["umum"]["Jumlah_Wilayah"],
|
| 1165 |
+
rows_by_jenis["khusus"]["Jumlah_Wilayah"])
|
| 1166 |
+
)
|
| 1167 |
|
| 1168 |
rows.append({
|
| 1169 |
"Jenis": "keseluruhan",
|
| 1170 |
"Jumlah_Wilayah": jumlah_wilayah_all,
|
| 1171 |
+
"Total_Perpus": terkumpul_all,
|
| 1172 |
|
| 1173 |
"Pop_Total_Jenis": pop_all,
|
| 1174 |
+
"Target68_Total_Jenis": target_all,
|
| 1175 |
+
"Terkumpul_Jenis": terkumpul_all,
|
| 1176 |
+
"Coverage_Target68_Jenis_%": float(coverage_all),
|
| 1177 |
+
|
| 1178 |
+
"Indeks_Dasar_0_100": float(dasar_all),
|
| 1179 |
+
"Indeks_Final_Disesuaikan_0_100": float(final_all),
|
| 1180 |
+
"Penyesuaian_Poin": float(final_all - dasar_all),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1181 |
})
|
| 1182 |
|
| 1183 |
out = pd.DataFrame(rows)
|
| 1184 |
|
| 1185 |
+
# ===== formatting tampilan =====
|
| 1186 |
+
# integer columns
|
| 1187 |
+
for c in ["Jumlah_Wilayah", "Total_Perpus", "Pop_Total_Jenis", "Target68_Total_Jenis", "Terkumpul_Jenis"]:
|
| 1188 |
if c in out.columns:
|
| 1189 |
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0).round(0).astype(int)
|
| 1190 |
|
| 1191 |
+
# float columns
|
| 1192 |
+
for c in ["Coverage_Target68_Jenis_%", "Indeks_Dasar_0_100", "Indeks_Final_Disesuaikan_0_100", "Penyesuaian_Poin"]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1193 |
if c in out.columns:
|
| 1194 |
+
if c == "Coverage_Target68_Jenis_%":
|
| 1195 |
+
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(2)
|
| 1196 |
+
else:
|
| 1197 |
+
out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(2)
|
| 1198 |
|
| 1199 |
return out
|
| 1200 |
|
| 1201 |
|
| 1202 |
+
|
| 1203 |
# ============================================================
|
| 1204 |
# 10) DETAIL ENTITAS: Final menempel dari agg_total (wilayah)
|
| 1205 |
# ============================================================
|