Skip to content

Commit d8d41e5

Browse files
committed
add data visualization in scatter plot
1 parent d7fa4ca commit d8d41e5

File tree

2 files changed

+90
-11
lines changed

2 files changed

+90
-11
lines changed

src/web/index.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h1 class="font-bold text-2xl text-center flex items-baseline justify-center spa
5050
</section>
5151

5252

53-
<section id="model-selection-section" class="hidden">
53+
<section id="model-selection-section" class="hidden pb-20">
5454
<form id="model-form" class="space-y-2 mt-5">
5555
<label for="model-selection" class="text-indigo-600 text-sm font-medium">
5656
Select Model
@@ -98,8 +98,9 @@ <h1 class="font-bold text-2xl text-center flex items-baseline justify-center spa
9898

9999

100100

101-
<section id="model-visualization" class="hidden">
102-
<h1>Visualization</h1>
101+
<section id="model-visualization" class="hidden pb-20">
102+
<h3 class="text-indigo-600 font-bold text-center">Visualization</h3>
103+
<canvas id="chart" width="500" height="300"></canvas>
103104
</section>
104105

105106

@@ -126,6 +127,7 @@ <h1>Testing</h1>
126127
</nav>
127128
</main>
128129

130+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
129131
<script src="script.js"></script>
130132
</body>
131133

src/web/script.js

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,25 @@ const equationResult = document.getElementById('equation-result')
2929
const btnCopy = document.getElementById('btn-copy')
3030

3131

32+
33+
// Global data
3234
/**
3335
* Linear equation result based on data processing
3436
*
3537
* @param {number} x - a feature data
3638
* @returns {number} a label/target/`y` value result
3739
*/
3840
let equation = null
39-
40-
// Global data
4141
let currentSection = 0
4242
const sectionsArray = [
4343
'Input data',
44-
'Model selection',
44+
'Model selection',
4545
'Model visualization',
4646
'Model testing'
4747
]
4848
let fileData = null
4949

50+
let chartInstance = null
5051

5152

5253
btnBack.addEventListener('click', () => {
@@ -117,17 +118,21 @@ dataForm.addEventListener('submit', function(e) {
117118
.map(row => row.split(','))
118119
.map((val, index, array) => {
119120
if (index == 0) return
121+
122+
if (val.every(cell => cell.trim() === "")) return
120123

121124
const obj = {}
122125

123126
for (let i = 0; i < array[0].length; i++) {
124-
obj[array[0][i]] = val[i]
127+
if (val[i] !== undefined && val[i] !== null) {
128+
obj[array[0][i]] = val[i].trim()
129+
}
125130
}
126131
return obj
127132
})
133+
.filter(obj => obj)
128134
fileData.shift()
129135

130-
131136
let previewedTable = `
132137
<table class="min-w-full bg-white border border-gray-200 rounded-lg">
133138
<thead>
@@ -155,6 +160,9 @@ dataForm.addEventListener('submit', function(e) {
155160

156161
previewData.innerHTML = previewedTable
157162

163+
featureSelect.innerHTML = ''
164+
labelSelect.innerHTML = ''
165+
featureCheckbox.innerHTML = ''
158166
for (const key in fileData[0]) {
159167
featureSelect.innerHTML += `<option value="${key}">${key}</option>`
160168
labelSelect.innerHTML += `<option value="${key}">${key}</option>`
@@ -251,9 +259,7 @@ modelForm.addEventListener('submit', function(e) {
251259
const feature = formData.get('features') || formData.get('feature')
252260

253261
switch (model) {
254-
case 'single':
255-
singleFeatureProcess(feature, label)
256-
break
262+
case 'single': singleFeatureProcess(feature, label); break;
257263
case 'multi': multiFeatureProcess(feature, label); break;
258264
default: alert('Invalid model type!'); break;
259265
}
@@ -288,6 +294,8 @@ function singleFeatureProcess(feature, label) {
288294
equationResultContainer.classList.remove('hidden')
289295
equationResultContainer.classList.add('flex')
290296
equationResult.textContent = `y = ${a} + ${b}x`
297+
298+
visualize(feature, label)
291299
}
292300

293301

@@ -314,3 +322,72 @@ btnCopy.addEventListener('click', () => {
314322
alert('Failed to copy text!')
315323
})
316324
})
325+
326+
327+
//////////////////////////////////////////////////
328+
//// THIRD SECTION SCRIPT
329+
//////////////////////////////////////////////////
330+
331+
function visualize(feature, label) {
332+
if (chartInstance) chartInstance.destroy()
333+
334+
const chart = document.getElementById('chart')
335+
const ctx = chart.getContext('2d')
336+
337+
338+
const featureArray = fileData.map(val => val[feature])
339+
const maxFeatureSampleData = Math.max(...featureArray)
340+
const minFeatureSampleData = Math.min(...featureArray)
341+
console.log(maxFeatureSampleData)
342+
const data = {
343+
datasets: [{
344+
label: 'Scatter Dataset',
345+
data: fileData.map(val => {
346+
return {
347+
x: val[feature],
348+
y: val[label]
349+
}
350+
}),
351+
backgroundColor: 'rgba(0, 123, 255, 0.6)',
352+
borderColor: 'rgba(0, 123, 255, 1)',
353+
borderWidth: 1
354+
},
355+
{
356+
label: 'Line y = 2x + 10',
357+
data: [
358+
{ x: minFeatureSampleData, y: equation(minFeatureSampleData) },
359+
{ x: maxFeatureSampleData, y: equation(maxFeatureSampleData) }
360+
],
361+
type: 'line',
362+
borderColor: 'rgba(255, 99, 132, 1)',
363+
borderWidth: 2,
364+
fill: false,
365+
tension: 0
366+
}]
367+
}
368+
369+
const config = {
370+
type: 'scatter',
371+
data: data,
372+
options: {
373+
responsive: true,
374+
scales: {
375+
x: {
376+
type: 'linear',
377+
position: 'bottom',
378+
ticks: {
379+
beginAtZero: true
380+
}
381+
},
382+
y: {
383+
ticks: {
384+
beginAtZero: true
385+
}
386+
}
387+
}
388+
}
389+
}
390+
391+
chartInstance = new Chart(ctx, config)
392+
}
393+

0 commit comments

Comments
 (0)