Merge pull request #358 from c-bata/combine-history-intermediate-buttons

Add global state filters for History and IntermediateValue plots
This commit is contained in:
Masashi Shibata
2023-01-12 09:32:36 +09:00
committed by GitHub
6 changed files with 265 additions and 139 deletions
+57 -44
View File
@@ -26,9 +26,13 @@ const plotDomId = "graph-history"
export const GraphHistory: FC<{
study: StudyDetail | null
}> = ({ study = null }) => {
betaLogScale?: boolean
betaIncludePruned?: boolean
}> = ({ study, betaLogScale, betaIncludePruned }) => {
const theme = useTheme()
const [xAxis, setXAxis] = useState<string>("number")
const [xAxis, setXAxis] = useState<
"number" | "datetime_start" | "datetime_complete"
>("number")
const [logScale, setLogScale] = useState<boolean>(false)
const [filterCompleteTrial, setFilterCompleteTrial] = useState<boolean>(false)
const [filterPrunedTrial, setFilterPrunedTrial] = useState<boolean>(false)
@@ -38,7 +42,7 @@ export const GraphHistory: FC<{
study,
[selected],
filterCompleteTrial,
filterPrunedTrial
betaIncludePruned === undefined ? filterPrunedTrial : !betaIncludePruned
)
useEffect(() => {
@@ -48,7 +52,7 @@ export const GraphHistory: FC<{
study.directions,
selected,
xAxis,
logScale,
betaLogScale === undefined ? logScale : betaLogScale,
theme.palette.mode
)
}
@@ -57,9 +61,8 @@ export const GraphHistory: FC<{
study?.directions,
selected,
logScale,
betaLogScale,
xAxis,
filterPrunedTrial,
filterCompleteTrial,
theme.palette.mode,
])
@@ -68,7 +71,13 @@ export const GraphHistory: FC<{
}
const handleXAxisChange = (e: ChangeEvent<HTMLInputElement>) => {
setXAxis(e.target.value)
if (e.target.value === "number") {
setXAxis("number")
} else if (e.target.value === "datetime_start") {
setXAxis("datetime_start")
} else if (e.target.value === "datetime_complete") {
setXAxis("datetime_complete")
}
}
const handleLogScaleChange = (e: ChangeEvent<HTMLInputElement>) => {
@@ -113,42 +122,46 @@ export const GraphHistory: FC<{
</Select>
</FormControl>
) : null}
<FormControl
component="fieldset"
sx={{ marginBottom: theme.spacing(2) }}
>
<FormLabel component="legend">Log y scale:</FormLabel>
<Switch
checked={logScale}
onChange={handleLogScaleChange}
value="enable"
/>
</FormControl>
<FormControl
component="fieldset"
sx={{ marginBottom: theme.spacing(2) }}
>
<FormLabel component="legend">Filter state:</FormLabel>
<FormControlLabel
control={
<Checkbox
checked={!filterCompleteTrial}
onChange={handleFilterCompleteChange}
/>
}
label="Complete"
/>
<FormControlLabel
control={
<Checkbox
checked={!filterPrunedTrial}
disabled={!study?.has_intermediate_values}
onChange={handleFilterPrunedChange}
/>
}
label="Pruned"
/>
</FormControl>
{betaLogScale === undefined ? (
<FormControl
component="fieldset"
sx={{ marginBottom: theme.spacing(2) }}
>
<FormLabel component="legend">Log y scale:</FormLabel>
<Switch
checked={logScale}
onChange={handleLogScaleChange}
value="enable"
/>
</FormControl>
) : null}
{betaIncludePruned === undefined ? (
<FormControl
component="fieldset"
sx={{ marginBottom: theme.spacing(2) }}
>
<FormLabel component="legend">Filter state:</FormLabel>
<FormControlLabel
control={
<Checkbox
checked={!filterCompleteTrial}
onChange={handleFilterCompleteChange}
/>
}
label="Complete"
/>
<FormControlLabel
control={
<Checkbox
checked={!filterPrunedTrial}
disabled={!study?.has_intermediate_values}
onChange={handleFilterPrunedChange}
/>
}
label="Pruned"
/>
</FormControl>
) : null}
<FormControl
component="fieldset"
sx={{ marginBottom: theme.spacing(2) }}
@@ -189,7 +202,7 @@ const plotHistory = (
trials: Trial[],
directions: StudyDirection[],
target: Target,
xAxis: string,
xAxis: "number" | "datetime_start" | "datetime_complete",
logScale: boolean,
mode: string
) => {
@@ -13,7 +13,6 @@ import {
Card,
CardContent,
} from "@mui/material"
import Grid2 from "@mui/material/Unstable_Grid2"
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
import { actionCreator } from "../action"
@@ -47,16 +46,14 @@ export const GraphHyperparameterImportanceBeta: FC<{
}, [nObjectives, importances, theme.palette.mode])
return (
<Grid2 xs={6}>
<Card>
<CardContent>
<Typography variant="h6" sx={{ margin: "1em 0", fontWeight: 600 }}>
Hyperparameter Importance
</Typography>
<Box id={plotDomId} sx={{ height: graphHeight }} />
</CardContent>
</Card>
</Grid2>
<Card>
<CardContent>
<Typography variant="h6" sx={{ margin: "1em 0", fontWeight: 600 }}>
Hyperparameter Importance
</Typography>
<Box id={plotDomId} sx={{ height: graphHeight }} />
</CardContent>
</Card>
)
}
@@ -9,11 +9,42 @@ import {
Grid,
Typography,
useTheme,
CardContent,
Card,
} from "@mui/material"
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
const plotDomId = "graph-intermediate-values"
export const GraphIntermediateValuesBeta: FC<{
trials: Trial[]
includePruned: boolean
logScale: boolean
}> = ({ trials, includePruned, logScale }) => {
const theme = useTheme()
useEffect(() => {
plotIntermediateValue(
trials,
theme.palette.mode,
false,
!includePruned,
logScale
)
}, [trials, theme.palette.mode, false, includePruned, logScale])
return (
<Card>
<CardContent>
<Typography variant="h6" sx={{ margin: "1em 0", fontWeight: 600 }}>
Intermediate values
</Typography>
<Box id={plotDomId} sx={{ height: "450px" }} />
</CardContent>
</Card>
)
}
export const GraphIntermediateValues: FC<{
trials: Trial[]
}> = ({ trials = [] }) => {
@@ -26,7 +57,8 @@ export const GraphIntermediateValues: FC<{
trials,
theme.palette.mode,
filterCompleteTrial,
filterPrunedTrial
filterPrunedTrial,
false
)
}, [trials, theme.palette.mode, filterCompleteTrial, filterPrunedTrial])
@@ -86,7 +118,8 @@ const plotIntermediateValue = (
trials: Trial[],
mode: string,
filterCompleteTrial: boolean,
filterPrunedTrial: boolean
filterPrunedTrial: boolean,
logScale: boolean
) => {
if (document.getElementById(plotDomId) === null) {
return
@@ -99,6 +132,14 @@ const plotIntermediateValue = (
r: 50,
b: 0,
},
yaxis: {
title: "Objective Value",
type: logScale ? "log" : "linear",
},
xaxis: {
title: "Step",
type: "linear",
},
template: mode === "dark" ? plotlyDarkTemplate : {},
}
if (trials.length === 0) {
@@ -165,7 +165,7 @@ export const StudyDetail: FC<{
}}
>
<CardContent>
<GraphHistory study={studyDetail} />
<GraphHistory study={studyDetail} isBeta={false} />
</CardContent>
</Card>
) : null}
@@ -13,28 +13,21 @@ import Grid2 from "@mui/material/Unstable_Grid2"
import ChevronRightIcon from "@mui/icons-material/ChevronRight"
import HomeIcon from "@mui/icons-material/Home"
import { GraphHistory } from "./GraphHistory"
import { StudyNote } from "./Note"
import { actionCreator } from "../action"
import {
reloadIntervalState,
useStudyDetailValue,
useStudyDirections,
useStudyName,
useStudySummaryValue,
} from "../state"
import { TrialTable } from "./TrialTable"
import { AppDrawer, PageId } from "./AppDrawer"
import { GraphParallelCoordinate } from "./GraphParallelCoordinate"
import { Contour } from "./GraphContour"
import { GraphHyperparameterImportanceBeta } from "./GraphHyperparameterImportances"
import { GraphSlice } from "./GraphSlice"
import { GraphParetoFront } from "./GraphParetoFront"
import { DataGrid, DataGridColumn } from "./DataGrid"
import { GraphIntermediateValues } from "./GraphIntermediateValues"
import { GraphEdfBeta } from "./GraphEdf"
import { TrialList } from "./TrialList"
import { BestTrialsCard } from "./BestTrialsCard"
import { StudyHistory } from "./StudyHistory"
interface ParamTypes {
studyId: string
@@ -55,10 +48,7 @@ export const StudyDetailBeta: FC<{
const studyId = useURLVars()
const studyDetail = useStudyDetailValue(studyId)
const reloadInterval = useRecoilValue<number>(reloadIntervalState)
const studySummary = useStudySummaryValue(studyId)
const directions = useStudyDirections(studyId)
const studyName = useStudyName(studyId)
const userAttrs = studySummary?.user_attrs || []
const title =
studyName !== null ? `${studyName} (id=${studyId})` : `Study #${studyId}`
@@ -77,78 +67,9 @@ export const StudyDetailBeta: FC<{
return () => clearInterval(intervalId)
}, [reloadInterval, studyDetail, page])
const userAttrColumns: DataGridColumn<Attribute>[] = [
{ field: "key", label: "Key", sortable: true },
{ field: "value", label: "Value", sortable: true },
]
const trials: Trial[] = studyDetail?.trials || []
let content = null
if (page === "history") {
content = (
<Box sx={{ display: "flex", width: "100%", flexDirection: "column" }}>
{directions !== null && directions.length > 1 ? (
<Card sx={{ margin: theme.spacing(2) }}>
<CardContent>
<GraphParetoFront study={studyDetail} />
</CardContent>
</Card>
) : null}
<Card
sx={{
margin: theme.spacing(2),
}}
>
<CardContent>
<GraphHistory study={studyDetail} />
</CardContent>
</Card>
{studyDetail !== null &&
studyDetail.directions.length == 1 &&
studyDetail.has_intermediate_values ? (
<Card sx={{ margin: theme.spacing(2) }}>
<CardContent>
<GraphIntermediateValues trials={trials} />
</CardContent>
</Card>
) : null}
<Grid2 container spacing={2} sx={{ padding: theme.spacing(0, 2) }}>
<GraphHyperparameterImportanceBeta
studyId={studyId}
study={studyDetail}
graphHeight="450px"
/>
<Grid2 xs={6} spacing={2}>
<BestTrialsCard studyDetail={studyDetail} />
</Grid2>
<Grid2 xs={6}>
<Card>
<CardContent
sx={{
display: "flex",
flexDirection: "column",
}}
>
<Typography
variant="h6"
sx={{ margin: "1em 0", fontWeight: 600 }}
>
Study User Attributes
</Typography>
<DataGrid<Attribute>
columns={userAttrColumns}
rows={userAttrs}
keyField={"key"}
dense={true}
initialRowsPerPage={5}
rowsPerPageOption={[5, 10, { label: "All", value: -1 }]}
/>
</CardContent>
</Card>
</Grid2>
</Grid2>
</Box>
)
content = <StudyHistory studyId={studyId} />
} else if (page === "analytics") {
content = (
<Box sx={{ display: "flex", width: "100%", flexDirection: "column" }}>
@@ -0,0 +1,154 @@
import React, { ChangeEvent, FC, useState } from "react"
import {
Box,
Card,
CardContent,
FormControl,
Switch,
Typography,
useTheme,
} from "@mui/material"
import { GraphParetoFront } from "./GraphParetoFront"
import { GraphHistory } from "./GraphHistory"
import { GraphIntermediateValuesBeta } from "./GraphIntermediateValues"
import Grid2 from "@mui/material/Unstable_Grid2"
import { DataGrid, DataGridColumn } from "./DataGrid"
import { GraphHyperparameterImportanceBeta } from "./GraphHyperparameterImportances"
import { BestTrialsCard } from "./BestTrialsCard"
import {
useStudyDetailValue,
useStudyDirections,
useStudySummaryValue,
} from "../state"
import FormControlLabel from "@mui/material/FormControlLabel"
export const StudyHistory: FC<{ studyId: number }> = ({ studyId }) => {
const theme = useTheme()
const directions = useStudyDirections(studyId)
const studySummary = useStudySummaryValue(studyId)
const studyDetail = useStudyDetailValue(studyId)
const [logScale, setLogScale] = useState<boolean>(false)
const [includePruned, setIncludePruned] = useState<boolean>(true)
const handleLogScaleChange = (e: ChangeEvent<HTMLInputElement>) => {
setLogScale(!logScale)
}
const handleIncludePrunedChange = (e: ChangeEvent<HTMLInputElement>) => {
setIncludePruned(!includePruned)
}
const userAttrs = studySummary?.user_attrs || []
const userAttrColumns: DataGridColumn<Attribute>[] = [
{ field: "key", label: "Key", sortable: true },
{ field: "value", label: "Value", sortable: true },
]
const trials: Trial[] = studyDetail?.trials || []
return (
<Box sx={{ display: "flex", width: "100%", flexDirection: "column" }}>
<FormControl
component="fieldset"
sx={{
display: "flex",
flexDirection: "row",
justifyContent: "flex-end",
padding: theme.spacing(2),
}}
>
<FormControlLabel
control={
<Switch
checked={logScale}
onChange={handleLogScaleChange}
value="enable"
/>
}
label="Log y scale"
/>
<FormControlLabel
control={
<Switch
checked={
studyDetail
? studyDetail.has_intermediate_values && includePruned
: false
}
onChange={handleIncludePrunedChange}
disabled={!studyDetail?.has_intermediate_values}
value="enable"
/>
}
label="Include PRUNED trials"
/>
</FormControl>
{directions !== null && directions.length > 1 ? (
<Card sx={{ margin: theme.spacing(2) }}>
<CardContent>
<GraphParetoFront study={studyDetail} />
</CardContent>
</Card>
) : null}
<Card
sx={{
margin: theme.spacing(2),
}}
>
<CardContent>
<GraphHistory
study={studyDetail}
betaIncludePruned={includePruned}
betaLogScale={logScale}
/>
</CardContent>
</Card>
<Grid2 container spacing={2} sx={{ padding: theme.spacing(0, 2) }}>
{studyDetail !== null &&
studyDetail.directions.length == 1 &&
studyDetail.has_intermediate_values ? (
<Grid2 xs={6}>
<GraphIntermediateValuesBeta
trials={trials}
includePruned={includePruned}
logScale={logScale}
/>
</Grid2>
) : null}
<Grid2 xs={6}>
<GraphHyperparameterImportanceBeta
studyId={studyId}
study={studyDetail}
graphHeight="450px"
/>
</Grid2>
<Grid2 xs={6} spacing={2}>
<BestTrialsCard studyDetail={studyDetail} />
</Grid2>
<Grid2 xs={6}>
<Card>
<CardContent
sx={{
display: "flex",
flexDirection: "column",
}}
>
<Typography
variant="h6"
sx={{ margin: "1em 0", fontWeight: 600 }}
>
Study User Attributes
</Typography>
<DataGrid<Attribute>
columns={userAttrColumns}
rows={userAttrs}
keyField={"key"}
dense={true}
initialRowsPerPage={5}
rowsPerPageOption={[5, 10, { label: "All", value: -1 }]}
/>
</CardContent>
</Card>
</Grid2>
</Grid2>
</Box>
)
}