mirror of
https://github.com/hsokolowski/iTree.git
synced 2026-04-18 20:36:55 -04:00
new layout drawer and new btns
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
36
src/components/Node/Hide.jsx
Normal file
36
src/components/Node/Hide.jsx
Normal 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;
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
49
src/components/TestSetFileReader.jsx
Normal file
49
src/components/TestSetFileReader.jsx
Normal 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;
|
||||
@@ -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>
|
||||
|
||||
19
src/contexts/IgnoredContext.jsx
Normal file
19
src/contexts/IgnoredContext.jsx
Normal 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 };
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user