mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-09-11 12:30:25 +08:00
@@ -0,0 +1 @@
|
||||
optuna_dashboard/static/components/PlotlyDarkMode.ts
|
||||
@@ -1,25 +1,58 @@
|
||||
import React, { FC } from "react"
|
||||
import React, { FC, useMemo, useState, useEffect } from "react"
|
||||
import { RecoilRoot } from "recoil"
|
||||
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
|
||||
import { SnackbarProvider } from "notistack"
|
||||
import { createTheme, useMediaQuery, ThemeProvider, Box } from "@mui/material"
|
||||
|
||||
import { StudyDetail } from "./StudyDetail"
|
||||
import { StudyList } from "./StudyList"
|
||||
|
||||
export const App: FC = () => {
|
||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)")
|
||||
const [colorMode, setColorMode] = useState<"light" | "dark">("light")
|
||||
useEffect(() => {
|
||||
setColorMode(prefersDarkMode ? "dark" : "light")
|
||||
}, [prefersDarkMode])
|
||||
const theme = useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: colorMode,
|
||||
},
|
||||
}),
|
||||
[colorMode]
|
||||
)
|
||||
const toggleColorMode = () => {
|
||||
setColorMode(colorMode === "dark" ? "light" : "dark")
|
||||
}
|
||||
|
||||
return (
|
||||
<RecoilRoot>
|
||||
<SnackbarProvider maxSnack={3}>
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route
|
||||
path={URL_PREFIX + "/studies/:studyId"}
|
||||
children={<StudyDetail />}
|
||||
/>
|
||||
<Route path={URL_PREFIX + "/"} children={<StudyList />} />
|
||||
</Switch>
|
||||
</Router>
|
||||
</SnackbarProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: colorMode === "dark" ? "#121212" : "#ffffff",
|
||||
width: "100%",
|
||||
minHeight: "100vh",
|
||||
paddingBottom: theme.spacing(2),
|
||||
}}
|
||||
>
|
||||
<SnackbarProvider maxSnack={3}>
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route
|
||||
path={URL_PREFIX + "/studies/:studyId"}
|
||||
children={<StudyDetail toggleColorMode={toggleColorMode} />}
|
||||
/>
|
||||
<Route
|
||||
path={URL_PREFIX + "/"}
|
||||
children={<StudyList toggleColorMode={toggleColorMode} />}
|
||||
/>
|
||||
</Switch>
|
||||
</Router>
|
||||
</SnackbarProvider>
|
||||
</Box>
|
||||
</ThemeProvider>
|
||||
</RecoilRoot>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
SelectChangeEvent,
|
||||
useTheme,
|
||||
} from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-edf"
|
||||
|
||||
@@ -25,9 +26,9 @@ export const Edf: FC<{
|
||||
|
||||
useEffect(() => {
|
||||
if (study != null) {
|
||||
plotEdf(study, objectiveId)
|
||||
plotEdf(study, objectiveId, theme.palette.mode)
|
||||
}
|
||||
}, [study, objectiveId])
|
||||
}, [study, objectiveId, theme.palette.mode])
|
||||
return (
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={3}>
|
||||
@@ -63,7 +64,7 @@ export const Edf: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const plotEdf = (study: StudyDetail, objectiveId: number) => {
|
||||
const plotEdf = (study: StudyDetail, objectiveId: number, mode: string) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
}
|
||||
@@ -95,6 +96,7 @@ const plotEdf = (study: StudyDetail, objectiveId: number) => {
|
||||
r: 50,
|
||||
b: 50,
|
||||
},
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
const values = completedTrials.map((t) => target(t))
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SelectChangeEvent,
|
||||
useTheme,
|
||||
} from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-history"
|
||||
|
||||
@@ -59,7 +60,8 @@ export const GraphHistory: FC<{
|
||||
xAxis,
|
||||
logScale,
|
||||
filterCompleteTrial,
|
||||
filterPrunedTrial
|
||||
filterPrunedTrial,
|
||||
theme.palette.mode
|
||||
)
|
||||
}
|
||||
}, [
|
||||
@@ -69,6 +71,7 @@ export const GraphHistory: FC<{
|
||||
xAxis,
|
||||
filterPrunedTrial,
|
||||
filterCompleteTrial,
|
||||
theme.palette.mode,
|
||||
])
|
||||
|
||||
return (
|
||||
@@ -171,7 +174,8 @@ const plotHistory = (
|
||||
xAxis: string,
|
||||
logScale: boolean,
|
||||
filterCompleteTrial: boolean,
|
||||
filterPrunedTrial: boolean
|
||||
filterPrunedTrial: boolean,
|
||||
mode: string
|
||||
) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
@@ -191,6 +195,7 @@ const plotHistory = (
|
||||
type: xAxis === "number" ? "linear" : "date",
|
||||
},
|
||||
showlegend: false,
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
let filteredTrials = study.trials.filter(
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "@mui/material"
|
||||
|
||||
import { getParamImportances } from "../apiClient"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
const plotDomId = "graph-hyperparameter-importances"
|
||||
|
||||
// To match colors used by plot_param_importances in optuna.
|
||||
@@ -59,13 +60,13 @@ export const GraphHyperparameterImportances: FC<{
|
||||
studyId,
|
||||
objectiveId
|
||||
)
|
||||
plotParamImportances(paramsImportanceData)
|
||||
plotParamImportances(paramsImportanceData, theme.palette.mode)
|
||||
}
|
||||
|
||||
if (numOfTrials > 0) {
|
||||
fetchAndPlotParamImportances(studyId, objectiveId)
|
||||
}
|
||||
}, [numOfTrials, objectiveId])
|
||||
}, [numOfTrials, objectiveId, theme.palette.mode])
|
||||
|
||||
return (
|
||||
<Grid container direction="row">
|
||||
@@ -102,7 +103,10 @@ export const GraphHyperparameterImportances: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const plotParamImportances = (paramsImportanceData: ParamImportances) => {
|
||||
const plotParamImportances = (
|
||||
paramsImportanceData: ParamImportances,
|
||||
mode: string
|
||||
) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
}
|
||||
@@ -131,6 +135,7 @@ const plotParamImportances = (paramsImportanceData: ParamImportances) => {
|
||||
b: 50,
|
||||
},
|
||||
showlegend: false,
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
const plotData: Partial<plotly.PlotData>[] = [
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import * as plotly from "plotly.js-dist"
|
||||
import React, { FC, useEffect } from "react"
|
||||
import { Grid, Typography } from "@mui/material"
|
||||
import { Grid, Typography, useTheme } from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-intermediate-values"
|
||||
|
||||
export const GraphIntermediateValues: FC<{
|
||||
trials: Trial[]
|
||||
}> = ({ trials = [] }) => {
|
||||
const theme = useTheme()
|
||||
useEffect(() => {
|
||||
plotIntermediateValue(trials)
|
||||
}, [trials])
|
||||
plotIntermediateValue(trials, theme.palette.mode)
|
||||
}, [trials, theme.palette.mode])
|
||||
return (
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={3}>
|
||||
@@ -27,7 +29,7 @@ export const GraphIntermediateValues: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const plotIntermediateValue = (trials: Trial[]) => {
|
||||
const plotIntermediateValue = (trials: Trial[], mode: string) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
}
|
||||
@@ -39,6 +41,7 @@ const plotIntermediateValue = (trials: Trial[]) => {
|
||||
r: 50,
|
||||
b: 0,
|
||||
},
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
if (trials.length === 0) {
|
||||
plotly.react(plotDomId, [], layout)
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
SelectChangeEvent,
|
||||
useTheme,
|
||||
} from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-parallel-coordinate"
|
||||
|
||||
@@ -25,16 +26,16 @@ export const GraphParallelCoordinate: FC<{
|
||||
|
||||
useEffect(() => {
|
||||
if (study !== null) {
|
||||
plotCoordinate(study, objectiveId)
|
||||
plotCoordinate(study, objectiveId, theme.palette.mode)
|
||||
}
|
||||
}, [study, objectiveId])
|
||||
}, [study, objectiveId, theme.palette.mode])
|
||||
|
||||
return (
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={3}>
|
||||
<Grid container direction="column">
|
||||
<Typography variant="h6" sx={{ margin: "1em 0" }}>
|
||||
Parallel coordinate
|
||||
Parallel Coordinate
|
||||
</Typography>
|
||||
{study !== null && study.directions.length !== 1 ? (
|
||||
<FormControl
|
||||
@@ -64,7 +65,11 @@ export const GraphParallelCoordinate: FC<{
|
||||
)
|
||||
}
|
||||
|
||||
const plotCoordinate = (study: StudyDetail, objectiveId: number) => {
|
||||
const plotCoordinate = (
|
||||
study: StudyDetail,
|
||||
objectiveId: number,
|
||||
mode: string
|
||||
) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
}
|
||||
@@ -76,6 +81,7 @@ const plotCoordinate = (study: StudyDetail, objectiveId: number) => {
|
||||
r: 50,
|
||||
b: 0,
|
||||
},
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
if (study.trials.length === 0) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
SelectChangeEvent,
|
||||
useTheme,
|
||||
} from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-pareto-front"
|
||||
|
||||
@@ -30,9 +31,9 @@ export const GraphParetoFront: FC<{
|
||||
|
||||
useEffect(() => {
|
||||
if (study != null) {
|
||||
plotParetoFront(study, objectiveXId, objectiveYId)
|
||||
plotParetoFront(study, objectiveXId, objectiveYId, theme.palette.mode)
|
||||
}
|
||||
}, [study, objectiveXId, objectiveYId])
|
||||
}, [study, objectiveXId, objectiveYId, theme.palette.mode])
|
||||
|
||||
return (
|
||||
<Grid container direction="row">
|
||||
@@ -87,7 +88,8 @@ export const GraphParetoFront: FC<{
|
||||
const plotParetoFront = (
|
||||
study: StudyDetail,
|
||||
objectiveXId: number,
|
||||
objectiveYId: number
|
||||
objectiveYId: number,
|
||||
mode: string
|
||||
) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
@@ -100,6 +102,7 @@ const plotParetoFront = (
|
||||
r: 50,
|
||||
b: 0,
|
||||
},
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
const trials: Trial[] = study ? study.trials : []
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
SelectChangeEvent,
|
||||
useTheme,
|
||||
} from "@mui/material"
|
||||
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
|
||||
|
||||
const plotDomId = "graph-slice"
|
||||
|
||||
@@ -38,8 +39,15 @@ export const GraphSlice: FC<{
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
plotSlice(trials, objectiveId, selected, logXScale, logYScale)
|
||||
}, [trials, objectiveId, selected, logXScale, logYScale])
|
||||
plotSlice(
|
||||
trials,
|
||||
objectiveId,
|
||||
selected,
|
||||
logXScale,
|
||||
logYScale,
|
||||
theme.palette.mode
|
||||
)
|
||||
}, [trials, objectiveId, selected, logXScale, logYScale, theme.palette.mode])
|
||||
|
||||
const handleObjectiveChange = (event: SelectChangeEvent<number>) => {
|
||||
setObjectiveId(event.target.value as number)
|
||||
@@ -126,7 +134,8 @@ const plotSlice = (
|
||||
objectiveId: number,
|
||||
selected: string | null,
|
||||
logXScale: boolean,
|
||||
logYScale: boolean
|
||||
logYScale: boolean,
|
||||
mode: string
|
||||
) => {
|
||||
if (document.getElementById(plotDomId) === null) {
|
||||
return
|
||||
@@ -142,27 +151,17 @@ const plotSlice = (
|
||||
xaxis: {
|
||||
title: selected || "",
|
||||
type: logXScale ? "log" : "linear",
|
||||
zerolinecolor: "#f2f5fa",
|
||||
zerolinewidth: 1.5,
|
||||
linecolor: "#f2f5fa",
|
||||
linewidth: 5,
|
||||
gridcolor: "#f2f5fa",
|
||||
gridwidth: 1,
|
||||
automargin: true,
|
||||
},
|
||||
yaxis: {
|
||||
title: "Objective Values",
|
||||
type: logYScale ? "log" : "linear",
|
||||
zerolinecolor: "#f2f5fa",
|
||||
zerolinewidth: 2,
|
||||
linecolor: "#f2f5fa",
|
||||
linewidth: 5,
|
||||
gridcolor: "#f2f5fa",
|
||||
gridwidth: 1,
|
||||
automargin: true,
|
||||
},
|
||||
plot_bgcolor: "#E5ecf6",
|
||||
showlegend: false,
|
||||
template: mode === "dark" ? plotlyDarkTemplate : {},
|
||||
}
|
||||
|
||||
const filteredTrials = trials.filter(
|
||||
@@ -195,23 +194,12 @@ const plotSlice = (
|
||||
x: valuesNum,
|
||||
y: objectiveValues,
|
||||
mode: "markers",
|
||||
marker: {
|
||||
color: "#185799",
|
||||
},
|
||||
},
|
||||
]
|
||||
layout["xaxis"] = {
|
||||
title: selected,
|
||||
type: logXScale ? "log" : "linear",
|
||||
zerolinecolor: "#f2f5fa",
|
||||
zerolinewidth: 1.5,
|
||||
linecolor: "#f2f5fa",
|
||||
linewidth: 5,
|
||||
gridcolor: "#f2f5fa",
|
||||
gridwidth: 1,
|
||||
tickfont: {
|
||||
color: "#000000",
|
||||
},
|
||||
automargin: true, // Otherwise the label is outside of the plot
|
||||
}
|
||||
plotly.react(plotDomId, trace, layout)
|
||||
@@ -228,23 +216,12 @@ const plotSlice = (
|
||||
x: valuesCategorical,
|
||||
y: objectiveValues,
|
||||
mode: "markers",
|
||||
marker: {
|
||||
color: "#185799",
|
||||
},
|
||||
},
|
||||
]
|
||||
layout["xaxis"] = {
|
||||
title: selected,
|
||||
type: logXScale ? "log" : "linear",
|
||||
zerolinecolor: "#f2f5fa",
|
||||
zerolinewidth: 1.5,
|
||||
linecolor: "#f2f5fa",
|
||||
linewidth: 5,
|
||||
gridcolor: "#f2f5fa",
|
||||
gridwidth: 1,
|
||||
tickfont: {
|
||||
color: "#000000",
|
||||
},
|
||||
tickvals: tickvals,
|
||||
ticktext: vocabArr,
|
||||
automargin: true, // Otherwise the label is outside of the plot
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -26,6 +26,8 @@ import FormControlLabel from "@mui/material/FormControlLabel"
|
||||
import MuiDialogTitle from "@mui/material/DialogTitle"
|
||||
import MuiDialogContent from "@mui/material/DialogContent"
|
||||
import CloseIcon from "@mui/icons-material/Close"
|
||||
import Brightness4Icon from "@mui/icons-material/Brightness4"
|
||||
import Brightness7Icon from "@mui/icons-material/Brightness7"
|
||||
|
||||
import { DataGridColumn, DataGrid } from "./DataGrid"
|
||||
import { GraphParallelCoordinate } from "./GraphParallelCoordinate"
|
||||
@@ -51,7 +53,9 @@ export const useStudyDetailValue = (studyId: number): StudyDetail | null => {
|
||||
return studyDetails[studyId] || null
|
||||
}
|
||||
|
||||
export const StudyDetail: FC = () => {
|
||||
export const StudyDetail: FC<{
|
||||
toggleColorMode: () => void
|
||||
}> = ({ toggleColorMode }) => {
|
||||
const theme = useTheme()
|
||||
const action = actionCreator()
|
||||
const { studyId } = useParams<ParamTypes>()
|
||||
@@ -251,6 +255,18 @@ export const StudyDetail: FC = () => {
|
||||
<Toolbar>
|
||||
<Typography variant="h6">{APP_BAR_TITLE}</Typography>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
toggleColorMode()
|
||||
}}
|
||||
color="inherit"
|
||||
>
|
||||
{theme.palette.mode === "dark" ? (
|
||||
<Brightness7Icon />
|
||||
) : (
|
||||
<Brightness4Icon />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton color="inherit" onClick={handleClickOpen}>
|
||||
<Settings />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { FC, useEffect } from "react"
|
||||
import React, { FC, useEffect, useMemo } from "react"
|
||||
import { useRecoilValue } from "recoil"
|
||||
import { Link } from "react-router-dom"
|
||||
import {
|
||||
@@ -31,8 +31,12 @@ import { Add, AddBox, Delete, Refresh, Remove } from "@mui/icons-material"
|
||||
import { actionCreator } from "../action"
|
||||
import { DataGrid, DataGridColumn } from "./DataGrid"
|
||||
import { studySummariesState } from "../state"
|
||||
import Brightness7Icon from "@mui/icons-material/Brightness7"
|
||||
import Brightness4Icon from "@mui/icons-material/Brightness4"
|
||||
|
||||
export const StudyList: FC = () => {
|
||||
export const StudyList: FC<{
|
||||
toggleColorMode: () => void
|
||||
}> = ({ toggleColorMode }) => {
|
||||
const theme = useTheme()
|
||||
|
||||
const [newStudySelectionAnchorEl, setNewStudySelectionAnchorEl] =
|
||||
@@ -55,6 +59,13 @@ export const StudyList: FC = () => {
|
||||
const [directions, setDirections] = React.useState<StudyDirection[]>([
|
||||
"minimize",
|
||||
])
|
||||
const linkColor = useMemo(
|
||||
() =>
|
||||
theme.palette.mode === "dark"
|
||||
? theme.palette.primary.light
|
||||
: theme.palette.primary.dark,
|
||||
[theme.palette.mode]
|
||||
)
|
||||
|
||||
const action = actionCreator()
|
||||
const studies = useRecoilValue<StudySummary[]>(studySummariesState)
|
||||
@@ -78,7 +89,10 @@ export const StudyList: FC = () => {
|
||||
label: "Name",
|
||||
sortable: true,
|
||||
toCellValue: (i) => (
|
||||
<Link to={`${URL_PREFIX}/studies/${studies[i].study_id}`}>
|
||||
<Link
|
||||
to={`${URL_PREFIX}/studies/${studies[i].study_id}`}
|
||||
style={{ color: linkColor }}
|
||||
>
|
||||
{studies[i].study_name}
|
||||
</Link>
|
||||
),
|
||||
@@ -212,6 +226,18 @@ export const StudyList: FC = () => {
|
||||
<Toolbar>
|
||||
<Typography variant="h6">{APP_BAR_TITLE}</Typography>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
toggleColorMode()
|
||||
}}
|
||||
color="inherit"
|
||||
>
|
||||
{theme.palette.mode === "dark" ? (
|
||||
<Brightness7Icon />
|
||||
) : (
|
||||
<Brightness4Icon />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
aria-controls="menu-appbar"
|
||||
aria-haspopup="true"
|
||||
|
||||
Reference in New Issue
Block a user