diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..baa31f10
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+optuna_dashboard/static/components/PlotlyDarkMode.ts
\ No newline at end of file
diff --git a/optuna_dashboard/static/components/App.tsx b/optuna_dashboard/static/components/App.tsx
index e0c3ae5d..ca3c5327 100644
--- a/optuna_dashboard/static/components/App.tsx
+++ b/optuna_dashboard/static/components/App.tsx
@@ -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 (
-
-
-
- }
- />
- } />
-
-
-
+
+
+
+
+
+ }
+ />
+ }
+ />
+
+
+
+
+
)
}
diff --git a/optuna_dashboard/static/components/GraphEdf.tsx b/optuna_dashboard/static/components/GraphEdf.tsx
index 57cb81fc..f799e04a 100644
--- a/optuna_dashboard/static/components/GraphEdf.tsx
+++ b/optuna_dashboard/static/components/GraphEdf.tsx
@@ -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 (
@@ -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))
diff --git a/optuna_dashboard/static/components/GraphHistory.tsx b/optuna_dashboard/static/components/GraphHistory.tsx
index 686dd75b..9607c63f 100644
--- a/optuna_dashboard/static/components/GraphHistory.tsx
+++ b/optuna_dashboard/static/components/GraphHistory.tsx
@@ -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(
diff --git a/optuna_dashboard/static/components/GraphHyperparameterImportances.tsx b/optuna_dashboard/static/components/GraphHyperparameterImportances.tsx
index 296f71be..f2a8454c 100644
--- a/optuna_dashboard/static/components/GraphHyperparameterImportances.tsx
+++ b/optuna_dashboard/static/components/GraphHyperparameterImportances.tsx
@@ -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 (
@@ -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[] = [
diff --git a/optuna_dashboard/static/components/GraphIntermediateValues.tsx b/optuna_dashboard/static/components/GraphIntermediateValues.tsx
index 28bc3b0f..09f4c146 100644
--- a/optuna_dashboard/static/components/GraphIntermediateValues.tsx
+++ b/optuna_dashboard/static/components/GraphIntermediateValues.tsx
@@ -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 (
@@ -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)
diff --git a/optuna_dashboard/static/components/GraphParallelCoordinate.tsx b/optuna_dashboard/static/components/GraphParallelCoordinate.tsx
index 5c43b524..2b1f6ef4 100644
--- a/optuna_dashboard/static/components/GraphParallelCoordinate.tsx
+++ b/optuna_dashboard/static/components/GraphParallelCoordinate.tsx
@@ -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 (
- Parallel coordinate
+ Parallel Coordinate
{study !== null && study.directions.length !== 1 ? (
{
+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) {
diff --git a/optuna_dashboard/static/components/GraphParetoFront.tsx b/optuna_dashboard/static/components/GraphParetoFront.tsx
index c60f450a..eeae1c6c 100644
--- a/optuna_dashboard/static/components/GraphParetoFront.tsx
+++ b/optuna_dashboard/static/components/GraphParetoFront.tsx
@@ -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 (
@@ -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 : []
diff --git a/optuna_dashboard/static/components/GraphSlice.tsx b/optuna_dashboard/static/components/GraphSlice.tsx
index 98d99050..b4a10198 100644
--- a/optuna_dashboard/static/components/GraphSlice.tsx
+++ b/optuna_dashboard/static/components/GraphSlice.tsx
@@ -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) => {
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
diff --git a/optuna_dashboard/static/components/PlotlyDarkMode.ts b/optuna_dashboard/static/components/PlotlyDarkMode.ts
new file mode 100644
index 00000000..f7d4d966
--- /dev/null
+++ b/optuna_dashboard/static/components/PlotlyDarkMode.ts
@@ -0,0 +1,8 @@
+import * as plotly from "plotly.js-dist"
+
+// Following template is extracted from the sdist of plotly Python library.
+// See https://github.com/plotly/plotly.py/blob/v5.6.0/packages/python/plotly/templategen/__init__.py and
+// https://github.com/plotly/plotly.py/blob/v5.6.0/packages/python/plotly/templategen/definitions.py
+
+//@ts-ignore
+export const plotlyDarkTemplate: Partial = {"data":{"bar":[{"error_x":{"color":"#f2f5fa"},"error_y":{"color":"#f2f5fa"},"marker":{"line":{"color":"rgb(17,17,17)","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"barpolar":[{"marker":{"line":{"color":"rgb(17,17,17)","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"carpet":[{"aaxis":{"endlinecolor":"#A2B1C6","gridcolor":"#506784","linecolor":"#506784","minorgridcolor":"#506784","startlinecolor":"#A2B1C6"},"baxis":{"endlinecolor":"#A2B1C6","gridcolor":"#506784","linecolor":"#506784","minorgridcolor":"#506784","startlinecolor":"#A2B1C6"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"heatmapgl":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmapgl"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter":[{"marker":{"line":{"color":"#283442"}},"type":"scatter"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"line":{"color":"#283442"}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#506784"},"line":{"color":"rgb(17,17,17)"}},"header":{"fill":{"color":"#2a3f5f"},"line":{"color":"rgb(17,17,17)"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#f2f5fa","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#f2f5fa"},"geo":{"bgcolor":"rgb(17,17,17)","lakecolor":"rgb(17,17,17)","landcolor":"rgb(17,17,17)","showlakes":true,"showland":true,"subunitcolor":"#506784"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"dark"},"paper_bgcolor":"rgb(17,17,17)","plot_bgcolor":"rgb(17,17,17)","polar":{"angularaxis":{"gridcolor":"#506784","linecolor":"#506784","ticks":""},"bgcolor":"rgb(17,17,17)","radialaxis":{"gridcolor":"#506784","linecolor":"#506784","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"rgb(17,17,17)","gridcolor":"#506784","gridwidth":2,"linecolor":"#506784","showbackground":true,"ticks":"","zerolinecolor":"#C8D4E3"},"yaxis":{"backgroundcolor":"rgb(17,17,17)","gridcolor":"#506784","gridwidth":2,"linecolor":"#506784","showbackground":true,"ticks":"","zerolinecolor":"#C8D4E3"},"zaxis":{"backgroundcolor":"rgb(17,17,17)","gridcolor":"#506784","gridwidth":2,"linecolor":"#506784","showbackground":true,"ticks":"","zerolinecolor":"#C8D4E3"}},"shapedefaults":{"line":{"color":"#f2f5fa"}},"sliderdefaults":{"bgcolor":"#C8D4E3","bordercolor":"rgb(17,17,17)","borderwidth":1,"tickwidth":0},"ternary":{"aaxis":{"gridcolor":"#506784","linecolor":"#506784","ticks":""},"baxis":{"gridcolor":"#506784","linecolor":"#506784","ticks":""},"bgcolor":"rgb(17,17,17)","caxis":{"gridcolor":"#506784","linecolor":"#506784","ticks":""}},"title":{"x":0.05},"updatemenudefaults":{"bgcolor":"#506784","borderwidth":0},"xaxis":{"automargin":true,"gridcolor":"#283442","linecolor":"#506784","ticks":"","title":{"standoff":15},"zerolinecolor":"#283442","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#283442","linecolor":"#506784","ticks":"","title":{"standoff":15},"zerolinecolor":"#283442","zerolinewidth":2}}}
diff --git a/optuna_dashboard/static/components/StudyDetail.tsx b/optuna_dashboard/static/components/StudyDetail.tsx
index 2ee51108..9f7862d5 100644
--- a/optuna_dashboard/static/components/StudyDetail.tsx
+++ b/optuna_dashboard/static/components/StudyDetail.tsx
@@ -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()
@@ -251,6 +255,18 @@ export const StudyDetail: FC = () => {
{APP_BAR_TITLE}
+ {
+ toggleColorMode()
+ }}
+ color="inherit"
+ >
+ {theme.palette.mode === "dark" ? (
+
+ ) : (
+
+ )}
+
diff --git a/optuna_dashboard/static/components/StudyList.tsx b/optuna_dashboard/static/components/StudyList.tsx
index 8f428450..ae31eb24 100644
--- a/optuna_dashboard/static/components/StudyList.tsx
+++ b/optuna_dashboard/static/components/StudyList.tsx
@@ -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([
"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(studySummariesState)
@@ -78,7 +89,10 @@ export const StudyList: FC = () => {
label: "Name",
sortable: true,
toCellValue: (i) => (
-
+
{studies[i].study_name}
),
@@ -212,6 +226,18 @@ export const StudyList: FC = () => {
{APP_BAR_TITLE}
+ {
+ toggleColorMode()
+ }}
+ color="inherit"
+ >
+ {theme.palette.mode === "dark" ? (
+
+ ) : (
+
+ )}
+