Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
512 changes: 488 additions & 24 deletions client/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-select": "^5.8.0",
"yup": "^1.3.3"
},
"devDependencies": {
Expand Down
54 changes: 54 additions & 0 deletions client/src/components/DataAnalysisForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect, useState, useContext } from 'react'
import axios from 'axios';
import { CsrfContext } from '../context/CsrfContext';
import DataCleanseDropDown from './DataCleanseDropDown';


const DataAnalysisForm = () => {

const { csrfToken, setCsrfToken } = useContext(CsrfContext);
const [functionNames, setFunctionNames] = useState([]);
const [selectedFunctionNames, setSelectedFunctionNames] = useState([]);

const handleSubmit = (e) => {
e.preventDefault();
const cleanseFromData = new FormData(e.target);
const formFunctionNames = cleanseFromData.getAll('functionNames');
console.log('Selected function names:', formFunctionNames);
};


useEffect(() => {
const url = 'http://localhost:8000/api/get_all_function_names/'
const config = {
withCredentials: true,
headers: {
'X-CSRFToken': csrfToken,
}
}
const getFunctionNames = async () => {
try {
const response = await axios.get(url, config);
console.log("RESPONSE ^^^^^ ", response)
setFunctionNames(response.data.function_names);
// Set the CSRF token in the headers for subsequent requests
} catch (error) {
console.error('Error fetching Function Name:', error);
}
};
getFunctionNames();

}, []);




return (
<form onSubmit={handleSubmit}>
<DataCleanseDropDown functionNames={functionNames} onSelectChange={setSelectedFunctionNames} selectedFunctionNames={selectedFunctionNames}/>
<button type="submit">Submit</button>
</form>
)
}

export default DataAnalysisForm
38 changes: 38 additions & 0 deletions client/src/components/DataCleanseDropDown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, {useState} from 'react';

import Select from 'react-select';
import makeAnimated from 'react-select/animated';


const animatedComponents = makeAnimated();

const DataCleanseDropDown = ({functionNames, onSelectChange}) => {

const options = functionNames.map(({ _id, function_name }) => ({
label: function_name,
value: _id
}));

const handleSelectChange = (selectedOptions) => {
const selectedFunctionNames = selectedOptions.map(option => option.value);

onSelectChange(selectedFunctionNames)
};

console.log("these are function Names ---->", functionNames)
return (
<div>
<Select
closeMenuOnSelect={false}
components={animatedComponents}
defaultValue={null}
isMulti
options={options}
onChange={handleSelectChange}
name="functionNames"
/>
</div>
)
}

export default DataCleanseDropDown
10 changes: 5 additions & 5 deletions client/src/components/StatCards.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const StatCards = ({ title, data }) => {
{title && <h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">{title}</h5>}
{Object.entries(data).map(([key, value]) => (
<div key={key}>
<p className="font-semibold text-gray-700 dark:text-gray-300">{key}</p>
<span className="font-semibold text-gray-700 dark:text-gray-300">{key}</span>
{Array.isArray(value) ? (
<ul className="list-disc ml-6">
{value.map((item, index) => (
Expand All @@ -30,13 +30,13 @@ const StatCards = ({ title, data }) => {
<div className="ml-6">
{Object.entries(value).map(([subKey, subValue], idx) => (
<div key={idx}>
<p className="font-semibold text-sm text-gray-700 dark:text-gray-300">{subKey}:</p>
<span className="font-semibold text-sm text-gray-700 dark:text-gray-300">{subKey}:</span>
{Array.isArray(subValue) ? (
<ul className="list-disc ml-6">
<span className="ml-2">
{subValue.map((item, idx) => (
<li key={idx}>{item}</li>
<span key={idx}>{item}</span>
))}
</ul>
</span>
) : (
<p className="font-normal text-sm text-gray-700 dark:text-gray-400 ml-6">{subValue}</p>
)}
Expand Down
16 changes: 16 additions & 0 deletions client/src/components/UploadCsvForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ const UploadCsvForm = () => {
setFile(e.target.files[0]);
};

useEffect(() => {
const storedFormData = localStorage.getItem('formData');
const storedParsedFileData = localStorage.getItem('parsedFileData');

if (storedFormData && storedParsedFileData) {
const parsedFormData = JSON.parse(storedFormData);
const parsedParsedFileData = JSON.parse(storedParsedFileData);

setDataframe(parsedFormData);
setParsedFileData(parsedParsedFileData);
}
}, []);

//! need validations if no file uploaded
const schema = Yup.object().shape({
file: Yup.mixed().required('CSV file is required'),
});
Expand All @@ -29,6 +43,7 @@ const UploadCsvForm = () => {
skipEmptyLines: false,
complete: function (results) {
setParsedFileData(results.data)
localStorage.setItem('parsedFileData', JSON.stringify(results.data));
console.log("PAPAPARSE----->", results.data)
},
},
Expand Down Expand Up @@ -56,6 +71,7 @@ const UploadCsvForm = () => {
console.log("RESPONSE---->", response)
console.log("FileData---->", response.data.df_info)
setDataframe(response.data)
localStorage.setItem('formData', JSON.stringify(response.data));
setUploadStatus('File Uploaded Successfully')
showCsvFile()

Expand Down
45 changes: 17 additions & 28 deletions client/src/views/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,55 @@
import React, { useState, useEffect, useContext } from 'react';
import axios from 'axios';

//! Components
import StatCards from '../components/StatCards';
import TestChart from '../components/TestChart';
import TableData from '../components/TableData';
import AllCsvs from '../components/AllCsvs';
import UploadCsvForm from '../components/UploadCsvForm';
import { DataframeContext } from '../context/DataframeContext';
import StatCardsData from '../utils/StatCardsData';
import { CsrfContext } from '../context/CsrfContext';
import DataAnalysisForm from '../components/DataAnalysisForm'

// const secretToken = import.meta.env.VITE_SECRET_TOKEN

const Dashboard = () => {
const {csrfToken, setCsrfToken} = useContext(CsrfContext)
const {dataframe} = useContext(DataframeContext)
const { csrfToken, setCsrfToken } = useContext(CsrfContext)
const { dataframe } = useContext(DataframeContext)
console.log('CSRF Token is in Dash:', csrfToken);
const { parsedFileData, setParsedFileData } = useContext(DataframeContext)

return (
<>
<div className="flex flex-wrap justify-center align-center mx-auto m-10">
<div className="flex flex-wrap justify-center m-10 mx-auto align-center">
<div className="">
<StatCardsData dataframe={dataframe}/> Basic Summary - # of rows/ columns/ duplicates/ missing values
<StatCardsData dataframe={dataframe} />
</div>
{/* <div className="w-full sm:w-1/2 md:w-1/4 p-4"><StatCards /> Describe (mean, medium)</div>
<div className="w-full sm:w-1/2 md:w-1/4 p-4"><StatCards /> Data Types</div>
<div className="w-full sm:w-1/2 md:w-1/4 p-4"><StatCards /></div> */}
</div>

{/* the divider after the top cards */}

<div className="relative flex py-5 items-center">
<div className="relative flex items-center py-5">
<div className="flex-grow border-t border-gray-400 dark:border-gray-200"></div>
<span className="flex-shrink mx-4 text-gray-400 dark:text-white">Statistics</span>
<div className="flex-grow border-t border-gray-400 dark:border-gray-200"></div>
</div>

{/* SearchBar Component */}

<div className="block mx-auto w-1/2 text-center">
<AllCsvs/>
{/* Dropdown Component */}
<div className="block w-1/2 mx-auto text-center">
<AllCsvs />
</div>

{/* Bottom half of screen */}
<div className='flex flex-wrap justify-around w-full p-10 m-10 mx-auto'>
<div className="w-full p-10 bg-white shadow sm:w-5/12 md:w-5/12 dark:bg-gray-700">

<div className='flex flex-wrap justify-around w-full mx-auto m-10 p-10'>
<div className="shadow w-full p-10 sm:w-5/12 md:w-5/12 bg-white dark:bg-gray-700">

{/* Upload form */}

{/* Upload Form */}
<UploadCsvForm />

{/* chart component */}
<TestChart />

{/* DataAnalysis Form */}
<DataAnalysisForm />
</div>

{/* right side div for visual of form */}

<div className="shadow w-full sm:w-5/12 md:w-5/12 p-10 bg-white dark:bg-gray-700">
<div className="w-full p-10 bg-white shadow sm:w-5/12 md:w-5/12 dark:bg-gray-700">
<TableData parsedFileData={parsedFileData} />
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions server/data_viz_app/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from djongo import models
from rest_pandas import PandasView, PandasUnstackedSerializer

from django.core.validators import MinLengthValidator

# Create your models here.
class CSVUpload(models.Model):
_id = models.ObjectIdField()
file_name = models.CharField(max_length=144)
file_name = models.CharField(max_length=144, validators=[MinLengthValidator(4)], blank=False, help_text='Length has to between 4 - 144 characters')
csv_file = models.FileField(upload_to='datasets/', blank=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Expand All @@ -19,4 +19,11 @@ def __repr__(self) -> str:
CSV File PATH - {self.csv_file} ^^^^'''


class FunctionName(models.Model):
_id = models.ObjectIdField()
function_name = models.CharField(max_length=144, validators=[MinLengthValidator(4)], blank=False, help_text='Length has to between 4 - 144 characters' )
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __repr__(self) -> str:
return f'''FunctionName ID {self._id} and name {self.function_name}'''
8 changes: 5 additions & 3 deletions server/data_viz_app/serializers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from rest_framework import serializers
from .models import CSVUpload
from .models import CSVUpload, FunctionName

class CSVUploadSerializer(serializers.ModelSerializer):
class Meta:
model = CSVUpload
fields = '__all__'


class DataFrameSerializer():
class FunctionNameSerializer(serializers.ModelSerializer):
class Meta:
pass
model = FunctionName
fields = '__all__'

13 changes: 7 additions & 6 deletions server/data_viz_app/urls.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from django.urls import path
from .views import DataInsights
from .views import data_cleanse, data_stats
from django.conf import settings
from django.conf.urls.static import static
from rest_framework.urlpatterns import format_suffix_patterns

from . import views

urlpatterns = [
path("get_csrf/", DataInsights.as_view()),
path("upload_csv/", DataInsights.as_view()),
path("home/",views.home, name="home"),
path("get_all_csvs/", views.get_all_csvs, name = "get_all_csvs")
path("get_csrf/", data_stats.DataInsights.as_view()),
path("upload_csv/", data_stats.DataInsights.as_view()),
path("home/",data_stats.home, name="home"),
path("get_all_csvs/", data_stats.get_all_csvs, name = "get_all_csvs"),
path("create_function_name/", data_cleanse.create_function_name, name ="create_function_name"),
path("get_all_function_names/", data_cleanse.get_all_function_names, name = "get_all_function_names")
]


Expand Down
2 changes: 2 additions & 0 deletions server/data_viz_app/views/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .data_stats import *
from .data_cleanse import *
61 changes: 61 additions & 0 deletions server/data_viz_app/views/data_cleanse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from django.http import JsonResponse
import pandas as pd
import numpy as np
from ..models import FunctionName
from ..serializers import FunctionNameSerializer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from django.views.decorators.csrf import csrf_protect, csrf_exempt


@api_view(['POST'])
def create_function_name(request):
print("### REQUEST ### ", request)
print("### REQUEST DATA ### ", request.data)

serializer = FunctionNameSerializer(data=request.data)
#todo validate data
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET'])
def get_all_function_names(request):
all_ds_functions = FunctionName.objects.all()
serializer_ds_functions = FunctionNameSerializer(all_ds_functions, many=True)
print("**function names **", all_ds_functions)
print("**function names serialized **", serializer_ds_functions)
return JsonResponse({"function_names" : serializer_ds_functions.data})




def sanitize_data():
# conditionals
#! if function name is called match to function in file

pass




# removes extra spaces, tabs, new lines, returns
def remove_spaces(self, df): #change?
df = df.replace(r'\r+|\n+|\t+|\(+|\)+|','', regex=True)
new_df = pd.DataFrame()
for col in df:
series = df[col]
# check column data type
if series.dtype == 'object':
series = series.str.strip() #removes leading and trailing spaces
# series = series.str.replace(" ", "") #this removes all spaces
new_df[col] = series
else:
new_df[col] = series
return new_df


def is_valid():
pass
Loading