diff --git a/components/categorical-variable.tsx b/components/categorical-variable.tsx index 2f668911..e73541b8 100644 --- a/components/categorical-variable.tsx +++ b/components/categorical-variable.tsx @@ -54,7 +54,7 @@ export default function CategoricalVariable(props: CategoricalVariableProps) {
{option} deleteOption(index)} size="small" aria-label="delete" color="primary"> - +
@@ -65,10 +65,10 @@ export default function CategoricalVariable(props: CategoricalVariableProps) { setOptions([...options, option]) }}/> - - + + - + ) diff --git a/components/data-points.tsx b/components/data-points.tsx index fab1f11c..b2cc755e 100644 --- a/components/data-points.tsx +++ b/components/data-points.tsx @@ -143,6 +143,7 @@ export default function DataPoints(props: DataPointProps) { }> + {buildCombinedVariables().length === 0 && "Data points will appear here"} {buildCombinedVariables().length > 0 && isLoadingState && } diff --git a/components/experiment.tsx b/components/experiment.tsx index dbc990dd..b1d4cb5f 100644 --- a/components/experiment.tsx +++ b/components/experiment.tsx @@ -152,12 +152,6 @@ export default function Experiment(props: ExperimentProps) { updateDescription={(description: string) => dispatch({ type: 'updateExperimentDescription', payload: description })} /> - - - - - dispatch({ type: 'updateDataPoints', payload: dataPoints })} /> + + + + + + dispatch({ type: 'updateDataPoints', payload: dataPoints })} /> + + diff --git a/components/model-editor.tsx b/components/model-editor.tsx index 1a952976..381c769d 100644 --- a/components/model-editor.tsx +++ b/components/model-editor.tsx @@ -30,7 +30,6 @@ export default function ModelEditor(props: ModelEditorProps) { name="info.description" label="Description" value={info.description} - required onChange={(e: ChangeEvent) => props.updateDescription((e.target as HTMLInputElement).value)} /> diff --git a/components/optimizer-configurator.tsx b/components/optimizer-configurator.tsx index 42b05ee7..885d642d 100644 --- a/components/optimizer-configurator.tsx +++ b/components/optimizer-configurator.tsx @@ -10,7 +10,7 @@ type OptimizerConfiguratorProps = { export default function OptimizerConfigurator(props: OptimizerConfiguratorProps) { const { config , onConfigUpdated} = props - const { register, handleSubmit, reset, watch, errors, getValues } = useForm() + const { register, getValues } = useForm() const handleChange = () => { onConfigUpdated(getValues() as OptimizerConfig) diff --git a/components/optimizer-model.tsx b/components/optimizer-model.tsx index 7b418b1e..aa87397f 100644 --- a/components/optimizer-model.tsx +++ b/components/optimizer-model.tsx @@ -1,9 +1,11 @@ -import { Box, Button, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography } from '@material-ui/core' +import { Box, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography, Tooltip } from '@material-ui/core' import { CategoricalVariableType, ValueVariableType } from '../types/common' import DeleteIcon from '@material-ui/icons/Delete' -import { useState } from 'react' import VariableEditor from './variable-editor' +import useStyles from '../styles/optimizer-model.style' import { TitleCard } from './title-card' +import LensIcon from '@material-ui/icons/Lens' +import PanoramaFishEyeIcon from '@material-ui/icons/PanoramaFishEye' type OptimizerModelProps = { valueVariables: ValueVariableType[] @@ -17,105 +19,110 @@ type OptimizerModelProps = { export default function OptimizerModel(props: OptimizerModelProps) { const { valueVariables, categoricalVariables, disabled, onDeleteValueVariable, onDeleteCategoricalVariable, addValueVariable, addCategoricalVariable } = props - const [isAddOpen, setAddOpen] = useState(false) + const classes = useStyles() return ( - - {valueVariables.length > 0 && - - - - Name - Description - minVal - maxVal - - - - - {valueVariables.map((valueVar, valueIndex) => ( - - {valueVar.name} - {valueVar.description} - {valueVar.minVal} - {valueVar.maxVal} - - {onDeleteValueVariable(valueVar)}}> - - - - - ))} - -
- } - - {categoricalVariables.length > 0 && - - - - - Name - Description - Options - - - - - {categoricalVariables.map((catVar, catIndex) => ( - - {catVar.name} - {catVar.description} - - {catVar.options.map((option, optionIndex) => ( -
- {option} -
- ))} -
- - {onDeleteCategoricalVariable(catVar)}}> - - - + + {(valueVariables.length > 0 || categoricalVariables.length > 0) && + + {valueVariables.length > 0 && +
+ + + + Name + Description + minVal + maxVal + - ))} - -
-
- } - {!isAddOpen && - - + + + {valueVariables.map((valueVar, valueIndex) => ( + + {valueVar.discrete ? + + + : + + + } + + {valueVar.name} + {valueVar.description} + {valueVar.minVal} + {valueVar.maxVal} + + {onDeleteValueVariable(valueVar)}}> + + + + + ))} + + + } + + {categoricalVariables.length > 0 && + + + + + Name + Description + Options + + + + + {categoricalVariables.map((catVar, catIndex) => ( + + {catVar.name} + {catVar.description} + + {catVar.options.map((option, optionIndex) => ( +
+ {option} +
+ ))} +
+ + {onDeleteCategoricalVariable(catVar)}}> + + + +
+ ))} +
+
+
+ }
} - {isAddOpen && - + + + {!disabled && addCategoricalVariable(categoricalVariable)} addValueVariable={(valueVariable: ValueVariableType) => addValueVariable(valueVariable)} - close={() => setAddOpen(false)} /> - - } - - {disabled && - - - Note: Model cannot be updated while there are data points - - - } + /> + } + + {disabled && + + + Model cannot be updated while there are data points. + + + } +
) } diff --git a/components/plots.tsx b/components/plots.tsx index fa8d0092..3f7ce3eb 100644 --- a/components/plots.tsx +++ b/components/plots.tsx @@ -6,13 +6,15 @@ export const Plots = () => { return ( <> - {experiment.results.plots.length > 0 && - + + {experiment.results.plots.length > 0 ?
    {experiment.results.plots && experiment.results.plots.map(plot =>
  • {plot.id}
  • )}
-
- } + : + "Plots will appear here" + } +
) } \ No newline at end of file diff --git a/components/title-card.tsx b/components/title-card.tsx index 93728b01..a44bfd73 100644 --- a/components/title-card.tsx +++ b/components/title-card.tsx @@ -4,11 +4,12 @@ import useStyles from "../styles/title-card.style" type TitleCardProps = { title: ReactNode + padding?: number children: any } export const TitleCard = (props: TitleCardProps) => { - const { title, children } = props + const { title, padding, children } = props const classes = useStyles() return ( @@ -17,7 +18,7 @@ export const TitleCard = (props: TitleCardProps) => { {title} - + {children} diff --git a/components/value-variable.tsx b/components/value-variable.tsx index f86173c0..26ad4348 100644 --- a/components/value-variable.tsx +++ b/components/value-variable.tsx @@ -1,5 +1,6 @@ import { Box, Button, TextField } from '@material-ui/core' import { useForm } from 'react-hook-form'; +import useStyles from '../styles/value-variable.style'; import { ValueVariableType } from '../types/common'; type ValueVariableProps = { @@ -7,15 +8,36 @@ type ValueVariableProps = { onAdded: (data: ValueVariableType) => void } +type ValueVariableInput = { + name: string + description: string + min: string + max: string +} + export default function ValueVariable(props: ValueVariableProps) { const { isDisabled, onAdded } = props + const classes = useStyles() - const { register, handleSubmit, reset, watch, errors } = useForm(); - const onSubmit = async (data: ValueVariableType) => { - onAdded(data) + const { register, handleSubmit, reset } = useForm() + + const onSubmit = async (data: ValueVariableInput) => { + const value: ValueVariableType = createValueVariable(data) + onAdded(value) reset() } + const createValueVariable = (input: ValueVariableInput): ValueVariableType => { + const discrete = input.min.indexOf('.') === -1 && input.max.indexOf('.') === -1 + return { + name: input.name, + description: input.description, + minVal: Number(input.min), + maxVal: Number(input.max), + discrete + } + } + return ( <>
@@ -33,23 +55,27 @@ export default function ValueVariable(props: ValueVariableProps) { label="Description" inputRef={register} /> - - - - + + + + + + + + ) diff --git a/components/variable-editor.tsx b/components/variable-editor.tsx index e3a2661a..c1399015 100644 --- a/components/variable-editor.tsx +++ b/components/variable-editor.tsx @@ -1,7 +1,6 @@ import CategoricalVariable from './categorical-variable'; import ValueVariable from './value-variable'; -import { Box, Card, CardContent, Grid, IconButton, Radio, Typography } from "@material-ui/core" -import CloseIcon from "@material-ui/icons/Close"; +import { Box, Tab, Tabs } from "@material-ui/core" import { useState } from "react" import useStyles from '../styles/variable-editor.style'; import { CategoricalVariableType, ValueVariableType } from '../types/common'; @@ -10,66 +9,40 @@ type VariableEditorProps = { isAddVariableDisabled: boolean addValueVariable: (valueVariable: ValueVariableType) => void addCategoricalVariable: (categoricalVariable: CategoricalVariableType) => void - close: () => void } export default function VariableEditor(props: VariableEditorProps) { - const { isAddVariableDisabled, addValueVariable, addCategoricalVariable, close } = props + const { isAddVariableDisabled, addValueVariable, addCategoricalVariable } = props - const [radioIndex, setRadioIndex] = useState(0) + const [tabIndex, setTabIndex] = useState(0) const classes = useStyles() - return ( - - - - - - - - - Add variable - - + const handleTabChange = (event: React.ChangeEvent<{}>, newValue: number) => { + setTabIndex(newValue) + } - - close()}> - - - - - - {setRadioIndex(0)}} - /> - Value - - - {setRadioIndex(1)}} - /> - Categorical - - - - {radioIndex === 0 && - addValueVariable(valueVariable)} /> - } - {radioIndex === 1 && - addCategoricalVariable(categoricalVariable)} /> - } - - - - - - - + return ( + <> + + + + + + {tabIndex === 0 && + addValueVariable(valueVariable)} /> + } + {tabIndex === 1 && + addCategoricalVariable(categoricalVariable)} /> + } + + ) } \ No newline at end of file diff --git a/reducers/reducers.test.ts b/reducers/reducers.test.ts index d1008ebb..9f253051 100644 --- a/reducers/reducers.test.ts +++ b/reducers/reducers.test.ts @@ -18,6 +18,7 @@ describe("experiment reducer", () => { options: [], }], valueVariables: [{ + discrete: false, name: "Water", description: "Wet", minVal: 100, @@ -58,6 +59,7 @@ describe("experiment reducer", () => { options: [], }], valueVariables: [{ + discrete: false, name: "Not water", description: "Not wet", minVal: 101, @@ -130,6 +132,7 @@ describe("experiment reducer", () => { it("should add value variable", async () => { const payload: ValueVariableType = { + discrete: false, name: "Flour", description: "Wet", minVal: 300, @@ -146,6 +149,7 @@ describe("experiment reducer", () => { valueVariables: [{ name: "Water", description: "Wet", + discrete: false, minVal: 100, maxVal: 200, }, @@ -156,6 +160,7 @@ describe("experiment reducer", () => { it("should delete value variable", async () => { const payload: ValueVariableType = { + discrete: false, name: "Water", description: "Wet", minVal: 100, diff --git a/styles/editable-table.style.tsx b/styles/editable-table.style.tsx index 11b39509..bd74aec8 100644 --- a/styles/editable-table.style.tsx +++ b/styles/editable-table.style.tsx @@ -1,9 +1,10 @@ import { makeStyles } from "@material-ui/core"; +import { grey } from "@material-ui/core/colors"; export const useStyles = makeStyles(theme => ({ buttonContainer: { whiteSpace: "nowrap", - } + }, })); export default useStyles \ No newline at end of file diff --git a/styles/optimizer-model.style.tsx b/styles/optimizer-model.style.tsx new file mode 100644 index 00000000..c218c80d --- /dev/null +++ b/styles/optimizer-model.style.tsx @@ -0,0 +1,13 @@ +import { makeStyles } from "@material-ui/core"; +import { grey } from "@material-ui/core/colors"; + +export const useStyles = makeStyles(theme => ({ + editBox: { + background: grey[100], + }, + iconDiscrete: { + fontSize: 10, + }, +})); + +export default useStyles \ No newline at end of file diff --git a/styles/value-variable.style.tsx b/styles/value-variable.style.tsx new file mode 100644 index 00000000..1e73b2ca --- /dev/null +++ b/styles/value-variable.style.tsx @@ -0,0 +1,13 @@ +import { makeStyles } from "@material-ui/core"; + +export const useStyles = makeStyles(theme => ({ + narrowInput: { + float: 'left', + width: '50%', + }, + narrowInputContainer: { + display: 'flex', + }, +})); + +export default useStyles \ No newline at end of file diff --git a/styles/variable-editor.style.tsx b/styles/variable-editor.style.tsx index cb67fc4a..c0e611f4 100644 --- a/styles/variable-editor.style.tsx +++ b/styles/variable-editor.style.tsx @@ -1,9 +1,10 @@ import { makeStyles } from "@material-ui/core"; export const useStyles = makeStyles(theme => ({ - main: { - background: theme.palette.grey[50], - } + customTab: { + minWidth: 'auto', + fontSize: theme.typography.pxToRem(12), + }, })); export default useStyles \ No newline at end of file diff --git a/theme/theme.ts b/theme/theme.ts index c3a1bd77..82f1adf5 100644 --- a/theme/theme.ts +++ b/theme/theme.ts @@ -110,8 +110,6 @@ const cyans: CustomColours = { /* bee: -rgba(236,228,213,1) -rgba(241,233,218,1) rgba(235,150,5,1) #e6c338 */ @@ -119,8 +117,8 @@ rgba(235,150,5,1) const bee: CustomColours = { primary: 'rgba(235,150,5,1)', secondary: '#e6c338', - backPrimary: 'rgba(236,228,213,1)', - backSecondary: 'rgba(241,233,218,1)', + backPrimary: grey[200], + backSecondary: grey[100], textInsideBox: grey[800], transparentBox: 'rgba(255,255,255,0.75)', } diff --git a/types/common.ts b/types/common.ts index d9c2d46c..8438a4f1 100644 --- a/types/common.ts +++ b/types/common.ts @@ -30,6 +30,7 @@ export type CategoricalVariableType = { } export type ValueVariableType = { + discrete: boolean name: string description: string minVal: number diff --git a/utility/converters.test.ts b/utility/converters.test.ts index a903a72d..59a8801d 100644 --- a/utility/converters.test.ts +++ b/utility/converters.test.ts @@ -13,9 +13,9 @@ describe("converters", () => { {name: "Kunde",description:"",options:["Mus","Ræv"]} ], valueVariables: [ - {name: "Sukker", description: "", minVal: 0,maxVal: 1000}, - {name: "Peber", description: "", minVal: 0,maxVal: 1000}, - {name: "Hvedemel", description: "", minVal: 0,maxVal: 1000} + {discrete: true, name: "Sukker", description: "", minVal: 0, maxVal: 1000}, + {discrete: true, name: "Peber", description: "", minVal: 0, maxVal: 1000}, + {discrete: false, name: "Hvedemel", description: "", minVal: 0.0, maxVal: 1000.8} ], optimizerConfig: { baseEstimator: "GP", @@ -33,7 +33,8 @@ describe("converters", () => { describe("calculateSpace", () => { it("should convert space to proper output format", () => { const space = calculateSpace(sampleExperiment) - expect(space).toContainEqual({from: 0, name: "Sukker", to: 1000, type: "numeric"}) + expect(space).toContainEqual({type: "discrete", from: 0, name: "Sukker", to: 1000}) + expect(space).toContainEqual({type: "continuous", from: 0, name: "Hvedemel", to: 1000.8}) }) }) diff --git a/utility/converters.ts b/utility/converters.ts index 0c649855..bbee5f10 100644 --- a/utility/converters.ts +++ b/utility/converters.ts @@ -2,10 +2,12 @@ import { ExperimentData } from "../openapi" import { CategoricalVariableType, DataPointType, ExperimentType, ScoreDataPointType, SpaceType, ValueVariableType } from "../types/common" export const calculateSpace = (experiment: ExperimentType): SpaceType => { - const numeric: SpaceType = experiment.valueVariables.map(v => { return {type: "numeric", name: v.name, from: Number(v.minVal), to: Number(v.maxVal)}}) - const categorial: SpaceType = experiment.categoricalVariables.map((v) => { return {type: "category", name: v.name, categories: v.options}}) - return numeric.concat(categorial) - } + const discrete: SpaceType = experiment.valueVariables.filter(v => v.discrete).map(v => { return {type: "discrete", name: v.name, from: Number(v.minVal), to: Number(v.maxVal)} }) + const continuous: SpaceType = experiment.valueVariables.filter(v => !v.discrete).map(v => { return {type: "continuous", name: v.name, from: Number(v.minVal), to: Number(v.maxVal)} }) + const categorial: SpaceType = experiment.categoricalVariables.map((v) => { return {type: "category", name: v.name, categories: v.options} }) + return discrete.concat(continuous, categorial) +} + const numPat = / [0-9] + / export const calculateData = (categorialValues: CategoricalVariableType[], numericValues: ValueVariableType[], dataPoints: DataPointType[][]): ExperimentData[] => { return dataPoints.map((run):ExperimentData => ({xi: run.filter(it => it.name !== "score").map(it => numericValues.find(p => p.name === it.name) ? Number(it.value) : it.value), yi: Number((run.filter(it => it.name === "score")[0] as ScoreDataPointType).value[0])}))