diff --git a/app/Http/Controllers/KecamatanController.php b/app/Http/Controllers/KecamatanController.php index 9f11a8f..78ab73b 100644 --- a/app/Http/Controllers/KecamatanController.php +++ b/app/Http/Controllers/KecamatanController.php @@ -4,6 +4,8 @@ use App\Models\Kecamatan; use Illuminate\Http\Request; +use App\Services\KMeansService; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Crypt; class KecamatanController extends Controller @@ -30,14 +32,28 @@ public function create() */ public function store(Request $request) { + $validateData = $request->validate([ + 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', + ]); + try{ - $validateData = $request->validate([ - 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', - ]); - + DB::beginTransaction(); Kecamatan::create($validateData); + + $serviceKMeans = new KMeansService(); + $serviceKMeans->SSEElbowCuranmor(); + $serviceKMeans->SSEElbowCuras(); + + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); + file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); + + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); + file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); + + DB::commit(); return redirect('/dashboard/kecamatan')->with('succes', 'Berhasil Menambahkan Data Kecamatan Baru'); }catch (\Exception $e){ + DB::rollBack(); return redirect('/dashboard/kecamatan')->with('error', 'Gagal Menambahkan Data Kecamatan Baru'); } @@ -71,14 +87,28 @@ public function edit(Kecamatan $kecamatan) */ public function update(Request $request, Kecamatan $kecamatan) { + $validateData = $request->validate([ + 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', + ]); + try{ - $validateData = $request->validate([ - 'nama_kecamatan' =>'required|max:255|unique:kecamatans,nama_kecamatan', - ]); - + DB::beginTransaction(); Kecamatan::where('id', $kecamatan->id)->update($validateData); + + $serviceKMeans = new KMeansService(); + $serviceKMeans->SSEElbowCuranmor(); + $serviceKMeans->SSEElbowCuras(); + + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); + file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); + + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); + file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); + + DB::commit(); return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Ubah'); }catch (\Exception $e){ + DB::rollBack(); return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan Gagal Di Ubah'); } @@ -91,10 +121,24 @@ public function update(Request $request, Kecamatan $kecamatan) public function destroy(Kecamatan $kecamatan) { try{ + DB::beginTransaction(); Kecamatan::destroy($kecamatan->id); + + $serviceKMeans = new KMeansService(); + $serviceKMeans->SSEElbowCuranmor(); + $serviceKMeans->SSEElbowCuras(); + + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); + file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); + + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); + file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); + + DB::commit(); return redirect('/dashboard/kecamatan')->with('succes', 'Data Kecamatan Berhasil Di Hapus'); }catch (\Exception $e){ + DB::rollBack(); return redirect('/dashboard/kecamatan')->with('error', 'Data Kecamatan '. $kecamatan->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Kecamatan '. $kecamatan->nama_kecamatan.' Terlebih Dahulu'); } diff --git a/app/Http/Controllers/KlasterController.php b/app/Http/Controllers/KlasterController.php index ee23c86..d15369b 100644 --- a/app/Http/Controllers/KlasterController.php +++ b/app/Http/Controllers/KlasterController.php @@ -5,6 +5,7 @@ use App\Models\Klaster; use Illuminate\Http\Request; use App\Services\KMeansService; +use Illuminate\Support\Facades\DB; class KlasterController extends Controller { @@ -29,30 +30,35 @@ public function create() */ public function store(Request $request) { + $validateData = $request->validate([ + 'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster', + 'warna' =>'required|max:255', + ]); + DB::beginTransaction(); + try{ - $validateData = $request->validate([ - 'nama_klaster' =>'required|max:255|unique:klasters,nama_klaster', - 'warna' =>'required|max:255', - ]); + + Klaster::create($validateData); $serviceKMeans = new KMeansService(); $serviceKMeans->SSEElbowCuranmor(); $serviceKMeans->SSEElbowCuras(); - $serviceKMeansCuras = new KMeansService(); - $hasilKMeansCuras = $serviceKMeansCuras->hitungKMeansCuras(); + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); - $serviceKmeansCuranmor = new KMeansService(); - $hasilKMeansCuranmor = $serviceKmeansCuranmor->hitungKMeansCuranmor(); + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); - - Klaster::create($validateData); + + DB::commit(); + return redirect('/dashboard/klaster')->with('succes', 'Berhasil Menambahkan Klaster Baru'); }catch (\Exception $e){ + DB::rollBack(); + return redirect('/dashboard/klaster')->with('error', 'Gagal Menambahkan Klaster Baru ' .$e->getMessage()); } } @@ -85,17 +91,32 @@ public function edit(Klaster $klaster) */ public function update(Request $request, Klaster $klaster) { + $validateData = $request->validate([ + 'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id, + 'warna' => 'sometimes|required|max:255', + ]); + try { - $validateData = $request->validate([ - 'nama_klaster' => 'sometimes|required|max:255|unique:klasters,nama_klaster,' . $klaster->id, - 'warna' => 'sometimes|required|max:255', - ]); - + DB::beginTransaction(); // Hanya update data yang diisi (tidak mengganti dengan null) Klaster::where('id', $klaster->id)->update(array_filter($validateData)); - + + $serviceKMeans = new KMeansService(); + $serviceKMeans->SSEElbowCuranmor(); + $serviceKMeans->SSEElbowCuras(); + + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); + file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); + + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); + file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); + + DB::commit(); + return redirect('/dashboard/klaster')->with('success', 'Data Klaster Berhasil Diubah'); } catch (\Exception $e) { + + DB::rollBack(); return redirect('/dashboard/klaster')->with('error', 'Data Klaster Gagal Diubah'); } @@ -107,11 +128,27 @@ public function update(Request $request, Klaster $klaster) public function destroy(Klaster $klaster) { try{ + + DB::beginTransaction(); Klaster::destroy($klaster->id); + DB::commit(); + + $serviceKMeans = new KMeansService(); + $serviceKMeans->SSEElbowCuranmor(); + $serviceKMeans->SSEElbowCuras(); + + $hasilKMeansCuras = $serviceKMeans->hitungKMeansCuras(); + file_put_contents(storage_path('app/public/hasil_kmeans_curas.json'), json_encode($hasilKMeansCuras)); + + $hasilKMeansCuranmor = $serviceKMeans->hitungKMeansCuranmor(); + file_put_contents(storage_path('app/public/hasil_kmeans_curanmor.json'), json_encode($hasilKMeansCuranmor)); + return redirect('/dashboard/klaster')->with('succes', 'Data Klaster Berhasil Di Hapus'); }catch (\Exception $e){ - return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu'); + + DB::rollBack(); + return redirect('/dashboard/klaster')->with('error', 'Data Klaster '. $klaster->nama_kecamatan .' Gagal Di Hapus | Hapus Data Curas Atau Curanmor Untuk Klaster '. $klaster->nama_kecamatan.' Terlebih Dahulu '. $e->getMessage()); } } } \ No newline at end of file diff --git a/app/Http/Controllers/KmeansController.php b/app/Http/Controllers/KmeansController.php index 52f9b65..fd46253 100644 --- a/app/Http/Controllers/KmeansController.php +++ b/app/Http/Controllers/KmeansController.php @@ -13,23 +13,14 @@ public function KMeansCuras() { $data = Curas::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curas')->orderBy('jumlah_curas', 'asc')->get(); - $k = Klaster::count('id'); $maxIterasi = 100; - $uniqueCount = $data->unique('jumlah_curas')->count(); - if ($uniqueCount < $k) { - throw new \Exception("Jumlah nilai unik pada 'jumlah_curas' ($uniqueCount) kurang dari jumlah klaster ($k). Pastikan data memiliki variasi yang cukup."); - } - // Ambil centroid awal yang unik - // Gunakan centroid tetap - - $centroidValues = [0, 1, 3]; - $centroids = collect($centroidValues)->map(function ($val) { - return ['jumlah_curas' => $val]; + $centroidManual = [0, 1, 3]; + $centroids = collect($centroidManual)->map(function ($value) { + return ['C' => $value]; }); - // Simpan centroid awal sebelum iterasi $centroidAwal = $centroids->toArray(); $iterasi = []; @@ -43,13 +34,13 @@ public function KMeansCuras() $jarak = []; foreach ($centroids as $idx => $centroid) { - $dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); + $dist = abs($item->jumlah_curas - $centroid['C']); $jarak["C" . ($idx + 1)] = $dist; } $iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); - $minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2" + $minIndex = array_keys($jarak, min($jarak))[0]; $clusterNumber = (int) str_replace("C", "", $minIndex); $clustered[$clusterNumber][] = $item; @@ -57,65 +48,64 @@ public function KMeansCuras() $currentAssignment[$item->id] = $clusterNumber; } - // ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break if ($currentAssignment === $prevAssignment) { break; } $prevAssignment = $currentAssignment; - - // Update centroid berdasarkan rata-rata foreach ($clustered as $key => $group) { $avg = collect($group)->avg('jumlah_curas'); $centroids = $centroids->map(function ($item, $index) use ($key, $avg) { return $index === ($key - 1) - ? ['jumlah_curas' => $avg] + ? ['C' => $avg] : $item; }); } } - - // Final mapping centroid ke klaster_id (aman/sedang/rawan) + // Final mapping centroid ke klaster_id $finalCentroids = $centroids->map(function ($item, $index) { - return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']]; - })->sortBy('jumlah_curas')->values(); + return ['index' => $index + 1, 'C' => $item['C']]; + })->sortBy('C')->values(); - $centroidToKlaster = []; + $availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values(); foreach ($finalCentroids as $i => $centroid) { - // Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...) - $centroidToKlaster[$centroid['index']] = $i + 1; + $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i]; } - - // Update ke database foreach ($data as $item) { Curas::where('id', $item->id)->update([ 'klaster_id' => $centroidToKlaster[$item->temp_klaster], ]); } - + // Format centroid awal $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) { - return ['C' . ($index + 1) => $item['jumlah_curas']]; + return ['C' . ($index + 1) => $item['C']]; }); - - $hasil = [ + // Format centroid akhir + $centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) { + return ['C' . ($index + 1) => $item['C']]; + }); + + $hasilKMeansCuras = [ 'centroid_awal' => $centroidAwalFormatted, + 'centroid_akhir' => $centroidAkhirFormatted, 'iterasi' => $iterasi ]; - + file_put_contents( storage_path('app/public/hasil_kmeans_curas.json'), - json_encode($hasil, JSON_PRETTY_PRINT) + json_encode($hasilKMeansCuras, JSON_PRETTY_PRINT) ); + return redirect('/dashboard/TampilHitungCuras'); - + } @@ -123,20 +113,13 @@ public function KMeansCuranmor() { $data = Curanmor::select('id', 'kecamatan_id', 'klaster_id', 'jumlah_curanmor')->orderBy('jumlah_curanmor', 'asc')->get(); - $k = Klaster::count('id'); $maxIterasi = 100; - $uniqueCount = $data->unique('jumlah_curanmor')->count(); - if ($uniqueCount < $k) { - throw new \Exception("Jumlah nilai unik pada 'jumlah_curanmor' ($uniqueCount) kurang dari jumlah klaster ($k). Pastikan data memiliki variasi yang cukup."); - } - - $centroidValues = [10, 20, 30]; - $centroids = collect($centroidValues)->map(function ($val) { - return ['jumlah_curanmor' => $val]; + $centroidManual = [10, 20, 30]; + $centroids = collect($centroidManual)->map(function ($value) { + return ['C' => $value]; }); - // Simpan centroid awal sebelum iterasi $centroidAwal = $centroids->toArray(); $iterasi = []; @@ -148,82 +131,84 @@ public function KMeansCuranmor() foreach ($data as $item) { $jarak = []; - + foreach ($centroids as $idx => $centroid) { - // Menggunakan Euclidean distance standar (akar kuadrat dari selisih kuadrat) - $dist = sqrt(pow($item->jumlah_curanmor - $centroid['jumlah_curanmor'], 2)); + $dist = abs($item->jumlah_curanmor - $centroid['C']); $jarak["C" . ($idx + 1)] = $dist; } - + $iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); - - $minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2" + + $minIndex = array_keys($jarak, min($jarak))[0]; $clusterNumber = (int) str_replace("C", "", $minIndex); - + $clustered[$clusterNumber][] = $item; $item->temp_klaster = $clusterNumber; $currentAssignment[$item->id] = $clusterNumber; } - - // ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break if ($currentAssignment === $prevAssignment) { break; } $prevAssignment = $currentAssignment; - - // Update centroid berdasarkan rata-rata foreach ($clustered as $key => $group) { $avg = collect($group)->avg('jumlah_curanmor'); $centroids = $centroids->map(function ($item, $index) use ($key, $avg) { return $index === ($key - 1) - ? ['jumlah_curanmor' => $avg] + ? ['C' => $avg] : $item; }); } } - - // Final mapping centroid ke klaster_id (aman/sedang/rawan) + // Final mapping centroid ke klaster_id $finalCentroids = $centroids->map(function ($item, $index) { - return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']]; - })->sortBy('jumlah_curanmor')->values(); + return ['index' => $index + 1, 'C' => $item['C']]; + })->sortBy('C')->values(); - $centroidToKlaster = []; + $availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values(); foreach ($finalCentroids as $i => $centroid) { - // Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...) - $centroidToKlaster[$centroid['index']] = $i + 1; + $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i]; } // Update ke database + + + foreach ($data as $item) { Curanmor::where('id', $item->id)->update([ 'klaster_id' => $centroidToKlaster[$item->temp_klaster], ]); } - + // Format centroid awal $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) { - return ['C' . ($index + 1) => $item['jumlah_curanmor']]; + return ['C' . ($index + 1) => $item['C']]; }); - - $hasil = [ + + // Format centroid akhir + $centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) { + return ['C' . ($index + 1) => $item['C']]; + }); + + $hasilKMeansCuranmor = [ 'centroid_awal' => $centroidAwalFormatted, + 'centroid_akhir' => $centroidAkhirFormatted, 'iterasi' => $iterasi ]; - + file_put_contents( storage_path('app/public/hasil_kmeans_curanmor.json'), - json_encode($hasil, JSON_PRETTY_PRINT) + json_encode($hasilKMeansCuranmor, JSON_PRETTY_PRINT) ); + return redirect('/dashboard/TampilHitungCuranmor'); - } } diff --git a/app/Services/KMeansService.php b/app/Services/KMeansService.php index 4dc2a93..3a30f0f 100644 --- a/app/Services/KMeansService.php +++ b/app/Services/KMeansService.php @@ -21,15 +21,16 @@ public function hitungKMeansCuras() $generated = collect(); while ($generated->count() < $k) { - $randomFloat = round(mt_rand($minValue * 100, $maxValue * 100) / 100, 2); - if (!$generated->contains($randomFloat)) { - $generated->push($randomFloat); + $random = mt_rand($minValue, $maxValue); + if (!$generated->contains($random)) { + $generated->push($random); } } $centroids = $generated->map(function ($value) { - return ['jumlah_curas' => $value]; + return ['C' => $value]; }); + $centroidAwal = $centroids->toArray(); $iterasi = []; @@ -43,7 +44,7 @@ public function hitungKMeansCuras() $jarak = []; foreach ($centroids as $idx => $centroid) { - $dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); + $dist = abs($item->jumlah_curas - $centroid['C']); $jarak["C" . ($idx + 1)] = $dist; } @@ -68,7 +69,7 @@ public function hitungKMeansCuras() $avg = collect($group)->avg('jumlah_curas'); $centroids = $centroids->map(function ($item, $index) use ($key, $avg) { return $index === ($key - 1) - ? ['jumlah_curas' => $avg] + ? ['C' => $avg] : $item; }); } @@ -76,15 +77,20 @@ public function hitungKMeansCuras() // Final mapping centroid ke klaster_id $finalCentroids = $centroids->map(function ($item, $index) { - return ['index' => $index + 1, 'jumlah_curas' => $item['jumlah_curas']]; - })->sortBy('jumlah_curas')->values(); + return ['index' => $index + 1, 'C' => $item['C']]; + })->sortBy('C')->values(); + + $availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values(); - $centroidToKlaster = []; foreach ($finalCentroids as $i => $centroid) { - $centroidToKlaster[$centroid['index']] = $i + 1; + $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i]; } + // Update ke database + + + foreach ($data as $item) { Curas::where('id', $item->id)->update([ 'klaster_id' => $centroidToKlaster[$item->temp_klaster], @@ -93,12 +99,12 @@ public function hitungKMeansCuras() // Format centroid awal $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) { - return ['C' . ($index + 1) => $item['jumlah_curas']]; + return ['C' . ($index + 1) => $item['C']]; }); // Format centroid akhir $centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) { - return ['C' . ($index + 1) => $item['jumlah_curas']]; + return ['C' . ($index + 1) => $item['C']]; }); return [ @@ -115,20 +121,22 @@ public function hitungKMeansCuranmor() $k = Klaster::count('id'); $maxIterasi = 100; + // Ambil centroid awal yang unik $minValue = $data->min('jumlah_curanmor'); $maxValue = $data->max('jumlah_curanmor'); $generated = collect(); while ($generated->count() < $k) { - $randomFloat = round(mt_rand($minValue * 100, $maxValue * 100) / 100, 2); - if (!$generated->contains($randomFloat)) { - $generated->push($randomFloat); + $random = mt_rand($minValue, $maxValue); + if (!$generated->contains($random)) { + $generated->push($random); } } $centroids = $generated->map(function ($value) { - return ['jumlah_curanmor' => $value]; + return ['C' => $value]; }); + $centroidAwal = $centroids->toArray(); $iterasi = []; @@ -142,13 +150,13 @@ public function hitungKMeansCuranmor() $jarak = []; foreach ($centroids as $idx => $centroid) { - $dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']); + $dist = abs($item->jumlah_curanmor - $centroid['C']); $jarak["C" . ($idx + 1)] = $dist; } $iterasi[$i][] = array_merge(['kecamatan_id' => $item->kecamatan_id], $jarak); - $minIndex = array_keys($jarak, min($jarak))[0]; // e.g. "jarakC2" + $minIndex = array_keys($jarak, min($jarak))[0]; $clusterNumber = (int) str_replace("C", "", $minIndex); $clustered[$clusterNumber][] = $item; @@ -156,77 +164,78 @@ public function hitungKMeansCuranmor() $currentAssignment[$item->id] = $clusterNumber; } - // ✨ Cek konvergensi: jika assignment sekarang == sebelumnya, break if ($currentAssignment === $prevAssignment) { break; } $prevAssignment = $currentAssignment; - - // Update centroid berdasarkan rata-rata foreach ($clustered as $key => $group) { $avg = collect($group)->avg('jumlah_curanmor'); $centroids = $centroids->map(function ($item, $index) use ($key, $avg) { return $index === ($key - 1) - ? ['jumlah_curanmor' => $avg] + ? ['C' => $avg] : $item; }); } } - - // Final mapping centroid ke klaster_id (aman/sedang/rawan) + // Final mapping centroid ke klaster_id $finalCentroids = $centroids->map(function ($item, $index) { - return ['index' => $index + 1, 'jumlah_curanmor' => $item['jumlah_curanmor']]; - })->sortBy('jumlah_curanmor')->values(); + return ['index' => $index + 1, 'C' => $item['C']]; + })->sortBy('C')->values(); - $centroidToKlaster = []; + $availableKlasterIDs = Klaster::orderBy('id', 'asc')->pluck('id')->values(); foreach ($finalCentroids as $i => $centroid) { - // Klaster ID mulai dari 1 (asumsi klaster di DB bernomor 1, 2, 3, ...) - $centroidToKlaster[$centroid['index']] = $i + 1; + $centroidToKlaster[$centroid['index']] = $availableKlasterIDs[$i]; } // Update ke database + + + foreach ($data as $item) { Curanmor::where('id', $item->id)->update([ 'klaster_id' => $centroidToKlaster[$item->temp_klaster], ]); } - + // Format centroid awal $centroidAwalFormatted = collect($centroidAwal)->values()->map(function ($item, $index) { - return ['C' . ($index + 1) => $item['jumlah_curanmor']]; + return ['C' . ($index + 1) => $item['C']]; }); - + + // Format centroid akhir + $centroidAkhirFormatted = $centroids->values()->map(function ($item, $index) { + return ['C' . ($index + 1) => $item['C']]; + }); + return [ 'centroid_awal' => $centroidAwalFormatted, + 'centroid_akhir' => $centroidAkhirFormatted, 'iterasi' => $iterasi ]; - } - public function SSEElbowCuras() + public function SSEElbowCuranmor() { - $data = Curas::select('id', 'jumlah_curas')->get(); + $data = Curanmor::select('id', 'jumlah_curanmor')->get(); $maxK = 10; $maxIterasi = 100; $elbowData = []; - // Ambil nilai minimum dan maksimum dari jumlah_curas - $min = $data->min('jumlah_curas'); - $max = $data->max('jumlah_curas'); + $min = $data->min('jumlah_curanmor'); + $max = $data->max('jumlah_curanmor'); + // Loop untuk setiap nilai k dari 2 hingga maxK for ($k = 2; $k <= $maxK; $k++) { - // Inisialisasi centroid awal sebagai float acak dalam rentang min-max $centroids = collect(range(1, $k))->map(function () use ($min, $max) { - return ['jumlah_curas' => mt_rand($min * 100, $max * 100) / 100]; + return ['jumlah_curanmor' => mt_rand($min, $max)]; }); - $centroidAwal = $centroids->pluck('jumlah_curas')->toArray(); $prevAssignment = []; for ($iter = 0; $iter < $maxIterasi; $iter++) { @@ -236,22 +245,104 @@ public function SSEElbowCuras() foreach ($data as $item) { $jarak = []; + // Hitung jarak antara data dan setiap centroid foreach ($centroids as $idx => $centroid) { - $dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); + $dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']); $jarak[$idx] = $dist; } + // Tentukan cluster dengan jarak terdekat $minIndex = array_keys($jarak, min($jarak))[0]; $clustered[$minIndex][] = $item; $currentAssignment[$item->id] = $minIndex; } + // Jika tidak ada perubahan cluster, break if ($currentAssignment === $prevAssignment) { break; } $prevAssignment = $currentAssignment; + // Update centroid dengan rata-rata cluster + foreach ($clustered as $key => $group) { + $avg = collect($group)->avg('jumlah_curanmor'); + $centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) { + return $idx == $key + ? ['jumlah_curanmor' => $avg] + : $centroid; + }); + } + } + + // Hitung SSE (Sum of Squared Errors) + $sse = 0; + foreach ($clustered as $key => $group) { + $centroidVal = $centroids[$key]['jumlah_curanmor']; + foreach ($group as $item) { + $sse += pow($item->jumlah_curanmor - $centroidVal, 2); + } + } + + // Simpan SSE untuk nilai k + $elbowData[] = [ + 'k' => $k, + 'sse' => round($sse, 4) + ]; + } + + // Simpan hasil SSE untuk setiap k ke file JSON + file_put_contents( + storage_path('app/public/sse_elbow_curanmor.json'), + json_encode($elbowData, JSON_PRETTY_PRINT) + ); + } + + public function SSEElbowCuras() + { + $data = Curas::select('id', 'jumlah_curas')->get(); + $maxK = 10; + $maxIterasi = 100; + $elbowData = []; + + $min = $data->min('jumlah_curas'); + $max = $data->max('jumlah_curas'); + + // Loop untuk setiap nilai k dari 2 hingga maxK + for ($k = 2; $k <= $maxK; $k++) { + $centroids = collect(range(1, $k))->map(function () use ($min, $max) { + return ['jumlah_curas' => mt_rand($min, $max)]; + }); + + $prevAssignment = []; + + for ($iter = 0; $iter < $maxIterasi; $iter++) { + $clustered = []; + $currentAssignment = []; + + foreach ($data as $item) { + $jarak = []; + + // Hitung jarak antara data dan setiap centroid + foreach ($centroids as $idx => $centroid) { + $dist = abs($item->jumlah_curas - $centroid['jumlah_curas']); + $jarak[$idx] = $dist; + } + + // Tentukan cluster dengan jarak terdekat + $minIndex = array_keys($jarak, min($jarak))[0]; + $clustered[$minIndex][] = $item; + $currentAssignment[$item->id] = $minIndex; + } + + // Jika tidak ada perubahan cluster, break + if ($currentAssignment === $prevAssignment) { + break; + } + + $prevAssignment = $currentAssignment; + + // Update centroid dengan rata-rata cluster foreach ($clustered as $key => $group) { $avg = collect($group)->avg('jumlah_curas'); $centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) { @@ -262,7 +353,7 @@ public function SSEElbowCuras() } } - // Hitung SSE + // Hitung SSE (Sum of Squared Errors) $sse = 0; foreach ($clustered as $key => $group) { $centroidVal = $centroids[$key]['jumlah_curas']; @@ -271,96 +362,22 @@ public function SSEElbowCuras() } } + // Simpan SSE untuk nilai k $elbowData[] = [ 'k' => $k, - 'sse' => $sse, - 'centroid_awal' => $centroidAwal + 'sse' => round($sse, 4) ]; } - - + // Simpan hasil SSE untuk setiap k ke file JSON file_put_contents( storage_path('app/public/sse_elbow_curas.json'), json_encode($elbowData, JSON_PRETTY_PRINT) ); } - - public function SSEElbowCuranmor() - { - $data = Curanmor::select('id', 'jumlah_curanmor')->get(); - $maxK = 10; - $maxIterasi = 100; - $elbowData = []; - - for ($k = 2; $k <= $maxK; $k++) { - // Inisialisasi centroid awal secara acak - $centroids = $data->unique('jumlah_curanmor')->shuffle()->take($k)->values()->map(function ($item) { - return ['jumlah_curanmor' => $item->jumlah_curanmor]; - }); - - // Simpan centroid awal sebagai array angka - $centroidAwal = $centroids->pluck('jumlah_curanmor')->toArray(); - - $prevAssignment = []; - - for ($iter = 0; $iter < $maxIterasi; $iter++) { - $clustered = []; - $currentAssignment = []; - - foreach ($data as $item) { - $jarak = []; - - foreach ($centroids as $idx => $centroid) { - $dist = abs($item->jumlah_curanmor - $centroid['jumlah_curanmor']); - $jarak[$idx] = $dist; - } - - $minIndex = array_keys($jarak, min($jarak))[0]; - $clustered[$minIndex][] = $item; - $currentAssignment[$item->id] = $minIndex; - } - - if ($currentAssignment === $prevAssignment) { - break; - } - - $prevAssignment = $currentAssignment; - - // Update centroid - foreach ($clustered as $key => $group) { - $avg = collect($group)->avg('jumlah_curanmor'); - $centroids = $centroids->map(function ($centroid, $idx) use ($key, $avg) { - return $idx == $key - ? ['jumlah_curanmor' => $avg] - : $centroid; - }); - } - } - - // Hitung SSE untuk k saat ini - $sse = 0; - foreach ($clustered as $key => $group) { - $centroidVal = $centroids[$key]['jumlah_curanmor']; - foreach ($group as $item) { - $sse += pow($item->jumlah_curanmor - $centroidVal, 2); - } - } - - $elbowData[] = [ - 'k' => $k, - 'sse' => $sse, - 'centroid_awal' => $centroidAwal - ]; - } - - // Simpan ke file - file_put_contents( - storage_path('app/public/sse_elbow_curanmor.json'), - json_encode($elbowData, JSON_PRETTY_PRINT) - ); - } + + } diff --git a/database/migrations/2025_02_20_164705_create_curas_table.php b/database/migrations/2025_02_20_164705_create_curas_table.php index a1e8d32..4596538 100644 --- a/database/migrations/2025_02_20_164705_create_curas_table.php +++ b/database/migrations/2025_02_20_164705_create_curas_table.php @@ -17,7 +17,7 @@ public function up(): void table: 'kecamatans', indexName: 'curas_kecamatan_id'); $table->float('jumlah_curas'); $table->foreignId('klaster_id')->nullable()->constrained( - table: 'klasters', indexName: 'curas_klaster_id'); + table: 'klasters', indexName: 'curas_klaster_id')->nullOnDelete(); $table->timestamps(); }); } diff --git a/database/migrations/2025_02_20_164712_create_curanmors_table.php b/database/migrations/2025_02_20_164712_create_curanmors_table.php index fc89a17..a3bec8b 100644 --- a/database/migrations/2025_02_20_164712_create_curanmors_table.php +++ b/database/migrations/2025_02_20_164712_create_curanmors_table.php @@ -17,7 +17,7 @@ public function up(): void table: 'kecamatans', indexName: 'curanmor_kecamatan_id'); $table->float('jumlah_curanmor'); $table->foreignId('klaster_id')->nullable()->constrained( - table: 'klasters', indexName: 'klaster_kecamatan_id'); + table: 'klasters', indexName: 'klaster_kecamatan_id')->nullOnDelete(); $table->timestamps(); }); } diff --git a/public/assets/js/chart-custom.js b/public/assets/js/chart-custom.js index 87eb8bb..a589a85 100644 --- a/public/assets/js/chart-custom.js +++ b/public/assets/js/chart-custom.js @@ -5213,12 +5213,11 @@ if (jQuery("#editor").length) { valueAxis.title.text = "Nilai SSE"; let lineSeries = chart.series.push(new am4charts.LineSeries()); - lineSeries.dataFields.valueY = "sse"; lineSeries.dataFields.categoryX = "k"; lineSeries.name = "SSE"; lineSeries.strokeWidth = 2; - lineSeries.tooltipText = "K={categoryX}\nSSE={valueY}\nCentroid Awal: {centroid_awal}"; + lineSeries.tooltipText = "K={categoryX}\nSSE={valueY}"; // Tooltip tanpa centroid_awal lineSeries.tensionX = 1; let bullet = lineSeries.bullets.push(new am4charts.CircleBullet()); @@ -5236,20 +5235,19 @@ if (jQuery("#editor").length) { fetch(`/storage/sse_elbow_${type}.json`) .then(response => response.json()) .then(data => { + // Format data untuk chart chart.data = data.map(item => ({ k: item.k, - sse: item.sse, - centroid_awal: item.centroid_awal.join(", ") + sse: item.sse })); console.log("Data yang dimuat ke chart:", chart.data); - }); } - // Load data default saat pertama kali (curas) + // Load data default saat pertama kali (curanmor) loadChartData('curanmor'); - // Event listener dropdown + // Event listener dropdown untuk memilih tipe data document.querySelectorAll('.chart-option').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); diff --git a/resources/views/admin/dashboardListCuras.blade.php b/resources/views/admin/dashboardListCuras.blade.php index 3af730e..2260b73 100644 --- a/resources/views/admin/dashboardListCuras.blade.php +++ b/resources/views/admin/dashboardListCuras.blade.php @@ -11,7 +11,8 @@ Tambah Kasus Curas - @if (session()->has('succes')) + + @if (session()->has('succes')) @@ -21,7 +22,7 @@ {{ session('error') }} @endif - +
diff --git a/resources/views/admin/dashboardListKecamatan.blade.php b/resources/views/admin/dashboardListKecamatan.blade.php index 332b7d0..ab28a64 100644 --- a/resources/views/admin/dashboardListKecamatan.blade.php +++ b/resources/views/admin/dashboardListKecamatan.blade.php @@ -35,7 +35,7 @@ - + @@ -50,7 +50,7 @@ -
NoNama KecamatanNama Kecamatan Action
{{ $kecamatan -> id }} {{ $kecamatan -> nama_kecamatan }} +
diff --git a/resources/views/admin/dashboardListKlaster.blade.php b/resources/views/admin/dashboardListKlaster.blade.php index 8198cb7..65c0ab3 100644 --- a/resources/views/admin/dashboardListKlaster.blade.php +++ b/resources/views/admin/dashboardListKlaster.blade.php @@ -13,15 +13,15 @@
@if (session()->has('succes')) - - @endif - @if (session()->has('error')) - - @endif + + @endif + @if (session()->has('error')) + + @endif
diff --git a/resources/views/components/layoutAdmin.blade.php b/resources/views/components/layoutAdmin.blade.php index aff3097..21a8bdb 100644 --- a/resources/views/components/layoutAdmin.blade.php +++ b/resources/views/components/layoutAdmin.blade.php @@ -357,12 +357,11 @@ class="rounded profile-img img-fluid avatar-70">
- © POS Dash. + © KProtect.