new layout drawer and new btns

This commit is contained in:
Hubert Sokołowski
2021-04-27 00:37:53 +02:00
parent d72c7ad83d
commit f23125e67a
11 changed files with 237 additions and 52 deletions

View File

@@ -4,6 +4,7 @@ import Tree from './Tree';
import Navigation from './Navigation';
import { builder as _builder_ } from '../services/Playground';
import { AttributesProvider } from '../contexts/AttributesContext';
import { IgnoredProviders } from '../contexts/IgnoredContext';
import { BuilderConfigProvider } from '../contexts/BuilderConfigContext';
function Main() {
@@ -27,7 +28,7 @@ function Main() {
<Navigation onPrepareConfig={StartDrawing} />
{/* <Button onClick={start}>Drzewo</Button> */}
<br></br>
<div>{isReady ? <Tree options={builder} /> : <div>czekam na ciebie</div>}</div>
<div>{isReady ? <Tree options={builder} /> : <div>Deploy your set</div>}</div>
</div>
</AttributesProvider>
</BuilderConfigProvider>

View File

@@ -7,22 +7,33 @@ import {
DrawerBody,
DrawerOverlay,
DrawerContent,
OrderedList,
ListItem,
} from '@chakra-ui/react';
function DrawerRoll() {
function DrawerRoll({ ignoredAttributes }) {
const { isOpen, onOpen, onClose } = useDisclosure();
var collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return (
<>
<Button onClick={onOpen}>Open Drawer</Button>
<Drawer placement="right" onClose={onClose} isOpen={isOpen}>
<DrawerOverlay />
<DrawerContent>
<DrawerHeader borderBottomWidth="1px">Basic Drawer</DrawerHeader>
<DrawerHeader borderBottomWidth="1px">Your all ignored attributes:</DrawerHeader>
<DrawerBody>
<OrderedList>
{ignoredAttributes.sort(collator.compare).map(item => (
<ListItem>
<p>{item}</p>
</ListItem>
))}
</OrderedList>
{/* <p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p> */}
</DrawerBody>
</DrawerContent>
</Drawer>
@@ -31,3 +42,4 @@ function DrawerRoll() {
}
export default DrawerRoll;
export const DrawerMemo = React.memo(DrawerRoll);

View File

@@ -24,10 +24,11 @@ import { builder } from '../../services/Playground';
import IgnoredAttributes from './IgnoredAttributes';
import Builder from './Builder';
import FormControlNumberInput from './FormControlNumberInput';
import DrawerRoll from './DrawerRoll';
import DrawerRoll, { DrawerMemo } from './DrawerRoll';
import { useLoadingContext } from '../../contexts/LoadingContext';
import { useAttributesContext } from '../../contexts/AttributesContext';
import { useBuilderConfigContext } from '../../contexts/BuilderConfigContext';
import { useIgnoredContext } from '../../contexts/IgnoredContext';
/**
* @typedef {import('../../utils/decision-tree.js').DecisionTreeBuilder} DecisionTreeBuilder
@@ -47,6 +48,7 @@ function Navigation({ onPrepareConfig }) {
const [allClazz, setAllClasses] = useState([]);
const [config, setConfig] = useState({});
const { attributes: options, onAttributesChange } = useAttributesContext();
//const { attributes: ignoredAttributes, onIgnoredChange } = useIgnoredContext();
const { isLoading } = useLoadingContext();
function handleSelectDecision(value) {
@@ -57,6 +59,7 @@ function Navigation({ onPrepareConfig }) {
function handleSelectIgnore(value) {
console.log(value);
setIgnoredAttributes(value);
//onIgnoredChange(value)
}
function handleSetMinItems(value) {
//console.log(value);
@@ -229,7 +232,7 @@ function Navigation({ onPrepareConfig }) {
</Collapse>
<Stack spacing={2} direction={['row']} align="center" alignContent="center" justify="center">
<Button onClick={onToggle}>{isOpen ? 'HIDE' : 'SHOW'}</Button>
<DrawerRoll />
<DrawerMemo ignoredAttributes={ignoredAttributes} />
</Stack>
</Box>
);

View File

@@ -23,9 +23,11 @@ function ReactTable({ set, cols }) {
console.log(set, cols);
const data = React.useMemo(() => set, []);
var collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
function prepareHeaders(cols) {
let tmp = [];
for (let item of cols.sort()) {
for (let item of cols.sort(collator.compare)) {
tmp.push({
Header: item,
accessor: item,

View File

@@ -36,7 +36,7 @@ function DataViewer({ node, side }) {
fontSize="14px"
fontWeight="semibold"
>
{sideSubTitle}
{sideSubTitle} - {node.nodeSet ? node.nodeSet.length : node.trainingSet2.length} elements.
</Button>
</Tooltip>
<Modal

View File

@@ -0,0 +1,36 @@
import React, { useState } from 'react';
import {
Box,
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Tooltip,
useDisclosure,
} from '@chakra-ui/react';
import { IoMdArrowDropdownCircle, IoMdArrowDropupCircle } from 'react-icons/io';
function DataViewer({ hide, onChange }) {
return (
<Button
mt={1}
px={2}
py={3}
onClick={() => onChange(!hide)}
colorScheme="teal"
variant="outline"
size="sm"
fontSize="14px"
//color="white"
mr={1}
>
{hide ? <IoMdArrowDropupCircle /> : <IoMdArrowDropdownCircle />}
</Button>
);
}
export default DataViewer;

View File

@@ -1,9 +1,9 @@
import { Box, Spinner, useDisclosure } from '@chakra-ui/react';
import { Box, Button, ButtonGroup, Hide, Spinner, Tooltip, useDisclosure } from '@chakra-ui/react';
import React, { useEffect, useMemo, useState } from 'react';
import { useBuilderConfigContext } from '../../contexts/BuilderConfigContext';
import { executeAlgorithm, mostFrequentValue } from '../../utils/algorithm-executor';
import DataViewer from './DataViewer';
//import { addNode } from "./utils";
import Hider from './Hide';
import Joint from './Joint';
import Leaf from './Leaf';
@@ -12,6 +12,7 @@ const Node = props => {
//console.log(props.node);
const { builderConfig } = useBuilderConfigContext();
const [highlighted, setHighlighted] = useState(false);
const [hide, setHide] = useState(false);
const [loading, setLoading] = useState(false);
const [node, setNode] = useState(props.node || {});
useEffect(() => setNode(props.node || {}), [props.node, setNode]);
@@ -115,6 +116,10 @@ const Node = props => {
});
};
const handleHide = value => {
setHide(value);
};
if (loading) {
return <Spinner size="xl" />;
}
@@ -122,41 +127,48 @@ const Node = props => {
return (
<div className={`node ${highlighted ? 'highlight' : ''}`} onClick={onNodeClicked}>
<Box d="flex" flexDirection="column" p="1" paddingLeft={3}>
<DataViewer node={node} side={side} />
{category ? (
<Leaf
category={category}
matchedCount={matchedCount}
notMatchedCount={notMatchedCount}
quality={quality}
requestLeafUnfold={unfoldLeaf}
/>
) : (
<Joint
attr2={attr2}
predicateName={predicateName}
pivot={pivot}
match={match}
notMatch={notMatch}
onChange={onChange}
requestFoldToLeaf={foldJointToLeaf}
nodeSet={nodeSet}
weight={weight}
>
<Node
node={match}
onChange={onChange}
requestChildChange={requestChildChangeIfMatchIs(true)}
side={true}
<Box d="flex" flexDirection="row">
<ButtonGroup size="sm" isAttached variant="outline">
<Hider hide={hide} onChange={handleHide} />
<DataViewer node={node} side={side} />
</ButtonGroup>
</Box>
<div style={{ display: hide ? 'none' : 'block' }}>
{category ? (
<Leaf
category={category}
matchedCount={matchedCount}
notMatchedCount={notMatchedCount}
quality={quality}
requestLeafUnfold={unfoldLeaf}
/>
<Node
node={notMatch}
) : (
<Joint
attr2={attr2}
predicateName={predicateName}
pivot={pivot}
match={match}
notMatch={notMatch}
onChange={onChange}
requestChildChange={requestChildChangeIfMatchIs(false)}
side={false}
/>
</Joint>
)}
requestFoldToLeaf={foldJointToLeaf}
nodeSet={nodeSet}
weight={weight}
>
<Node
node={match}
onChange={onChange}
requestChildChange={requestChildChangeIfMatchIs(true)}
side={true}
/>
<Node
node={notMatch}
onChange={onChange}
requestChildChange={requestChildChangeIfMatchIs(false)}
side={false}
/>
</Joint>
)}
</div>
</Box>
</div>
);

View File

@@ -0,0 +1,49 @@
import React, { useState } from 'react';
import ReactFileReader from 'react-file-reader';
import { Button } from '@chakra-ui/react';
import { GrDocumentUpload } from 'react-icons/gr';
import { readLocalFile } from '../utils/file-reader';
import parseCsv from 'csv-parse/lib/sync';
function TestSetFileReader(props) {
const handleFiles = async files => {
const file = await readLocalFile(files[0]);
//console.log(file);
const clean = file
.split('\n')
.map(line => {
return line.replace(/(^"|"$)|(")/g, '');
//return line.replace(/(^"|"$)/g, '');
})
.join('\n');
//console.log(clean);
const data = parseCsv(clean, {
columns: h => {
// let header = h.map((v, i) => v || `attr${i}`);
// allAttributes.push(header);
// return header;
if (props.isHeaders) return h.map((v, i) => v);
else return h.map((v, i) => `attr${i}`);
},
comment: '#',
skipEmptyLines: true,
delimiter: [',', '\t'],
});
//const data = parseCsv(file,{columns: true, comment: "#",skipEmptyLines: true,})
console.log(data);
props.onChange({ data });
};
return (
<div>
<ReactFileReader multipleFiles={false} fileTypes={['.csv']} handleFiles={handleFiles}>
<Button leftIcon={<GrDocumentUpload />}>Upload test set</Button>
</ReactFileReader>
</div>
);
}
export default TestSetFileReader;

View File

@@ -1,10 +1,11 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Box, Spinner } from '@chakra-ui/react';
// import { start } from '../services/Playground';
// import { dt } from '../services/TSP';
import { Box, Button, HStack, Spinner } from '@chakra-ui/react';
import { GrTechnology, GrDocumentUpload } from 'react-icons/gr';
import { GiWaterDivinerStick } from 'react-icons/gi';
import Node from './Node';
import { useLoadingContext } from '../contexts/LoadingContext';
import { executeAlgorithm } from '../utils/algorithm-executor';
import TestSetFileReader from './TestSetFileReader';
/**
* @typedef {import('../utils/decision-tree.js').DecisionTreeBuilder} DecisionTreeBuilder
@@ -27,6 +28,7 @@ const Tree = ({ options }) => {
// }, [options]);
const [root, setRoot] = useState(null);
const [testSet, setTestSet] = useState([]);
const { isLoading, setIsLoading } = useLoadingContext();
useEffect(() => {
@@ -57,14 +59,39 @@ const Tree = ({ options }) => {
const requestChildChange = newRoot => setRoot(newRoot);
function handleGetTestSet({ data }) {
setTestSet(data);
console.log(data);
}
function predict(root) {
console.log('predict');
}
return (
<div id="tree">
<h1>Tree</h1>
<p>
<button onClick={() => logTree(root)}>Log tree</button>
</p>
<HStack spacing="24px">
<Box>
<p>
<Button leftIcon={<GrTechnology />} onClick={() => logTree(root)}>
Log tree
</Button>
</p>
</Box>
<Box>
<p>
<TestSetFileReader onChange={handleGetTestSet} isHeaders={false} />
</p>
</Box>
<Box>
<p>
<Button leftIcon={<GiWaterDivinerStick />} onClick={() => predict(root)}>
Predict
</Button>
</p>
</Box>
</HStack>
{isLoading && <Spinner size="xl" />}
<h2>Nodes:</h2>
<h1>Tree nodes:</h1>
<Box>
{!root ? (
<p>No tree to show</p>

View File

@@ -0,0 +1,19 @@
import React, { useContext, useState } from 'react';
// @ts-ignore
const IgnoredContext = React.createContext();
export const IgnoredProviders = ({ children }) => {
const [attributes, setAttributes] = useState([]);
const onIgnoredChange = input => setAttributes(input.map(element => ({ value: element, name: element })));
return (
<IgnoredContext.Provider value={{ attributes, onIgnoredChange }}>{children}</IgnoredContext.Provider>
);
};
export const useIgnoredContext = () => {
const { attributes, onIgnoredChange } = useContext(IgnoredContext);
return { attributes, onIgnoredChange };
};

View File

@@ -1,3 +1,27 @@
function predict(tree, item) {
var attr, value, predicate, pivot;
// Traversing tree from the root to leaf
while (true) {
if (tree.category) {
// only leafs contains predicted category
return tree.category;
}
attr = tree.attribute;
value = item[attr];
predicate = predicates[tree.predicate];
pivot = tree.pivot;
// move to one of subtrees
if (predicate(value, pivot)) {
tree = tree.match;
} else {
tree = tree.notMatch;
}
}
}
var predicates = {
'==': function (a, b) {
return a === b;