Djacon commited on
Commit
2498dd5
Β·
1 Parent(s): 8a15ecf

Update analytics

Browse files
files/js/analytics.js CHANGED
@@ -1,3 +1,13 @@
 
 
 
 
 
 
 
 
 
 
1
  function prettify(num) {
2
  num = +num;
3
  let mark = '';
@@ -21,6 +31,7 @@ function prettify(num) {
21
  return num + mark;
22
  }
23
 
 
24
  function median(arr) {
25
  arr.sort((a, b) => a - b);
26
 
@@ -34,6 +45,7 @@ function median(arr) {
34
  return +((mid1 + mid2) / 2).toFixed(2);
35
  }
36
 
 
37
  function get_info(arr) {
38
  let [min, max] = d3.extent(arr);
39
  let avg = +(arr.reduce((a, b) => a + b) / arr.length).toFixed(2);
@@ -43,7 +55,15 @@ function get_info(arr) {
43
  }
44
 
45
 
46
- function plot_hist(col_name, chart_id) {
 
 
 
 
 
 
 
 
47
  let column = cache_df.dataset[chart_id];
48
 
49
  let min = column.metadata.min, max = column.metadata.max;
@@ -51,15 +71,16 @@ function plot_hist(col_name, chart_id) {
51
  let valid_count = column.metadata.total_values - nan_count;
52
  let nan_percentage = nan_count / column.metadata.total_values * 100;
53
  let info = [
54
- ['DataType', 'Numerical'],
55
  ['Mean', prettify(column.metadata.mean)],
56
  ['Median', prettify(column.metadata.median)],
57
  ['Std. Deviation', prettify(column.metadata.var)],
 
58
  ['Missing Values', `${nan_count} (${+(nan_percentage).toFixed(1)}%)`],
59
  ['Valid Values', `${valid_count} (${+(100 - nan_percentage).toFixed(1)}%)`],
60
  ]
61
 
62
- addChart(chart_id, col_name, info);
63
 
64
  var width = document.getElementById(`chart-${chart_id}`).clientWidth;
65
  var height = 300;
@@ -123,6 +144,7 @@ function plot_hist(col_name, chart_id) {
123
  });
124
  }
125
 
 
126
  function mode(data) {
127
  let modeLabel = 'Not Found';
128
  let maxCount = 0;
@@ -151,7 +173,7 @@ function plot_pie(col_name, chart_id) {
151
  ['Valid Values', `${valid_count} (${+(100 - nan_percentage).toFixed(1)}%)`],
152
  ];
153
 
154
- addChart(chart_id, col_name, info);
155
 
156
  var width = document.getElementById(`chart-${chart_id}`).clientWidth;
157
  var height = 300;
@@ -181,14 +203,6 @@ function plot_pie(col_name, chart_id) {
181
  .attr("fill", (_, i)=> color(i))
182
  .attr("d", arc)
183
 
184
- // svg.selectAll("label")
185
- // .data(pie(column))
186
- // .enter()
187
- // .append("text")
188
- // .attr("transform", d => `translate(${arc.centroid(d)})`)
189
- // .attr("text-anchor", "middle")
190
- // .text(d => d.data[0]);
191
-
192
  arcs.on("mouseover", (_, d) => {
193
  svg.append("text")
194
  .text(`${d.data[0]}: ${+(d.data[1] / valid_count * 100).toFixed(1)}%`)
@@ -224,11 +238,11 @@ function _handle_column(data, col) {
224
  for (let row of data) {
225
  let value = row[col];
226
  if (value !== '') {
227
- if (type != 'object') {
228
  if (_is_number(value)) {
229
  type = 'num';
230
  } else {
231
- type = 'object';
232
  }
233
  }
234
 
@@ -248,18 +262,17 @@ function _handle_column(data, col) {
248
  }
249
  }
250
 
251
- type = maybe_cats ? 'cat' : type == 'num' ? type : 'object';
252
- // console.log(col, type);
253
 
254
  let nan_count = data.length - cols.length;
255
- if (type == 'cat') {
256
  cats = Object.entries(cats);
257
  let [mode_col, mode_count] = mode(cats);
258
  let col_data = {type, col, data: cats,
259
  metadata: {nan_count, total_values: data.length,
260
  unique: cats_count, mode_info: `${mode_col} (${+(mode_count / cols.length * 100).toFixed(1)}%)`}}
261
  return [true, col_data];
262
- } else if (type == 'num') {
263
  cols = new Float32Array(cols);
264
  let [min, max, mean_col, median_col, var_col] = get_info(cols);
265
  let col_data = {type, col, data: cols,
@@ -267,6 +280,15 @@ function _handle_column(data, col) {
267
  min: min, max: max, mean: mean_col, median: median_col, var: var_col}}
268
  return [true, col_data];
269
  }
 
 
 
 
 
 
 
 
 
270
  return [false, {}];
271
  }
272
 
@@ -335,8 +357,8 @@ function _plot(col_id) {
335
  values = cache_df.dataset[col_id];
336
  if (values.type == 'cat') {
337
  plot_pie(values.col, col_id);
338
- } else if (values.type == 'num') {
339
- plot_hist(values.col, col_id);
340
  }
341
  }
342
 
@@ -354,7 +376,7 @@ function _toggle_column(col_id, is_open=true) {
354
  }
355
  }
356
 
357
- function addChart(chartID, name, info) {
358
  info_div = [];
359
  for (let item of info) {
360
  let v = `<p class="mt-1 text-sm text-gray-500 truncate sm:w-auto"><b>${item[0]}:</b> ${item[1]}</p>`
@@ -366,7 +388,12 @@ function addChart(chartID, name, info) {
366
  newChartDiv.className = 'cols dark-block p-4 mt-4 w-full overflow-hidden bg-white rounded-lg';
367
  newChartDiv.innerHTML = `
368
  <div class="dark-block w-full p-4 bg-white rounded-lg xl:p-6">
369
- <h1 class="text-lg font-medium text-gray-700 capitalize sm:text-xl md:text-2xl">${name}</h1>
 
 
 
 
 
370
  <div class="grid gap-12 mt-8 sm:grid-cols-2">
371
  <div id="tooltip-${chartID}" class="rounded-lg" style="position: absolute; display: none; background-color: black; color: white; border: 1px solid black; padding: 5px; z-index: 1;"></div>
372
  <div id="chart-${chartID}" class="flex items-center capitalize no-invert">
@@ -374,7 +401,6 @@ function addChart(chartID, name, info) {
374
  <div class="flow-root mt-6">
375
  <ul>
376
  <li>
377
- <span class="absolute top-4 left-4 rtl:right-4 rtl:left-auto -ml-px h-full w-0.5 bg-gray-200" aria-hidden="true"></span>
378
  <div class="relative flex">
379
  <span class="flex items-center justify-center w-8 h-8">
380
  <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-indigo-600 no-invert" viewBox="0 0 20 20" fill="currentColor">
@@ -398,22 +424,34 @@ function addChart(chartID, name, info) {
398
  var lastWidth = window.innerWidth;
399
  document.getElementById("submit").addEventListener("click", render);
400
  window.addEventListener("resize", () => {
 
401
  if (Math.abs(lastWidth - window.innerWidth) > 25) {
402
  render();
403
  lastWidth = window.innerWidth;
404
  }
405
  });
406
 
 
407
  fileInput.addEventListener('change', function() {
 
 
 
 
 
 
 
408
  cache_df.is_empty = true;
409
  cache_df.dataset = [];
410
  });
411
 
412
 
413
  function render() {
 
414
  if (fileInput.files.length > 0) {
415
  if (!fileInput.files[0].name.endsWith('.csv')) {
416
- console.warn('Invalid Format!');
 
 
417
  return;
418
  }
419
 
@@ -440,10 +478,13 @@ function render() {
440
  };
441
  reader.readAsText(selectedFile);
442
  } else {
443
- console.warn('There is no file!');
 
 
444
  }
445
  }
446
 
 
447
  function _comeback_options() {
448
  dropdownSearch.style.display = 'none';
449
  let ids = new Set();
@@ -468,6 +509,30 @@ function _apply_options() {
468
  }
469
  }
470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  const showDropdownButton = document.getElementById('showDropdown');
472
  const dropdownSearch = document.getElementById('dropdownSearch');
473
  const ulColumns = document.getElementById('ul-columns');
 
1
+ // Info Output Sections
2
+ const sumError = document.getElementById('sum-err');
3
+ const sumInfo = document.getElementById('sum-info');
4
+
5
+ // SVGs for columns
6
+ const digitSVG = `<svg width="24" height="24" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--twemoji" preserveAspectRatio="xMidYMid meet" fill="none"><g id="SVGRepo_bgCarrier" stroke-width="0"/><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/><g id="SVGRepo_iconCarrier"><path fill="currentColor" d="M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z"/><path d="M9.613 6.096H8.492c-.912 0-1.292-.665-1.292-1.311c0-.665.475-1.311 1.292-1.311h2.698c.817 0 1.273.589 1.273 1.349v10.81c0 .95-.608 1.481-1.425 1.481c-.817 0-1.425-.532-1.425-1.481V6.096zm5.129 16.627c0 1.196-.513 2.241-1.558 2.906c1.368.627 2.318 1.9 2.318 3.4c0 2.28-2.09 4.198-4.788 4.198c-2.812 0-4.559-2.07-4.559-3.571c0-.74.779-1.272 1.463-1.272c1.291 0 .988 2.223 3.134 2.223c.988 0 1.786-.76 1.786-1.767c0-2.66-3.23-.703-3.23-2.944c0-1.995 2.698-.646 2.698-2.755c0-.722-.513-1.273-1.368-1.273c-1.805 0-1.558 1.862-2.85 1.862c-.779 0-1.235-.703-1.235-1.406c0-1.481 2.033-3.077 4.142-3.077c2.736-.001 4.047 1.993 4.047 3.476zm13.373-8.231c.836 0 1.48.38 1.48 1.254S28.951 17 28.228 17h-6.346c-.835 0-1.48-.38-1.48-1.254c0-.399.246-.741.437-.969c1.577-1.881 3.286-3.59 4.729-5.68c.343-.494.666-1.083.666-1.767c0-.779-.59-1.463-1.368-1.463c-2.185 0-1.14 3.078-2.964 3.078c-.912 0-1.387-.646-1.387-1.387c0-2.394 2.128-4.312 4.465-4.312c2.336 0 4.217 1.539 4.217 3.951c0 2.641-2.944 5.262-4.559 7.295h3.477zm-6.934 15.526c-.931 0-1.33-.627-1.33-1.121c0-.418.152-.646.267-.836l4.255-7.713c.418-.76.95-1.102 1.938-1.102c1.102 0 2.184.703 2.184 2.432v5.832h.323c.741 0 1.33.494 1.33 1.254s-.589 1.254-1.33 1.254h-.323v1.614c0 1.007-.398 1.483-1.367 1.483s-1.368-.476-1.368-1.483v-1.614h-4.579zm4.578-7.808h-.038l-2.564 5.3h2.603v-5.3z" fill="#FFF"/></g></svg>`
7
+ const labelSVG = `<svg fill="currentColor" height="24" width="24" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 295 295" xml:space="preserve"><path d="M290.156,23.89c-0.482-10.311-8.733-18.562-19.044-19.044L168.005,0.023c-5.62-0.272-11.097,1.855-15.077,5.836 L5.858,152.93C2.108,156.681,0,161.767,0,167.072s2.107,10.392,5.858,14.143l107.929,107.928c3.904,3.905,9.023,5.857,14.142,5.857 c5.118,0,10.237-1.953,14.143-5.857l147.069-147.069c3.98-3.98,6.1-9.454,5.837-15.077L290.156,23.89z M252.481,76.087 c-9.269,9.269-24.298,9.269-33.567,0s-9.269-24.298,0-33.567s24.298-9.269,33.567,0S261.751,66.817,252.481,76.087z"/></svg>`
8
+ const sentsSVG = `<svg width="24" height="24" viewBox="-3 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"><g id="Icon-Set-Filled" sketch:type="MSLayerGroup" transform="translate(-105.000000, -101.000000)" fill="currentColor"><path d="M125,109 C123.896,109 123,108.104 123,107 L123,103 L129,109 L125,109 L125,109 Z M124,119 L112,119 C111.448,119 111,118.553 111,118 C111,117.448 111.448,117 112,117 L124,117 C124.552,117 125,117.448 125,118 C125,118.553 124.552,119 124,119 L124,119 Z M124,125 L112,125 C111.448,125 111,124.553 111,124 C111,123.447 111.448,123 112,123 L124,123 C124.552,123 125,123.447 125,124 C125,124.553 124.552,125 124,125 L124,125 Z M123,101.028 C122.872,101.028 109,101 109,101 C106.791,101 105,102.791 105,105 L105,129 C105,131.209 106.791,133 109,133 L127,133 C129.209,133 131,131.209 131,129 L131,109 L123,101.028 L123,101.028 Z" id="text-document" sketch:type="MSShapeGroup"></path></g></g></svg>`
9
+
10
+
11
  function prettify(num) {
12
  num = +num;
13
  let mark = '';
 
31
  return num + mark;
32
  }
33
 
34
+
35
  function median(arr) {
36
  arr.sort((a, b) => a - b);
37
 
 
45
  return +((mid1 + mid2) / 2).toFixed(2);
46
  }
47
 
48
+
49
  function get_info(arr) {
50
  let [min, max] = d3.extent(arr);
51
  let avg = +(arr.reduce((a, b) => a + b) / arr.length).toFixed(2);
 
55
  }
56
 
57
 
58
+ function get_lengths_array(arr) {
59
+ for (let i = 0; i < arr.length; i++) {
60
+ arr[i] = arr[i].split(' ').length;
61
+ }
62
+ return new Int16Array(arr);
63
+ }
64
+
65
+
66
+ function plot_hist(col_name, chart_id, col_type='num') {
67
  let column = cache_df.dataset[chart_id];
68
 
69
  let min = column.metadata.min, max = column.metadata.max;
 
71
  let valid_count = column.metadata.total_values - nan_count;
72
  let nan_percentage = nan_count / column.metadata.total_values * 100;
73
  let info = [
74
+ ['DataType', col_type == 'num' ? 'Numerical': 'Text | Lengths'],
75
  ['Mean', prettify(column.metadata.mean)],
76
  ['Median', prettify(column.metadata.median)],
77
  ['Std. Deviation', prettify(column.metadata.var)],
78
+ ['Conf. Interval', `[${prettify(Math.max(column.metadata.mean-3*column.metadata.var, min))}; ${prettify(Math.min(column.metadata.mean+3*column.metadata.var, max))}]`],
79
  ['Missing Values', `${nan_count} (${+(nan_percentage).toFixed(1)}%)`],
80
  ['Valid Values', `${valid_count} (${+(100 - nan_percentage).toFixed(1)}%)`],
81
  ]
82
 
83
+ addChart(chart_id, col_name, info, extra_symb=(col_type == 'num' ? digitSVG: sentsSVG) );
84
 
85
  var width = document.getElementById(`chart-${chart_id}`).clientWidth;
86
  var height = 300;
 
144
  });
145
  }
146
 
147
+
148
  function mode(data) {
149
  let modeLabel = 'Not Found';
150
  let maxCount = 0;
 
173
  ['Valid Values', `${valid_count} (${+(100 - nan_percentage).toFixed(1)}%)`],
174
  ];
175
 
176
+ addChart(chart_id, col_name, info, extra_symb=labelSVG);
177
 
178
  var width = document.getElementById(`chart-${chart_id}`).clientWidth;
179
  var height = 300;
 
203
  .attr("fill", (_, i)=> color(i))
204
  .attr("d", arc)
205
 
 
 
 
 
 
 
 
 
206
  arcs.on("mouseover", (_, d) => {
207
  svg.append("text")
208
  .text(`${d.data[0]}: ${+(d.data[1] / valid_count * 100).toFixed(1)}%`)
 
238
  for (let row of data) {
239
  let value = row[col];
240
  if (value !== '') {
241
+ if (type != 'string') {
242
  if (_is_number(value)) {
243
  type = 'num';
244
  } else {
245
+ type = 'str';
246
  }
247
  }
248
 
 
262
  }
263
  }
264
 
265
+ type = maybe_cats ? 'cat' : type == 'num' ? type : 'str';
 
266
 
267
  let nan_count = data.length - cols.length;
268
+ if (type === 'cat') {
269
  cats = Object.entries(cats);
270
  let [mode_col, mode_count] = mode(cats);
271
  let col_data = {type, col, data: cats,
272
  metadata: {nan_count, total_values: data.length,
273
  unique: cats_count, mode_info: `${mode_col} (${+(mode_count / cols.length * 100).toFixed(1)}%)`}}
274
  return [true, col_data];
275
+ } else if (type === 'num') {
276
  cols = new Float32Array(cols);
277
  let [min, max, mean_col, median_col, var_col] = get_info(cols);
278
  let col_data = {type, col, data: cols,
 
280
  min: min, max: max, mean: mean_col, median: median_col, var: var_col}}
281
  return [true, col_data];
282
  }
283
+
284
+ cols = get_lengths_array(cols);
285
+ let [min, max, mean_col, median_col, var_col] = get_info(cols);
286
+ if (min !== max) {
287
+ let col_data = {type, col, data: cols,
288
+ metadata: {nan_count, total_values: data.length,
289
+ min: min, max: max, mean: mean_col, median: median_col, var: var_col}}
290
+ return [true, col_data];
291
+ }
292
  return [false, {}];
293
  }
294
 
 
357
  values = cache_df.dataset[col_id];
358
  if (values.type == 'cat') {
359
  plot_pie(values.col, col_id);
360
+ } else if (['num', 'str'].includes(values.type)) {
361
+ plot_hist(values.col, col_id, values.type);
362
  }
363
  }
364
 
 
376
  }
377
  }
378
 
379
+ function addChart(chartID, name, info, extra_symb='⬛') {
380
  info_div = [];
381
  for (let item of info) {
382
  let v = `<p class="mt-1 text-sm text-gray-500 truncate sm:w-auto"><b>${item[0]}:</b> ${item[1]}</p>`
 
388
  newChartDiv.className = 'cols dark-block p-4 mt-4 w-full overflow-hidden bg-white rounded-lg';
389
  newChartDiv.innerHTML = `
390
  <div class="dark-block w-full p-4 bg-white rounded-lg xl:p-6">
391
+ <h1 class="text-lg font-medium text-gray-700 capitalize sm:text-xl md:text-2xl flex items-center">
392
+ <div style='margin-right: 0.5rem;'>
393
+ ${extra_symb}
394
+ </div>
395
+ ${name}
396
+ </h1>
397
  <div class="grid gap-12 mt-8 sm:grid-cols-2">
398
  <div id="tooltip-${chartID}" class="rounded-lg" style="position: absolute; display: none; background-color: black; color: white; border: 1px solid black; padding: 5px; z-index: 1;"></div>
399
  <div id="chart-${chartID}" class="flex items-center capitalize no-invert">
 
401
  <div class="flow-root mt-6">
402
  <ul>
403
  <li>
 
404
  <div class="relative flex">
405
  <span class="flex items-center justify-center w-8 h-8">
406
  <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-indigo-600 no-invert" viewBox="0 0 20 20" fill="currentColor">
 
424
  var lastWidth = window.innerWidth;
425
  document.getElementById("submit").addEventListener("click", render);
426
  window.addEventListener("resize", () => {
427
+ if (cache_df.is_empty) return;
428
  if (Math.abs(lastWidth - window.innerWidth) > 25) {
429
  render();
430
  lastWidth = window.innerWidth;
431
  }
432
  });
433
 
434
+
435
  fileInput.addEventListener('change', function() {
436
+ sumError.classList.add('hidden');
437
+ if (fileInput.files.length > 0) {
438
+ sumInfo.innerText = `File "${fileInput.files[0].name}" was uploaded`;
439
+ sumInfo.classList.remove('hidden');
440
+ } else {
441
+ sumInfo.classList.add('hidden');
442
+ }
443
  cache_df.is_empty = true;
444
  cache_df.dataset = [];
445
  });
446
 
447
 
448
  function render() {
449
+ sumError.classList.add('hidden');
450
  if (fileInput.files.length > 0) {
451
  if (!fileInput.files[0].name.endsWith('.csv')) {
452
+ sumError.innerText = 'Not supported type (Only `.csv`)';
453
+ sumInfo.classList.add('hidden');
454
+ sumError.classList.remove('hidden');
455
  return;
456
  }
457
 
 
478
  };
479
  reader.readAsText(selectedFile);
480
  } else {
481
+ sumError.innerText = 'There is no file!';
482
+ sumInfo.classList.add('hidden');
483
+ sumError.classList.remove('hidden');
484
  }
485
  }
486
 
487
+
488
  function _comeback_options() {
489
  dropdownSearch.style.display = 'none';
490
  let ids = new Set();
 
509
  }
510
  }
511
 
512
+
513
+ function allowDrop(event) {
514
+ event.preventDefault();
515
+ // console.log('inside');
516
+ }
517
+
518
+ function drop(event) {
519
+ event.preventDefault();
520
+ sumError.classList.add('hidden');
521
+ const files = event.dataTransfer.files;
522
+ if (files.length > 0) {
523
+ const newDT = new DataTransfer();
524
+ newDT.items.add(files[0]);
525
+ fileInput.files = newDT.files;
526
+
527
+ sumInfo.innerText = `File "${fileInput.files[0].name}" was uploaded`;
528
+ sumInfo.classList.remove('hidden');
529
+ } else {
530
+ sumInfo.classList.add('hidden');
531
+ }
532
+ cache_df.is_empty = true;
533
+ cache_df.dataset = [];
534
+ }
535
+
536
  const showDropdownButton = document.getElementById('showDropdown');
537
  const dropdownSearch = document.getElementById('dropdownSearch');
538
  const ulColumns = document.getElementById('ul-columns');
static/analytics.html CHANGED
@@ -231,16 +231,20 @@
231
  <div class="mt-6">
232
  <section class="mt-6 space-y-6">
233
  <div class="dark-block rounded-lg w-full p-4 bg-white xl:p-6">
234
- <div>
235
  <label class="flex flex-col items-center justify-center w-full h-32 mt-2 text-gray-500 border-2 border-gray-300 rounded-md cursor-pointer hover:text-gray-600 md:h-64">
236
  <svg class="w-8 h-8" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
237
  <path d="M16.88 9.1A4 4 0 0 1 16 17H5a5 5 0 0 1-1-9.9V7a3 3 0 0 1 4.52-2.59A4.98 4.98 0 0 1 17 8c0 .38-.04.74-.12 1.1zM11 11h3l-4-4-4 4h3v3h2v-3z"></path>
238
  </svg>
239
-
240
  <span class="mt-4">Import Data</span>
241
  <input id="data" type="file" class="hidden" accept=".csv">
242
  </label>
243
  </div>
 
 
 
 
244
  <div class="mt-4 flex justify-between no-invert">
245
  <button id="submit" class="w-full flex items-center justify-center py-2 px-4 rounded font-medium text-white rounded-full" style="max-height: 2.5rem;">
246
  Analize
 
231
  <div class="mt-6">
232
  <section class="mt-6 space-y-6">
233
  <div class="dark-block rounded-lg w-full p-4 bg-white xl:p-6">
234
+ <div class="file-section" ondragover="allowDrop(event)" ondrop="drop(event)">
235
  <label class="flex flex-col items-center justify-center w-full h-32 mt-2 text-gray-500 border-2 border-gray-300 rounded-md cursor-pointer hover:text-gray-600 md:h-64">
236
  <svg class="w-8 h-8" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
237
  <path d="M16.88 9.1A4 4 0 0 1 16 17H5a5 5 0 0 1-1-9.9V7a3 3 0 0 1 4.52-2.59A4.98 4.98 0 0 1 17 8c0 .38-.04.74-.12 1.1zM11 11h3l-4-4-4 4h3v3h2v-3z"></path>
238
  </svg>
239
+
240
  <span class="mt-4">Import Data</span>
241
  <input id="data" type="file" class="hidden" accept=".csv">
242
  </label>
243
  </div>
244
+
245
+ <p id='sum-err' class="hidden no-invert mt-3 text-sm text-red-500"></p>
246
+ <p id='sum-info' class="hidden no-invert mt-3 text-sm text-blue-500"></p>
247
+
248
  <div class="mt-4 flex justify-between no-invert">
249
  <button id="submit" class="w-full flex items-center justify-center py-2 px-4 rounded font-medium text-white rounded-full" style="max-height: 2.5rem;">
250
  Analize
static/index.html CHANGED
@@ -295,7 +295,7 @@
295
  <p class="font-medium text-gray-500">Total Projects</p>
296
 
297
  <div class="flex items-end">
298
- <h2 class="mt-1 text-2xl font-medium text-original">3</h2>
299
  </div>
300
  </div>
301
 
 
295
  <p class="font-medium text-gray-500">Total Projects</p>
296
 
297
  <div class="flex items-end">
298
+ <h2 class="mt-1 text-2xl font-medium text-original">4</h2>
299
  </div>
300
  </div>
301