PIKIRAN

Dashboard Analisis Sentimen MBG Libur

:root { –color-primary: #2180 8D; –color-primary-hover: #1D7480; –color-primary-active: #1A6873; –color-success: #208D81; –color-warning: #A84B2F; –color-error: #C0152F; –color-bg-1: rgba(59, 130, 246, 0.08); –color-bg-2: rgba(245, 158, 11, 0.08); –color-bg-3: rgba(34, 197, 94, 0.08); –color-bg-4: rgba(239, 68, 68, 0.08); –color-bg-5: rgba(147, 51, 234, 0.08); –color-bg-6: rgba(249, 115, 22, 0.08); –color-bg-7: rgba(236, 72, 153, 0.08); –color-bg-8: rgba(6, 182, 212, 0.08); –color-background: #fCfCf9; –color-surface: #ffFffd; –color-text: #134252; –color-text-secondary: #627078; –color-border: rgba(94, 82, 64, 0.2); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, ‘Segoe UI’, Roboto, sans-serif; background-color: var(–color-background); color: var(–color-text); line-height: 1.6; } .container { max-width: 1400px; margin: 0 auto; padding: 20px; } header { background: linear-gradient(135deg, #208D81 0%, #1D7480 100%); color: white; padding: 30px 20px; border-radius: 12px; margin-bottom: 30px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } header h1 { font-size: 32px; margin-bottom: 10px; font-weight: 600; } header p { font-size: 16px; opacity: 0.9; } .kpi-section { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 30px; } .kpi-card { background: var(–color-surface); border: 1px solid var(–color-border); border-radius: 10px; padding: 20px; text-align: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); transition: all 0.3s ease; } .kpi-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); transform: translateY(-2px); } .kpi-card .label { font-size: 12px; color: var(–color-text-secondary); text-transform: uppercase; font-weight: 600; letter-spacing: 0.5px; margin-bottom: 8px; } .kpi-card .value { font-size: 28px; font-weight: 700; color: var(–color-primary); margin-bottom: 4px; } .kpi-card .subtext { font-size: 12px; color: var(–color-text-secondary); } .charts-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 20px; margin-bottom: 30px; } .chart-container { background: var(–color-surface); border: 1px solid var(–color-border); border-radius: 10px; padding: 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .chart-container h2 { font-size: 18px; font-weight: 600; margin-bottom: 20px; color: var(–color-text); border-bottom: 2px solid var(–color-primary); padding-bottom: 10px; } .chart-wrapper { position: relative; height: 300px; margin-bottom: 15px; } .wordcloud-container { background: var(–color-surface); border: 1px solid var(–color-border); border-radius: 10px; padding: 30px 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); grid-column: 1 / -1; } .wordcloud-container h2 { font-size: 18px; font-weight: 600; margin-bottom: 20px; color: var(–color-text); border-bottom: 2px solid var(–color-primary); padding-bottom: 10px; } .wordcloud { display: flex; flex-wrap: wrap; gap: 15px; justify-content: center; align-items: center; } .word { padding: 8px 16px; background: var(–color-bg-1); border-radius: 20px; color: var(–color-text); font-weight: 500; border: 1px solid var(–color-border); transition: all 0.3s ease; cursor: pointer; } .word:hover { background: var(–color-primary); color: white; transform: scale(1.1); } .legend { display: flex; gap: 20px; margin-top: 15px; font-size: 12px; flex-wrap: wrap; } .legend-item { display: flex; align-items: center; gap: 6px; } .legend-color { width: 12px; height: 12px; border-radius: 3px; } .explanation { background: var(–color-bg-3); border-left: 4px solid var(–color-success); border-radius: 6px; padding: 15px; margin-bottom: 20px; font-size: 14px; color: var(–color-text); } .explanation h3 { font-size: 14px; font-weight: 600; margin-bottom: 8px; color: var(–color-text); } .explanation p { margin: 0; } .methodology-section { background: var(–color-surface); border: 1px solid var(–color-border); border-radius: 10px; padding: 20px; margin-top: 30px; } .methodology-section h2 { font-size: 18px; font-weight: 600; margin-bottom: 15px; color: var(–color-text); } .methodology-section ol { margin-left: 20px; color: var(–color-text-secondary); } .methodology-section li { margin-bottom: 10px; line-height: 1.6; } .sentiment-color-positive { color: var(–color-success); font-weight: 600; } .sentiment-color-negative { color: var(–color-error); font-weight: 600; } .sentiment-color-neutral { color: var(–color-warning); font-weight: 600; } @media (max-width: 768px) { .charts-grid { grid-template-columns: 1fr; } header h1 { font-size: 24px; } .kpi-section { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); } } https://cdn.jsdelivr.net/npm/chart.js

📊 MBG Libur Sekolah – Sentiment Analysis

Analisis sentimen netizen terkait kebijakan Makan Bergizi Gratis saat libur sekolah dari data Threads

Total Komentar
421
dari 369 pengguna unik
Sentimen Negatif
300
71.3% dari total
Sentimen Netral
84
20.0% dari total
Sentimen Positif
37
8.8% dari total
Sesuai Konteks
418
99.3% relevan
Tidak Sesuai Konteks
3
0.7% tidak relevan

📌 Penjelasan Analisis

Data ini menganalisis sentimen netizen terhadap kebijakan MBG yang tetap disalurkan saat libur sekolah. Mayoritas komentar (71.3%) bersifat negatif, mencerminkan kekhawatiran publik tentang efisiensi anggaran dan ketepatan kebijakan. Hanya 8.8% komentar yang positif, menunjukkan dukungan terbatas terhadap kebijakan ini.

📈 Distribusi Sentimen

Negatif (300)
Netral (84)
Positif (37)

🎯 Kesesuaian Konteks

Sesuai (418)
Tidak Sesuai (3)

🔀 Irisan Sentiment × Konteks

🎨 Persentase Sentimen

⏰ Distribusi Waktu Posting Thread

📅 Sentimen Berdasarkan Waktu Posting

💬 Rata-rata Likes Berdasarkan Waktu Posting

☁️ Word Cloud – Kata Kunci Utama

MBG
Libur
Sekolah
Tetap
Anak
Jalan
Bencana
Program
Masih
Makan
Dana
Anggaran
Korupsi
Selama
Aceh

🔍 Metodologi Analisis

  1. Pengumpulan Data: Ekstraksi 421 komentar dari thread Threads dengan pencarian “mbg libur”. Data mencakup username, waktu, text, dan engagement metrics.
  2. Preprocessing & Kombinasi Teks: Menggabungkan 4 kolom teks (text1-text4) menjadi satu komentar lengkap untuk analisis holistik. Normalisasi teks dilakukan untuk memastikan konsistensi.
  3. Sentiment Analysis (Lexicon-Based):
    • Positif: Kata-kata seperti “baik”, “bagus”, “setuju”, “bermanfaat”, “berhasil”, “enak”, “bergizi”
    • Negatif: Kata-kata seperti “korupsi”, “tidak masuk akal”, “aneh”, “ribet”, “merugikan”, “korupsi”, “serakah”, “tidak transparan”
    • Netral: Ketika tidak ada indikator sentimen yang jelas atau seimbang
  4. Context Analysis: Menentukan apakah komentar relevan dengan topik MBG libur sekolah. Minimal 1 kata kunci dari domain MBG harus ada (mbg, libur, sekolah, gizi, dana, korupsi, bencana, dll).
  5. Sentiment-Context Matrix: Membuat irisan antara sentiment (Positif/Negatif/Netral) × Context (Sesuai/Tidak Sesuai) untuk analisis mendalam.
  6. Word Frequency Analysis: Ekstraksi 30 kata paling sering muncul setelah menghilangkan stopwords bahasa Indonesia dan kata-kata UI (More, Like, Reply, Share).
  7. Visualisasi: Menggunakan Chart.js untuk pie charts, bar charts, dan word cloud untuk presentasi insight yang mudah dipahami.

📊 Insight Utama:

  • Publik sangat kritis terhadap kebijakan MBG saat libur (71.3% negatif)
  • Isu utama: efisiensi anggaran, potensi korupsi, dan alokasi ke bencana Sumatra
  • Hampir semua komentar relevan dengan topik (99.3%), menunjukkan diskusi yang fokus
  • Hanya 8.8% dukungan positif, sebagian besar dari pengelola dapur/penerima manfaat langsung
  • Pola Waktu: Mayoritas komentar pada 3-5 hari lalu (159 komentar), dengan engagement tertinggi pada 1-3 hari lalu (rata-rata 78.9 likes)
  • Tren Sentimen: Sentimen negatif konsisten mendominasi di semua periode waktu (36-57 per periode)
  • Engagement Volatility: Engagement tertinggi pada thread yang berusia 1-3 hari, menunjukkan puncak viral pada periode tersebut
// Color palette const colors = { negative: ‘#C0152F’, neutral: ‘#A84B2F’, positive: ‘#208D81’, secondary: ‘#1D7480’, border: ‘rgba(94, 82, 64, 0.2)’ }; // Chart 1: Sentiment Distribution (Doughnut) const sentimentCtx = document.getElementById(‘sentimentChart’).getContext(‘2d’); new Chart(sentimentCtx, { type: ‘doughnut’, data: { labels: [‘Negatif’, ‘Netral’, ‘Positif’], datasets: [{ data: [300, 84, 37], backgroundColor: [colors.negative, colors.neutral, colors.positive], borderColor: ‘#fff’, borderWidth: 2, spacing: 10 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: ‘bottom’, labels: { padding: 20, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } }); // Chart 2: Context Distribution (Doughnut) const contextCtx = document.getElementById(‘contextChart’).getContext(‘2d’); new Chart(contextCtx, { type: ‘doughnut’, data: { labels: [‘Sesuai Konteks’, ‘Tidak Sesuai Konteks’], datasets: [{ data: [418, 3], backgroundColor: [colors.positive, colors.negative], borderColor: ‘#fff’, borderWidth: 2, spacing: 10 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: ‘bottom’, labels: { padding: 20, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } }); // Chart 3: Sentiment-Context Matrix (Stacked Bar) const sentimentContextCtx = document.getElementById(‘sentimentContextChart’).getContext(‘2d’); new Chart(sentimentContextCtx, { type: ‘bar’, data: { labels: [‘Sesuai’, ‘Tidak Sesuai’], datasets: [ { label: ‘Negatif’, data: [299, 1], backgroundColor: colors.negative }, { label: ‘Netral’, data: [82, 2], backgroundColor: colors.neutral }, { label: ‘Positif’, data: [37, 0], backgroundColor: colors.positive } ] }, options: { responsive: true, maintainAspectRatio: false, indexAxis: ‘y’, scales: { x: { stacked: true, ticks: { color: ‘#627078’, font: { size: 11 } }, grid: { color: ‘rgba(94, 82, 64, 0.1)’ } }, y: { stacked: true, ticks: { color: ‘#627078’, font: { size: 11 } } } }, plugins: { legend: { position: ‘top’, labels: { padding: 15, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } }); // Chart 4: Sentiment Pie const sentimentPieCtx = document.getElementById(‘sentimentPieChart’).getContext(‘2d’); new Chart(sentimentPieCtx, { type: ‘pie’, data: { labels: [‘Negatif\n(71.3%)’, ‘Netral\n(20.0%)’, ‘Positif\n(8.8%)’], datasets: [{ data: [71.3, 20.0, 8.8], backgroundColor: [colors.negative, colors.neutral, colors.positive], borderColor: ‘#fff’, borderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: ‘bottom’, labels: { padding: 20, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } }); // Chart 5: Time Distribution (Bar) const timeDistributionCtx = document.getElementById(‘timeDistributionChart’).getContext(‘2d’); new Chart(timeDistributionCtx, { type: ‘bar’, data: { labels: [‘Last Hour’, ‘1-6 Hours’, ‘6-24 Hours’, ‘1-3 Days’, ‘3-5 Days’, ‘5+ Days’], datasets: [{ label: ‘Jumlah Komentar’, data: [13, 17, 36, 74, 159, 117], backgroundColor: colors.positive, borderColor: colors.secondary, borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { color: ‘#627078’, font: { size: 11 } }, grid: { color: ‘rgba(94, 82, 64, 0.1)’ } }, x: { ticks: { color: ‘#627078’, font: { size: 10 } }, grid: { display: false } } }, plugins: { legend: { display: false } } } }); // Chart 6: Sentiment by Time (Stacked Bar) const sentimentByTimeCtx = document.getElementById(‘sentimentByTimeChart’).getContext(‘2d’); new Chart(sentimentByTimeCtx, { type: ‘bar’, data: { labels: [‘Last Hour’, ‘1-6 Hours’, ‘6-24 Hours’, ‘1-3 Days’, ‘3-5 Days’, ‘5+ Days’], datasets: [ { label: ‘Negatif’, data: [8, 2, 10, 20, 57, 36], backgroundColor: colors.negative }, { label: ‘Netral’, data: [2, 8, 15, 31, 70, 61], backgroundColor: colors.neutral }, { label: ‘Positif’, data: [3, 7, 11, 23, 32, 20], backgroundColor: colors.positive } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { stacked: true, ticks: { color: ‘#627078’, font: { size: 10 } }, grid: { display: false } }, y: { stacked: true, ticks: { color: ‘#627078’, font: { size: 11 } }, grid: { color: ‘rgba(94, 82, 64, 0.1)’ } } }, plugins: { legend: { position: ‘top’, labels: { padding: 15, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } }); // Chart 7: Engagement by Time (Line) const engagementByTimeCtx = document.getElementById(‘engagementByTimeChart’).getContext(‘2d’); new Chart(engagementByTimeCtx, { type: ‘line’, data: { labels: [‘Last Hour’, ‘1-6 Hours’, ‘6-24 Hours’, ‘1-3 Days’, ‘3-5 Days’, ‘5+ Days’], datasets: [{ label: ‘Rata-rata Likes’, data: [1.3, 11.3, 4.5, 78.9, 21.2, 28.7], borderColor: colors.positive, backgroundColor: ‘rgba(32, 141, 129, 0.05)’, borderWidth: 3, tension: 0.4, pointRadius: 5, pointBackgroundColor: colors.positive, pointBorderColor: ‘#fff’, pointBorderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { color: ‘#627078’, font: { size: 11 } }, grid: { color: ‘rgba(94, 82, 64, 0.1)’ } }, x: { ticks: { color: ‘#627078’, font: { size: 10 } }, grid: { color: ‘rgba(94, 82, 64, 0.1)’ } } }, plugins: { legend: { display: true, labels: { padding: 15, font: { size: 12, weight: ‘500’ }, color: ‘#134252’ } } } } });

waiting for you...