From 18e01d4d37801d14ef14c091f817597200f9f22f Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 9 Feb 2024 18:32:55 +0900 Subject: [PATCH 1/7] Implement backend rendering of timeline plot --- optuna_dashboard/_app.py | 2 ++ optuna_dashboard/ts/apiClient.ts | 1 + .../ts/components/GraphTimeline.tsx | 33 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index ac0e1cf0..997c89b6 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -283,6 +283,8 @@ def create_app( fig = optuna.visualization.plot_rank(study) elif plot_type == "edf": fig = optuna.visualization.plot_edf(study) + elif plot_type == "timeline": + fig = optuna.visualization.plot_timeline(study) else: response.status = 404 # Not found return {"reason": f"plot_type={plot_type} is not supported."} diff --git a/optuna_dashboard/ts/apiClient.ts b/optuna_dashboard/ts/apiClient.ts index 14566a07..b6b25171 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -452,6 +452,7 @@ export enum PlotType { ParallelCoordinate = "parallel_coordinate", Rank = "rank", EDF = "edf", + Timeline = "timeline", } export const getPlotAPI = ( studyId: number, diff --git a/optuna_dashboard/ts/components/GraphTimeline.tsx b/optuna_dashboard/ts/components/GraphTimeline.tsx index e9de2c71..f048a696 100644 --- a/optuna_dashboard/ts/components/GraphTimeline.tsx +++ b/optuna_dashboard/ts/components/GraphTimeline.tsx @@ -3,12 +3,45 @@ import React, { FC, useEffect } from "react" import { Card, CardContent, Grid, Typography, useTheme } from "@mui/material" import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" +import { getPlotAPI, PlotType } from "../apiClient" +import { useBackendRender } from "../state" const plotDomId = "graph-timeline" const maxBars = 100 export const GraphTimeline: FC<{ study: StudyDetail | null +}> = ({ study }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphTimelineBackend: FC<{ + study: StudyDetail | null +}> = ({ study }) => { + const studyId = study?.id + const numCompletedTrials = + study?.trials.filter((t) => t.state === "Complete").length || 0 + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.Timeline) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId, numCompletedTrials]) + return
+} + +const GraphTimelineFrontend: FC<{ + study: StudyDetail | null }> = ({ study }) => { const theme = useTheme() const colorTheme = usePlotlyColorTheme(theme.palette.mode) From f443fa750260bfe5f43f1840b1a20de78e19e9ad Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 9 Feb 2024 18:33:34 +0900 Subject: [PATCH 2/7] Implement backend rendering of importance plot --- optuna_dashboard/_app.py | 2 + optuna_dashboard/ts/apiClient.ts | 1 + .../GraphHyperparameterImportances.tsx | 37 ++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index 997c89b6..2f87c833 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -285,6 +285,8 @@ def create_app( fig = optuna.visualization.plot_edf(study) elif plot_type == "timeline": fig = optuna.visualization.plot_timeline(study) + elif plot_type == "param_importances": + fig = optuna.visualization.plot_param_importances(study) else: response.status = 404 # Not found return {"reason": f"plot_type={plot_type} is not supported."} diff --git a/optuna_dashboard/ts/apiClient.ts b/optuna_dashboard/ts/apiClient.ts index b6b25171..9bf76f92 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -453,6 +453,7 @@ export enum PlotType { Rank = "rank", EDF = "edf", Timeline = "timeline", + ParamImportances = "param_importances", } export const getPlotAPI = ( studyId: number, diff --git a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx index 88cce45f..098b030b 100644 --- a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx +++ b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx @@ -3,7 +3,8 @@ import React, { FC, useEffect } from "react" import { Typography, useTheme, Box, Card, CardContent } from "@mui/material" import { useParamImportance } from "../hooks/useParamImportance" -import { useStudyDirections, usePlotlyColorTheme } from "../state" +import { useStudyDirections, usePlotlyColorTheme, useBackendRender } from "../state" +import { getPlotAPI, PlotType } from "../apiClient" const plotDomId = "graph-hyperparameter-importances" @@ -11,6 +12,40 @@ export const GraphHyperparameterImportance: FC<{ studyId: number study: StudyDetail | null graphHeight: string +}> = ({ studyId, study = null, graphHeight }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphHyperparameterImportanceBackend: FC<{ + studyId: number + study: StudyDetail | null + graphHeight: string +}> = ({ studyId, study = null, graphHeight }) => { + const numCompletedTrials = + study?.trials.filter((t) => t.state === "Complete").length || 0 + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.ParamImportances) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId, numCompletedTrials]) + return +} + +const GraphHyperparameterImportanceFrontend: FC<{ + studyId: number + study: StudyDetail | null + graphHeight: string }> = ({ studyId, study = null, graphHeight }) => { const theme = useTheme() const colorTheme = usePlotlyColorTheme(theme.palette.mode) From af6b028eea45849ee2877a72c0fa73e4b3349b5e Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 9 Feb 2024 18:33:59 +0900 Subject: [PATCH 3/7] Implement backend rendering of pareto front plot --- optuna_dashboard/_app.py | 2 ++ optuna_dashboard/ts/apiClient.ts | 1 + .../ts/components/GraphParetoFront.tsx | 33 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index 2f87c833..1d4c9f7c 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -287,6 +287,8 @@ def create_app( fig = optuna.visualization.plot_timeline(study) elif plot_type == "param_importances": fig = optuna.visualization.plot_param_importances(study) + elif plot_type == "pareto_front": + fig = optuna.visualization.plot_pareto_front(study) else: response.status = 404 # Not found return {"reason": f"plot_type={plot_type} is not supported."} diff --git a/optuna_dashboard/ts/apiClient.ts b/optuna_dashboard/ts/apiClient.ts index 9bf76f92..cf775fd6 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -454,6 +454,7 @@ export enum PlotType { EDF = "edf", Timeline = "timeline", ParamImportances = "param_importances", + ParetoFront = "pareto_front", } export const getPlotAPI = ( studyId: number, diff --git a/optuna_dashboard/ts/components/GraphParetoFront.tsx b/optuna_dashboard/ts/components/GraphParetoFront.tsx index 61ad7b9e..de5bb5dc 100644 --- a/optuna_dashboard/ts/components/GraphParetoFront.tsx +++ b/optuna_dashboard/ts/components/GraphParetoFront.tsx @@ -14,11 +14,44 @@ import { import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" import { useNavigate } from "react-router-dom" +import { getPlotAPI, PlotType } from "../apiClient" +import { useBackendRender } from "../state" const plotDomId = "graph-pareto-front" export const GraphParetoFront: FC<{ study: StudyDetail | null +}> = ({ study = null }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphParetoFrontBackend: FC<{ + study: StudyDetail | null +}> = ({ study = null }) => { + const studyId = study?.id + const numCompletedTrials = + study?.trials.filter((t) => t.state === "Complete").length || 0 + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.ParetoFront) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId, numCompletedTrials]) + return +} + +const GraphParetoFrontFrontend: FC<{ + study: StudyDetail | null }> = ({ study = null }) => { const theme = useTheme() const colorTheme = usePlotlyColorTheme(theme.palette.mode) From 32ea832d5313a5231b1d689ceb14e41469003956 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 9 Feb 2024 19:09:21 +0900 Subject: [PATCH 4/7] Apply fmt --- .../GraphHyperparameterImportances.tsx | 22 ++++++++++++++++--- .../ts/components/GraphTimeline.tsx | 7 +++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx index 098b030b..a41f85c0 100644 --- a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx +++ b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx @@ -3,7 +3,11 @@ import React, { FC, useEffect } from "react" import { Typography, useTheme, Box, Card, CardContent } from "@mui/material" import { useParamImportance } from "../hooks/useParamImportance" -import { useStudyDirections, usePlotlyColorTheme, useBackendRender } from "../state" +import { + useStudyDirections, + usePlotlyColorTheme, + useBackendRender, +} from "../state" import { getPlotAPI, PlotType } from "../apiClient" const plotDomId = "graph-hyperparameter-importances" @@ -14,9 +18,21 @@ export const GraphHyperparameterImportance: FC<{ graphHeight: string }> = ({ studyId, study = null, graphHeight }) => { if (useBackendRender()) { - return + return ( + + ) } else { - return + return ( + + ) } } diff --git a/optuna_dashboard/ts/components/GraphTimeline.tsx b/optuna_dashboard/ts/components/GraphTimeline.tsx index f048a696..3fba8fe1 100644 --- a/optuna_dashboard/ts/components/GraphTimeline.tsx +++ b/optuna_dashboard/ts/components/GraphTimeline.tsx @@ -37,7 +37,12 @@ const GraphTimelineBackend: FC<{ console.error(err) }) }, [studyId, numCompletedTrials]) - return
+ return ( + + {" "} +
{" "} + + ) } const GraphTimelineFrontend: FC<{ From 4ceeb1bc7a056eebabd458860b914b5b40b31d8a Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Wed, 14 Feb 2024 18:15:34 +0900 Subject: [PATCH 5/7] Introduce usePlot --- .../GraphHyperparameterImportances.tsx | 28 +++++++++++-------- .../ts/components/GraphParetoFront.tsx | 28 +++++++++++-------- .../ts/components/GraphTimeline.tsx | 28 +++++++++++-------- 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx index a41f85c0..12ef8d2c 100644 --- a/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx +++ b/optuna_dashboard/ts/components/GraphHyperparameterImportances.tsx @@ -8,7 +8,8 @@ import { usePlotlyColorTheme, useBackendRender, } from "../state" -import { getPlotAPI, PlotType } from "../apiClient" +import { PlotType } from "../apiClient" +import { usePlot } from "../hooks/usePlot" const plotDomId = "graph-hyperparameter-importances" @@ -43,18 +44,23 @@ const GraphHyperparameterImportanceBackend: FC<{ }> = ({ studyId, study = null, graphHeight }) => { const numCompletedTrials = study?.trials.filter((t) => t.state === "Complete").length || 0 + const { data, layout, error } = usePlot({ + numCompletedTrials, + studyId, + plotType: PlotType.ParamImportances, + }) + useEffect(() => { - if (studyId === undefined) { - return + if (data && layout) { + plotly.react(plotDomId, data, layout) } - getPlotAPI(studyId, PlotType.ParamImportances) - .then(({ data, layout }) => { - plotly.react(plotDomId, data, layout) - }) - .catch((err) => { - console.error(err) - }) - }, [studyId, numCompletedTrials]) + }, [data, layout]) + useEffect(() => { + if (error) { + console.error(error) + } + }, [error]) + return } diff --git a/optuna_dashboard/ts/components/GraphParetoFront.tsx b/optuna_dashboard/ts/components/GraphParetoFront.tsx index de5bb5dc..9ddec25b 100644 --- a/optuna_dashboard/ts/components/GraphParetoFront.tsx +++ b/optuna_dashboard/ts/components/GraphParetoFront.tsx @@ -14,8 +14,9 @@ import { import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" import { useNavigate } from "react-router-dom" -import { getPlotAPI, PlotType } from "../apiClient" +import { PlotType } from "../apiClient" import { useBackendRender } from "../state" +import { usePlot } from "../hooks/usePlot" const plotDomId = "graph-pareto-front" @@ -35,18 +36,23 @@ const GraphParetoFrontBackend: FC<{ const studyId = study?.id const numCompletedTrials = study?.trials.filter((t) => t.state === "Complete").length || 0 + const { data, layout, error } = usePlot({ + numCompletedTrials, + studyId, + plotType: PlotType.ParetoFront, + }) + useEffect(() => { - if (studyId === undefined) { - return + if (data && layout) { + plotly.react(plotDomId, data, layout) } - getPlotAPI(studyId, PlotType.ParetoFront) - .then(({ data, layout }) => { - plotly.react(plotDomId, data, layout) - }) - .catch((err) => { - console.error(err) - }) - }, [studyId, numCompletedTrials]) + }, [data, layout]) + useEffect(() => { + if (error) { + console.error(error) + } + }, [error]) + return } diff --git a/optuna_dashboard/ts/components/GraphTimeline.tsx b/optuna_dashboard/ts/components/GraphTimeline.tsx index 3fba8fe1..f7e2db65 100644 --- a/optuna_dashboard/ts/components/GraphTimeline.tsx +++ b/optuna_dashboard/ts/components/GraphTimeline.tsx @@ -3,8 +3,9 @@ import React, { FC, useEffect } from "react" import { Card, CardContent, Grid, Typography, useTheme } from "@mui/material" import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" -import { getPlotAPI, PlotType } from "../apiClient" +import { PlotType } from "../apiClient" import { useBackendRender } from "../state" +import { usePlot } from "../hooks/usePlot" const plotDomId = "graph-timeline" const maxBars = 100 @@ -25,18 +26,23 @@ const GraphTimelineBackend: FC<{ const studyId = study?.id const numCompletedTrials = study?.trials.filter((t) => t.state === "Complete").length || 0 + const { data, layout, error } = usePlot({ + numCompletedTrials, + studyId, + plotType: PlotType.Timeline, + }) + useEffect(() => { - if (studyId === undefined) { - return + if (data && layout) { + plotly.react(plotDomId, data, layout) } - getPlotAPI(studyId, PlotType.Timeline) - .then(({ data, layout }) => { - plotly.react(plotDomId, data, layout) - }) - .catch((err) => { - console.error(err) - }) - }, [studyId, numCompletedTrials]) + }, [data, layout]) + useEffect(() => { + if (error) { + console.error(error) + } + }, [error]) + return ( {" "} From 9256a1baac70de11d086e2b1598dfef5c3913120 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Wed, 14 Feb 2024 18:19:34 +0900 Subject: [PATCH 6/7] Remove unnecessary space --- optuna_dashboard/ts/components/GraphTimeline.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/optuna_dashboard/ts/components/GraphTimeline.tsx b/optuna_dashboard/ts/components/GraphTimeline.tsx index f7e2db65..abe4effd 100644 --- a/optuna_dashboard/ts/components/GraphTimeline.tsx +++ b/optuna_dashboard/ts/components/GraphTimeline.tsx @@ -1,6 +1,6 @@ import * as plotly from "plotly.js-dist-min" import React, { FC, useEffect } from "react" -import { Card, CardContent, Grid, Typography, useTheme } from "@mui/material" +import { Card, CardContent, Grid, Typography, useTheme, Box } from "@mui/material" import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" import { PlotType } from "../apiClient" @@ -45,8 +45,7 @@ const GraphTimelineBackend: FC<{ return ( - {" "} -
{" "} +
) } From ead77a957811b2a6a62c4e010cdd43dc38343c96 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Wed, 14 Feb 2024 18:33:44 +0900 Subject: [PATCH 7/7] Remove unused import --- optuna_dashboard/ts/components/GraphTimeline.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/optuna_dashboard/ts/components/GraphTimeline.tsx b/optuna_dashboard/ts/components/GraphTimeline.tsx index abe4effd..519399bb 100644 --- a/optuna_dashboard/ts/components/GraphTimeline.tsx +++ b/optuna_dashboard/ts/components/GraphTimeline.tsx @@ -1,6 +1,6 @@ import * as plotly from "plotly.js-dist-min" import React, { FC, useEffect } from "react" -import { Card, CardContent, Grid, Typography, useTheme, Box } from "@mui/material" +import { Card, CardContent, Grid, Typography, useTheme } from "@mui/material" import { makeHovertext } from "../graphUtil" import { usePlotlyColorTheme } from "../state" import { PlotType } from "../apiClient"