From 4828089fdff7d52a5f5b0e676442a46310fa359d Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 26 Jan 2024 19:08:19 +0900 Subject: [PATCH 1/6] Split useBackendRender function --- optuna_dashboard/ts/components/GraphContour.tsx | 17 +++-------------- optuna_dashboard/ts/state.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/optuna_dashboard/ts/components/GraphContour.tsx b/optuna_dashboard/ts/components/GraphContour.tsx index 2c660a89..7f59e718 100644 --- a/optuna_dashboard/ts/components/GraphContour.tsx +++ b/optuna_dashboard/ts/components/GraphContour.tsx @@ -15,27 +15,16 @@ import blue from "@mui/material/colors/blue" import { plotlyDarkTemplate } from "./PlotlyDarkMode" import { useMergedUnionSearchSpace } from "../searchSpace" import { getAxisInfo } from "../graphUtil" -import { useQuery } from "../urlQuery" import { getPlotAPI, PlotType } from "../apiClient" -import { useRecoilValue } from "recoil" -import { plotlypyIsAvailableState } from "../state" +import { useBackendRender } from "../state" const plotDomId = "graph-contour" export const Contour: FC<{ study: StudyDetail | null }> = ({ study = null }) => { - const query = useQuery() - const plotlypyIsAvailable = useRecoilValue(plotlypyIsAvailableState) - if (query.get("plotlypy_rendering") === "true") { - if (plotlypyIsAvailable) { - return - } else { - console.warn( - "Use frontend rendering because plotlypy is specified but not available." - ) - return - } + if (useBackendRender()) { + return } else { return } diff --git a/optuna_dashboard/ts/state.ts b/optuna_dashboard/ts/state.ts index 49307401..20f75c2d 100644 --- a/optuna_dashboard/ts/state.ts +++ b/optuna_dashboard/ts/state.ts @@ -1,4 +1,5 @@ import { atom, useRecoilValue } from "recoil" +import { useQuery } from "./urlQuery" export const studySummariesState = atom({ key: "studySummaries", @@ -104,3 +105,18 @@ export const useArtifacts = (studyId: number, trialId: number): Artifact[] => { } return trial.artifacts } + +export const useBackendRender = (): boolean => { + const query = useQuery() + const plotlypyIsAvailable = useRecoilValue(plotlypyIsAvailableState) + + if (query.get("plotlypy_rendering") === "true") { + if (plotlypyIsAvailable) { + return true + } + console.warn( + "Use frontend rendering because plotlypy is specified but not available." + ) + } + return false +} From 94ce9f9fa162ddf19653377e68794f86d682a2c9 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 26 Jan 2024 19:12:24 +0900 Subject: [PATCH 2/6] Implement API --- optuna_dashboard/_app.py | 8 ++++++++ optuna_dashboard/ts/apiClient.ts | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index 1c9c0119..5057353d 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -271,6 +271,14 @@ def create_app( ) if plot_type == "contour": fig = optuna.visualization.plot_contour(study) + elif plot_type == "slice": + fig = optuna.visualization.plot_slice(study) + elif plot_type == "parallel_coordinate": + fig = optuna.visualization.plot_parallel_coordinate(study) + elif plot_type == "rank": + fig = optuna.visualization.plot_rank(study) + elif plot_type == "edf": + fig = optuna.visualization.plot_edf(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 3798f602..46fe3d0e 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -448,6 +448,10 @@ type PlotResponse = { } export enum PlotType { Contour = "contour", + Slice = "slice", + ParallelCoordinate = "parallel_coordinate", + Rank = "rank", + EDF = "edf", } export const getPlotAPI = ( studyId: number, From 78a7b9dbaab456499d1b41852f907c5b8ee62a35 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 26 Jan 2024 19:13:06 +0900 Subject: [PATCH 3/6] Implement GraphSliceBackend --- optuna_dashboard/ts/components/GraphSlice.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/optuna_dashboard/ts/components/GraphSlice.tsx b/optuna_dashboard/ts/components/GraphSlice.tsx index 2a807cb7..c668423c 100644 --- a/optuna_dashboard/ts/components/GraphSlice.tsx +++ b/optuna_dashboard/ts/components/GraphSlice.tsx @@ -20,6 +20,8 @@ import { useParamTargets, } from "../trialFilter" import { useMergedUnionSearchSpace } from "../searchSpace" +import { getPlotAPI, PlotType } from "../apiClient" +import { useBackendRender } from "../state" const plotDomId = "graph-slice" @@ -32,6 +34,35 @@ const isLogScale = (s: SearchSpaceItem): boolean => { export const GraphSlice: FC<{ study: StudyDetail | null +}> = ({ study = null }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphSliceBackend: FC<{ + study: StudyDetail | null +}> = ({ study = null }) => { + const studyId = study?.id + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.Slice) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId]) + return +} + +const GraphSliceFrontend: FC<{ + study: StudyDetail | null }> = ({ study = null }) => { const theme = useTheme() From 55cca4a76e032da5c51773c69d75748216dd49e1 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 26 Jan 2024 19:17:24 +0900 Subject: [PATCH 4/6] Implement GraphParallelCoordinateBackend --- .../ts/components/GraphParallelCoordinate.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/optuna_dashboard/ts/components/GraphParallelCoordinate.tsx b/optuna_dashboard/ts/components/GraphParallelCoordinate.tsx index b991ef94..3a227237 100644 --- a/optuna_dashboard/ts/components/GraphParallelCoordinate.tsx +++ b/optuna_dashboard/ts/components/GraphParallelCoordinate.tsx @@ -17,6 +17,8 @@ import { useParamTargets, } from "../trialFilter" import { useMergedUnionSearchSpace } from "../searchSpace" +import { getPlotAPI, PlotType } from "../apiClient" +import { useBackendRender } from "../state" const plotDomId = "graph-parallel-coordinate" @@ -86,6 +88,35 @@ const useTargets = ( export const GraphParallelCoordinate: FC<{ study: StudyDetail | null +}> = ({ study = null }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphParallelCoordinateBackend: FC<{ + study: StudyDetail | null +}> = ({ study = null }) => { + const studyId = study?.id + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.ParallelCoordinate) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId]) + return +} + +const GraphParallelCoordinateFrontend: FC<{ + study: StudyDetail | null }> = ({ study = null }) => { const theme = useTheme() const [targets, searchSpace, renderCheckBoxes] = useTargets(study) From 27cdde3a1b82dde94d2f89fe2013daac70eb0cd4 Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 26 Jan 2024 19:19:35 +0900 Subject: [PATCH 5/6] Implement GraphRankBackend --- optuna_dashboard/ts/components/GraphRank.tsx | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/optuna_dashboard/ts/components/GraphRank.tsx b/optuna_dashboard/ts/components/GraphRank.tsx index 6daaf10a..3ee4f9df 100644 --- a/optuna_dashboard/ts/components/GraphRank.tsx +++ b/optuna_dashboard/ts/components/GraphRank.tsx @@ -14,6 +14,8 @@ import { import { plotlyDarkTemplate } from "./PlotlyDarkMode" import { getAxisInfo, makeHovertext } from "../graphUtil" import { useMergedUnionSearchSpace } from "../searchSpace" +import { getPlotAPI, PlotType } from "../apiClient" +import { useBackendRender } from "../state" const plotDomId = "graph-rank" @@ -31,6 +33,35 @@ interface RankPlotInfo { export const GraphRank: FC<{ study: StudyDetail | null +}> = ({ study = null }) => { + if (useBackendRender()) { + return + } else { + return + } +} + +const GraphRankBackend: FC<{ + study: StudyDetail | null +}> = ({ study = null }) => { + const studyId = study?.id + useEffect(() => { + if (studyId === undefined) { + return + } + getPlotAPI(studyId, PlotType.Rank) + .then(({ data, layout }) => { + plotly.react(plotDomId, data, layout) + }) + .catch((err) => { + console.error(err) + }) + }, [studyId]) + return +} + +const GraphRankFrontend: FC<{ + study: StudyDetail | null }> = ({ study = null }) => { const theme = useTheme() const [objectiveId, setobjectiveId] = useState(0) From b2756fd33994289eacb2ad24224a300f1fdcd6ac Mon Sep 17 00:00:00 2001 From: Kenshin Abe Date: Fri, 2 Feb 2024 18:07:13 +0900 Subject: [PATCH 6/6] Prevent plot from being wider than screen width --- optuna_dashboard/_app.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index 5057353d..0ba94b1a 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -273,6 +273,10 @@ def create_app( fig = optuna.visualization.plot_contour(study) elif plot_type == "slice": fig = optuna.visualization.plot_slice(study) + # Note: Optuna's implementation forces a minimum width. + # We override it to prevent the figure from going beyond the screen width. + # https://github.com/optuna/optuna/blob/2abd0ae81eaf3683ce1dd580429904c8a705300d/optuna/visualization/_slice.py#L237-L239 + fig.update_layout(width=None) elif plot_type == "parallel_coordinate": fig = optuna.visualization.plot_parallel_coordinate(study) elif plot_type == "rank":