434 lines
16 KiB
PHP
434 lines
16 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Hasil Uji Data')
|
|
@section('content')
|
|
|
|
@if (session('success'))
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
{{ session('success') }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="card p-4 shadow-sm mb-4">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div>
|
|
<h4><strong>Gunakan seluruh Dataset sebagai Data Latih?</strong></h4>
|
|
<p class="text-muted">Silakan reset data terlebih dahulu sebelum memilih opsi atau mengganti opsi.</p>
|
|
</div>
|
|
<form action="{{ route('uji.reset') }}" method="POST" onsubmit="return confirm('Yakin ingin mereset hasil uji?')">
|
|
@csrf
|
|
<button type="submit" class="btn btn-danger">Reset Data</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
<form id="datasetForm" method="POST" action="{{ route('uji-data.reset') }}">
|
|
@csrf
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="radio" name="gunakan_dataset" id="radioYa" value="ya"
|
|
{{ session('enable_radio') ? '' : 'disabled' }}>
|
|
<label class="form-check-label" for="radioYa">Ya</label>
|
|
</div>
|
|
<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="radio" name="gunakan_dataset" id="radioTidak" value="tidak"
|
|
{{ session('enable_radio') ? '' : 'disabled' }}>
|
|
<label class="form-check-label" for="radioTidak">Tidak</label>
|
|
</div>
|
|
</form>
|
|
|
|
<div id="inputDataUji" class="mt-4">
|
|
<h5>Input data yang akan diuji</h5>
|
|
<form method="POST" action="{{ route('uji-data.upload') }}" enctype="multipart/form-data">
|
|
@csrf
|
|
<div class="mb-3 d-flex align-items-center">
|
|
<label for="fileExcel" class="form-label me-2 mb-0">Pilih File Excel</label>
|
|
<input class="form-control me-2" type="file" name="file_excel" id="fileExcel" accept=".xls,.xlsx" required style="max-width: 300px;">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-mouse-pointer"></i> Gunakan
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
|
|
<div id="splitOption" style="display:none;" class="mt-4">
|
|
<form id="formSplit" method="POST" action="{{ route('uji.proses') }}">
|
|
@csrf
|
|
<label for="splitData" class="form-label"><strong>Splitting Data Latih</strong></label>
|
|
<div class="input-group" style="max-width: 200px;">
|
|
<select id="splitData" name="persentase" class="form-select">
|
|
<option value="50">50%</option>
|
|
<option value="60">60%</option>
|
|
<option value="70">70%</option>
|
|
<option value="75">75%</option>
|
|
<option value="80">80%</option>
|
|
<option value="85">85%</option>
|
|
<option value="90">90%</option>
|
|
<option value="95">95%</option>
|
|
|
|
</select>
|
|
<button type="submit" class="btn btn-primary ms-2" id="applySplit">
|
|
<i class="fas fa-mouse-pointer"></i> Terapkan
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="row text-center mt-4">
|
|
<h3>Pembagian Data</h3>
|
|
<div class="col-md-6 mb-3">
|
|
<div class="card text-white bg-info p-4 rounded">
|
|
<div>
|
|
<i class="fas fa-chart-bar fa-3x"></i>
|
|
</div>
|
|
<h2 id="persenLatih">{{ $persentase_latih }}%</h2>
|
|
<h4>Data Latih</h4>
|
|
<p>Nilai Asli <span id="jumlahLatih">{{ $jumlah_data_latih }}</span> Data</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<div class="card text-white bg-success p-4 rounded">
|
|
<div>
|
|
<i class="fas fa-flask fa-3x"></i>
|
|
</div>
|
|
<h2 id="persenUji">{{ $persentase_uji }}%</h2>
|
|
<h4>Data Uji</h4>
|
|
<p>Nilai Asli <span id="jumlahUji">{{ $jumlah_data_uji }}</span> Data</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<hr>
|
|
<h4>Probabilitas Kelas Data Latih</h4>
|
|
<div class="row text-center mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card p-3 shadow-sm border-left border-danger">
|
|
<h5 class="text-danger">Naik</h5>
|
|
<p style="font-size: 1.5rem; font-weight: bold;">
|
|
{{ number_format($prob_naik * 100, 2) }}%
|
|
</p>
|
|
<p class="text-muted" style="margin: 0;">
|
|
({{ $jumlah_naik }} dari {{ $jumlah_data_latih }} data)
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card p-3 shadow-sm border-left border-success">
|
|
<h5 class="text-success">Turun</h5>
|
|
<p style="font-size: 1.5rem; font-weight: bold;">
|
|
{{ number_format($prob_turun * 100, 2) }}%
|
|
</p>
|
|
<p class="text-muted" style="margin: 0;">
|
|
({{ $jumlah_turun }} dari {{ $jumlah_data_latih }} data)
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="row justify-content-center">
|
|
@foreach ($atribut_numerik as $fitur => $data)
|
|
|
|
@php
|
|
// Definisikan icon dan warna sesuai atribut
|
|
$icon = '';
|
|
$color = '';
|
|
switch ($fitur) {
|
|
case 'phbs':
|
|
$icon = '📘'; // Buku biru (bisa ganti pakai fontawesome atau svg)
|
|
$color = '#0d6efd'; // biru
|
|
break;
|
|
case 'imunisasi':
|
|
$icon = '📜'; // Gulungan kertas hijau
|
|
$color = '#198754'; // hijau
|
|
break;
|
|
case 'merokok':
|
|
$icon = '🚬'; // Icon rokok merah (boleh ganti)
|
|
$color = '#dc3545'; // merah
|
|
break;
|
|
case 'kasus_2023':
|
|
$icon = '📅'; // Kalender kuning
|
|
$color = '#ffc107'; // kuning
|
|
break;
|
|
default:
|
|
$icon = '📊'; // Default chart icon
|
|
$color = '#6c757d'; // abu-abu
|
|
}
|
|
@endphp
|
|
|
|
<div class="col-md-3 mb-4">
|
|
<div class="card p-4 shadow-sm" style="border-radius: 12px;">
|
|
<div class="text-center mb-3">
|
|
<div style="font-size: 3rem; color: {{ $color }};">
|
|
{!! $icon !!}
|
|
</div>
|
|
<h5 class="card-title" style="color: {{ $color }}; font-weight: 600; margin-top: 0.5rem;">
|
|
{{ $data['label'] ?? 'Tidak ada label' }}
|
|
</h5>
|
|
</div>
|
|
|
|
<div class="text-center" style="font-weight: 600; color: #555;">
|
|
Mean
|
|
</div>
|
|
<div class="d-flex justify-content-between px-3 my-2" style="color: #555;">
|
|
<div style="font-size: 0.9rem;">Turun</div>
|
|
<div style="font-size: 0.9rem;">Naik</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between px-3 mb-3">
|
|
<div style="font-weight: 700; font-size: 1.3rem; color: #000;">
|
|
{{ number_format($data['mean']['naik'], 2) }}
|
|
</div>
|
|
<div style="font-weight: 700; font-size: 1.3rem; color: #dc3545;">
|
|
{{ number_format($data['mean']['turun'], 2) }}
|
|
</div>
|
|
</div>
|
|
|
|
<hr style="margin: 1rem 0; border-color: #ddd;">
|
|
|
|
<div class="text-center" style="font-weight: 600; color: #555;">
|
|
Standar Deviasi
|
|
</div>
|
|
<div class="d-flex justify-content-between px-3 my-2" style="color: #555;">
|
|
<div style="font-size: 0.9rem;">Turun</div>
|
|
<div style="font-size: 0.9rem;">Naik</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between px-3">
|
|
<div style="font-weight: 700; font-size: 1.3rem; color: #000;">
|
|
{{ number_format($data['std']['naik'], 2) }}
|
|
</div>
|
|
<div style="font-weight: 700; font-size: 1.3rem; color: #dc3545;">
|
|
{{ number_format($data['std']['turun'], 2) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
<hr>
|
|
<h4>Hasil Pengujian Data Uji</h4>
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-bordered">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Kecamatan</th>
|
|
<th>Data Tahun</th>
|
|
<th>PHBS</th>
|
|
<th>Imunisasi</th>
|
|
<th>Merokok</th>
|
|
<th>Jumlah Kasus</th>
|
|
<th>Latitude</th>
|
|
<th>Longitude</th>
|
|
<th>Prediksi Tahun</th>
|
|
@unless ($from_excel)
|
|
<th>Status Asli</th>
|
|
@endunless
|
|
<th>Status Prediksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach ($data_uji as $item)
|
|
<tr>
|
|
<td>{{ $item['id'] }}</td>
|
|
<td>{{ $item['kabupaten'] }}</td>
|
|
<td>{{ $item['data_tahun'] ?? '-' }}</td>
|
|
<td>{{ $item['phbs'] }}</td>
|
|
<td>{{ $item['imunisasi'] }}</td>
|
|
<td>{{ $item['merokok'] }}</td>
|
|
<td>{{ $item['kasus_2023'] }}</td>
|
|
<td>{{ $item['latitude'] }}</td>
|
|
<td>{{ $item['longitude'] }}</td>
|
|
<td>
|
|
@if(isset($item['data_tahun']))
|
|
@if(in_array((int)$item['data_tahun'], [2023, 2024]))
|
|
2025
|
|
@else
|
|
{{ (int)$item['data_tahun'] + 1 }}
|
|
@endif
|
|
@else
|
|
-
|
|
@endif
|
|
</td>
|
|
@unless ($from_excel)
|
|
<td>{{ $item['hipotesis_asli'] }}</td>
|
|
@endunless
|
|
<td>
|
|
<span class="badge {{ $item['prediksi'] == 'Naik' ? 'bg-danger' : 'bg-success' }}">
|
|
{{ $item['prediksi'] }}
|
|
</span>
|
|
</td>
|
|
<!-- dst -->
|
|
</tr>
|
|
@endforeach
|
|
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<hr>
|
|
|
|
<h4>Confusion Matrix</h4>
|
|
<div class="row text-center">
|
|
<div class="col-md-3">
|
|
<h5>Data yang di Uji</h5>
|
|
<p><strong>{{ $jumlah_data_uji }}</strong></p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<h5>Akurasi Model</h5>
|
|
<p><strong>{{ $akurasi }}%</strong></p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<h5>Precision</h5>
|
|
<p><strong>{{ $precision }}%</strong></p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<h5>Recall</h5>
|
|
<p><strong>{{ $recall }}%</strong></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row text-center mt-4">
|
|
<div class="col-md-3"><strong>True Positive (TP):</strong><br>{{ $tp }}</div>
|
|
<div class="col-md-3"><strong>False Positive (FP):</strong><br>{{ $fp }}</div>
|
|
<div class="col-md-3"><strong>True Negative (TN):</strong><br>{{ $tn }}</div>
|
|
<div class="col-md-3"><strong>False Negative (FN):</strong><br>{{ $fn }}</div>
|
|
</div>
|
|
</div>
|
|
@push('scripts')
|
|
<script>
|
|
const resetBtn = document.getElementById('resetBtn');
|
|
const radioYa = document.getElementById('radioYa');
|
|
const radioTidak = document.getElementById('radioTidak');
|
|
const inputDataUji = document.getElementById('inputDataUji');
|
|
const splitOption = document.getElementById('splitOption');
|
|
const applySplit = document.getElementById('applySplit');
|
|
const splitData = document.getElementById('splitData');
|
|
const persenLatihElem = document.getElementById('persenLatih');
|
|
const persenUjiElem = document.getElementById('persenUji');
|
|
const jumlahLatihElem = document.getElementById('jumlahLatih');
|
|
const jumlahUjiElem = document.getElementById('jumlahUji');
|
|
const totalData = {{ $jumlah_data ?? 0 }};
|
|
|
|
function resetForm() {
|
|
radioYa.disabled = false;
|
|
radioTidak.disabled = false;
|
|
radioYa.checked = false;
|
|
radioTidak.checked = false;
|
|
inputDataUji.style.display = 'none';
|
|
splitOption.style.display = 'none';
|
|
}
|
|
|
|
resetBtn.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
resetForm();
|
|
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Berhasil!',
|
|
text: 'Data uji telah direset.',
|
|
showConfirmButton: false,
|
|
timer: 2000
|
|
});
|
|
});
|
|
|
|
radioYa.addEventListener('change', function () {
|
|
if (this.checked) {
|
|
inputDataUji.style.display = 'block';
|
|
splitOption.style.display = 'none';
|
|
radioTidak.disabled = true;
|
|
}
|
|
});
|
|
|
|
radioTidak.addEventListener('change', function () {
|
|
if (this.checked) {
|
|
inputDataUji.style.display = 'none';
|
|
splitOption.style.display = 'block';
|
|
radioYa.disabled = true;
|
|
}
|
|
});
|
|
|
|
applySplit.addEventListener('click', function () {
|
|
const persenLatih = parseInt(splitData.value);
|
|
const persenUji = 100 - persenLatih;
|
|
|
|
const jumlahLatih = Math.round(totalData * persenLatih / 100);
|
|
const jumlahUji = totalData - jumlahLatih;
|
|
|
|
persenLatihElem.textContent = persenLatih + '%';
|
|
persenUjiElem.textContent = persenUji + '%';
|
|
jumlahLatihElem.textContent = jumlahLatih;
|
|
jumlahUjiElem.textContent = jumlahUji;
|
|
});
|
|
document.getElementById('resetForm').addEventListener('submit', function(e) {
|
|
e.preventDefault(); // cegah form langsung submit
|
|
|
|
Swal.fire({
|
|
title: 'Yakin ingin reset data hasil uji?',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Ya',
|
|
cancelButtonText: 'Tidak',
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Kirim data via fetch/ajax supaya gak reload halaman
|
|
fetch(this.action, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': document.querySelector('input[name=_token]').value,
|
|
'Accept': 'application/json',
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if(data.success){
|
|
resetForm(); // fungsi dari kamu yang mengaktifkan radio dan sembunyikan elemen
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Berhasil!',
|
|
text: 'Data uji telah direset.',
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
});
|
|
} else {
|
|
Swal.fire('Gagal', 'Reset data gagal dilakukan.', 'error');
|
|
}
|
|
})
|
|
.catch(() => {
|
|
Swal.fire('Gagal', 'Terjadi kesalahan server.', 'error');
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
@endpush
|
|
@push('scripts')
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const radioYa = document.getElementById('radioYa');
|
|
const radioTidak = document.getElementById('radioTidak');
|
|
const inputDataUji = document.getElementById('inputDataUji');
|
|
const splitOption = document.getElementById('splitOption');
|
|
|
|
function toggleInputOptions() {
|
|
if (radioYa.checked) {
|
|
inputDataUji.style.display = 'block';
|
|
splitOption.style.display = 'none';
|
|
} else if (radioTidak.checked) {
|
|
inputDataUji.style.display = 'none';
|
|
splitOption.style.display = 'block';
|
|
} else {
|
|
inputDataUji.style.display = 'none';
|
|
splitOption.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// Jalankan saat halaman pertama kali dimuat
|
|
toggleInputOptions();
|
|
|
|
// Event listener saat radio berubah
|
|
radioYa.addEventListener('change', toggleInputOptions);
|
|
radioTidak.addEventListener('change', toggleInputOptions);
|
|
});
|
|
</script>
|
|
@endpush
|
|
@endsection |