From a7429318f3231ae6713cd7d9954a5c8e9a1b8548 Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Fri, 1 Dec 2023 10:22:11 +0100 Subject: [PATCH 01/10] Limit the maximum number of trials to be used for one update More specifically, this PR makes the following changes: 1. Add query param for limit, 2. Update studyDetails only if there is no study with the specified study_id or the fetched trials has a positive length, 3. Shorten the waiting interval when there is a leftover in the server side, and 4. Adapt the flake8 setup to the Optuna repo. --- optuna_dashboard/_app.py | 25 ++++++++++++------- optuna_dashboard/_serializer.py | 2 ++ optuna_dashboard/ts/action.ts | 14 ++++++++--- optuna_dashboard/ts/apiClient.ts | 6 ++++- .../ts/components/StudyDetail.tsx | 8 +++++- optuna_dashboard/ts/state.ts | 5 ++++ optuna_dashboard/ts/types/index.d.ts | 1 + python_tests/test_serializers.py | 4 +-- setup.cfg | 3 +++ 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index ead27188..1dd05854 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -191,14 +191,19 @@ def create_app( @app.get("/api/studies/") @json_api_view def get_study_detail(study_id: int) -> dict[str, Any]: - try: - after = int(request.params["after"]) - assert after >= 0 - except AssertionError: - response.status = 400 # Bad parameter - return {"reason": "`after` should be larger or equal 0."} - except KeyError: - after = 0 + query_params = dict(after=0, limit=1000) + for query_key in query_params: + try: + query_params[query_key] = int(request.params[query_key]) + assert query_params[query_key] >= 0 + except AssertionError: + response.status = 400 # Bad parameter + return {"reason": f"`{query_key}` should be larger than or equal to 0."} + except KeyError: + # Use the default parameter defined in query_params. + pass + + after, limit = query_params["after"], query_params["limit"] summary = get_study_summary(storage, study_id) if summary is None: response.status = 404 # Not found @@ -229,16 +234,18 @@ def create_app( plotly_graph_objects = get_plotly_graph_objects(system_attrs) skipped_trial_ids = get_skipped_trial_ids(system_attrs) skipped_trial_numbers = [t.number for t in trials if t._trial_id in skipped_trial_ids] + fetched_trials_partially = after + limit < len(trials) return serialize_study_detail( summary, best_trials, - trials[after:], + trials[after : after + limit], intersection, union, union_user_attrs, has_intermediate_values, plotly_graph_objects, skipped_trial_numbers, + fetched_trials_partially, ) @app.get("/api/studies//param_importances") diff --git a/optuna_dashboard/_serializer.py b/optuna_dashboard/_serializer.py index 7030abec..3bc659c3 100644 --- a/optuna_dashboard/_serializer.py +++ b/optuna_dashboard/_serializer.py @@ -141,11 +141,13 @@ def serialize_study_detail( has_intermediate_values: bool, plotly_graph_objects: dict[str, str], skipped_trial_numbers: list[int], + fetched_trials_partially: bool, ) -> dict[str, Any]: serialized: dict[str, Any] = { "name": summary.study_name, "directions": [d.name.lower() for d in summary.directions], "user_attrs": serialize_attrs(summary.user_attrs), + "fetched_trials_partially": fetched_trials_partially, } system_attrs = getattr(summary, "system_attrs", {}) serialized["artifacts"] = list_study_artifacts(system_attrs) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index 10fe43bc..3947a0ee 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -27,6 +27,7 @@ import { studySummariesState, paramImportanceState, isFileUploading, + isTrialLeftInCache, artifactIsAvailable, reloadIntervalState, trialsUpdatingState, @@ -46,6 +47,7 @@ export const actionCreator = () => { const setUploading = useSetRecoilState(isFileUploading) const setTrialsUpdating = useSetRecoilState(trialsUpdatingState) const setArtifactIsAvailable = useSetRecoilState(artifactIsAvailable) + const setIsTrialLeftInCache = useSetRecoilState(isTrialLeftInCache) const setStudyDetailState = (studyId: number, study: StudyDetail) => { setStudyDetails((prevVal) => { @@ -233,6 +235,7 @@ export const actionCreator = () => { const updateStudyDetail = (studyId: number) => { let nLocalFixedTrials = 0 + let nMaximumTrialsAtOnce = 1000 if (studyId in studyDetails) { const currentTrials = studyDetails[studyId].trials const firstUpdatable = currentTrials.findIndex((trial) => @@ -240,15 +243,20 @@ export const actionCreator = () => { ) nLocalFixedTrials = firstUpdatable === -1 ? currentTrials.length : firstUpdatable + nMaximumTrialsAtOnce = 2000 } - getStudyDetailAPI(studyId, nLocalFixedTrials) + getStudyDetailAPI(studyId, nLocalFixedTrials, nMaximumTrialsAtOnce) .then((study) => { const currentFixedTrials = studyId in studyDetails ? studyDetails[studyId].trials.slice(0, nLocalFixedTrials) : [] - study.trials = currentFixedTrials.concat(study.trials) - setStudyDetailState(studyId, study) + if (study.trials.length !== 0 || !(studyId in studyDetails)) { + // Update trials only if necessary. The second condition is for study with no trials. + study.trials = currentFixedTrials.concat(study.trials) + setStudyDetailState(studyId, study) + setIsTrialLeftInCache(study.fetched_trials_partially) + } }) .catch((err) => { const reason = err.response?.data.reason diff --git a/optuna_dashboard/ts/apiClient.ts b/optuna_dashboard/ts/apiClient.ts index f42d20de..ec80056d 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -102,16 +102,19 @@ interface StudyDetailResponse { artifacts: Artifact[] feedback_component_type: FeedbackComponentType skipped_trial_numbers?: number[] + fetched_trials_partially: boolean } export const getStudyDetailAPI = ( studyId: number, - nLocalTrials: number + nLocalTrials: number, + nMaximumTrialsAtOnce: number ): Promise => { return axiosInstance .get(`/api/studies/${studyId}`, { params: { after: nLocalTrials, + limit: nMaximumTrialsAtOnce, }, }) .then((res) => { @@ -145,6 +148,7 @@ export const getStudyDetailAPI = ( plotly_graph_objects: res.data.plotly_graph_objects, artifacts: res.data.artifacts, skipped_trial_numbers: res.data.skipped_trial_numbers ?? [], + fetched_trials_partially: res.data.fetched_trials_partially, } }) } diff --git a/optuna_dashboard/ts/components/StudyDetail.tsx b/optuna_dashboard/ts/components/StudyDetail.tsx index 2f56ec8b..1f2823dd 100644 --- a/optuna_dashboard/ts/components/StudyDetail.tsx +++ b/optuna_dashboard/ts/components/StudyDetail.tsx @@ -17,6 +17,7 @@ import DownloadIcon from "@mui/icons-material/Download" import { StudyNote } from "./Note" import { actionCreator } from "../action" import { + isTrialLeftInCache, reloadIntervalState, useStudyDetailValue, useStudyIsPreferential, @@ -57,6 +58,7 @@ export const StudyDetail: FC<{ const reloadInterval = useRecoilValue(reloadIntervalState) const studyName = useStudyName(studyId) const isPreferential = useStudyIsPreferential(studyId) + const isTrialLeft = useRecoilValue(isTrialLeftInCache) const title = studyName !== null ? `${studyName} (id=${studyId})` : `Study #${studyId}` @@ -73,9 +75,13 @@ export const StudyDetail: FC<{ const nTrials = studyDetail ? studyDetail.trials.length : 0 let interval = reloadInterval * 1000 + // If trials are left in cache, we collect them quickly. // For Human-in-the-loop Optimization, the interval is set to 2 seconds // when the number of trials is small, and the page is "trialList" or top page of preferential. - if ( + if (isTrialLeft) { + // Too short time is frustrating because the page freezes until the rendering is done. + interval = 3000 + } else if ( (!isPreferential && page === "trialList") || (isPreferential && page === "top") ) { diff --git a/optuna_dashboard/ts/state.ts b/optuna_dashboard/ts/state.ts index b1f60654..7825311b 100644 --- a/optuna_dashboard/ts/state.ts +++ b/optuna_dashboard/ts/state.ts @@ -33,6 +33,11 @@ export const drawerOpenState = atom({ default: false, }) +export const isTrialLeftInCache = atom({ + key: "isTrialLeftInCache", + default: false, +}) + export const isFileUploading = atom({ key: "isFileUploading", default: false, diff --git a/optuna_dashboard/ts/types/index.d.ts b/optuna_dashboard/ts/types/index.d.ts index 67182ff8..b1ed1bb7 100644 --- a/optuna_dashboard/ts/types/index.d.ts +++ b/optuna_dashboard/ts/types/index.d.ts @@ -220,6 +220,7 @@ type StudyDetail = { plotly_graph_objects: PlotlyGraphObject[] artifacts: Artifact[] skipped_trial_numbers: number[] + fetched_trials_partially: boolean } type StudyDetails = { diff --git a/python_tests/test_serializers.py b/python_tests/test_serializers.py index d1bdf59b..1f52d926 100644 --- a/python_tests/test_serializers.py +++ b/python_tests/test_serializers.py @@ -61,7 +61,7 @@ def test_get_study_detail_is_preferential() -> None: study_summary = study_summaries[0] study_detail = serialize_study_detail( - study_summary, [], study.trials, [], [], [], False, {}, [] + study_summary, [], study.trials, [], [], [], False, {}, [], False ) assert study_detail["is_preferential"] @@ -74,7 +74,7 @@ def test_get_study_detail_is_not_preferential() -> None: study_summary = study_summaries[0] study_detail = serialize_study_detail( - study_summary, [], study.trials, [], [], [], False, {}, [] + study_summary, [], study.trials, [], [], [], False, {}, [], False ) assert not study_detail["is_preferential"] diff --git a/setup.cfg b/setup.cfg index 93d9ad56..1eabbdce 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,7 @@ [flake8] +ignore = + E203 + W503 max-line-length = 99 statistics = True exclude = venv,build From 5bd1d5538a9464eb42e010056ca9126840c057bf Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Mon, 25 Dec 2023 08:06:31 +0100 Subject: [PATCH 02/10] Replace the first load n_trials with 2000 --- optuna_dashboard/ts/action.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index 3947a0ee..961aadb7 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -235,7 +235,7 @@ export const actionCreator = () => { const updateStudyDetail = (studyId: number) => { let nLocalFixedTrials = 0 - let nMaximumTrialsAtOnce = 1000 + let nMaximumTrialsAtOnce = 2000 if (studyId in studyDetails) { const currentTrials = studyDetails[studyId].trials const firstUpdatable = currentTrials.findIndex((trial) => @@ -243,7 +243,6 @@ export const actionCreator = () => { ) nLocalFixedTrials = firstUpdatable === -1 ? currentTrials.length : firstUpdatable - nMaximumTrialsAtOnce = 2000 } getStudyDetailAPI(studyId, nLocalFixedTrials, nMaximumTrialsAtOnce) .then((study) => { From bef9fb9e2701087a2cc1925e0c4041b9cea3ddbb Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Mon, 25 Dec 2023 08:10:13 +0100 Subject: [PATCH 03/10] Add a comment line for the default query values --- optuna_dashboard/_app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index 1dd05854..a0be6770 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -191,6 +191,7 @@ def create_app( @app.get("/api/studies/") @json_api_view def get_study_detail(study_id: int) -> dict[str, Any]: + # Use the following default values if not specified in request.params. query_params = dict(after=0, limit=1000) for query_key in query_params: try: From 646bc7497eba683476a815584d561f8d90c80d0a Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Mon, 25 Dec 2023 08:16:09 +0100 Subject: [PATCH 04/10] Rename isTrialLeftInCache with FetchedTrialsPartially for uniformity --- optuna_dashboard/ts/action.ts | 10 ++++++---- optuna_dashboard/ts/components/StudyDetail.tsx | 8 +++++--- optuna_dashboard/ts/state.ts | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index 961aadb7..c2d3cc31 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -27,7 +27,7 @@ import { studySummariesState, paramImportanceState, isFileUploading, - isTrialLeftInCache, + fetchedTrialsPartiallyState, artifactIsAvailable, reloadIntervalState, trialsUpdatingState, @@ -47,7 +47,9 @@ export const actionCreator = () => { const setUploading = useSetRecoilState(isFileUploading) const setTrialsUpdating = useSetRecoilState(trialsUpdatingState) const setArtifactIsAvailable = useSetRecoilState(artifactIsAvailable) - const setIsTrialLeftInCache = useSetRecoilState(isTrialLeftInCache) + const setFetchedTrialsPartially = useSetRecoilState( + fetchedTrialsPartiallyState + ) const setStudyDetailState = (studyId: number, study: StudyDetail) => { setStudyDetails((prevVal) => { @@ -235,7 +237,7 @@ export const actionCreator = () => { const updateStudyDetail = (studyId: number) => { let nLocalFixedTrials = 0 - let nMaximumTrialsAtOnce = 2000 + const nMaximumTrialsAtOnce = 2000 if (studyId in studyDetails) { const currentTrials = studyDetails[studyId].trials const firstUpdatable = currentTrials.findIndex((trial) => @@ -254,7 +256,7 @@ export const actionCreator = () => { // Update trials only if necessary. The second condition is for study with no trials. study.trials = currentFixedTrials.concat(study.trials) setStudyDetailState(studyId, study) - setIsTrialLeftInCache(study.fetched_trials_partially) + setFetchedTrialsPartially(study.fetched_trials_partially) } }) .catch((err) => { diff --git a/optuna_dashboard/ts/components/StudyDetail.tsx b/optuna_dashboard/ts/components/StudyDetail.tsx index 1f2823dd..321fcafa 100644 --- a/optuna_dashboard/ts/components/StudyDetail.tsx +++ b/optuna_dashboard/ts/components/StudyDetail.tsx @@ -17,7 +17,7 @@ import DownloadIcon from "@mui/icons-material/Download" import { StudyNote } from "./Note" import { actionCreator } from "../action" import { - isTrialLeftInCache, + fetchedTrialsPartiallyState, reloadIntervalState, useStudyDetailValue, useStudyIsPreferential, @@ -58,7 +58,9 @@ export const StudyDetail: FC<{ const reloadInterval = useRecoilValue(reloadIntervalState) const studyName = useStudyName(studyId) const isPreferential = useStudyIsPreferential(studyId) - const isTrialLeft = useRecoilValue(isTrialLeftInCache) + const fetchedTrialsPartially = useRecoilValue( + fetchedTrialsPartiallyState + ) const title = studyName !== null ? `${studyName} (id=${studyId})` : `Study #${studyId}` @@ -78,7 +80,7 @@ export const StudyDetail: FC<{ // If trials are left in cache, we collect them quickly. // For Human-in-the-loop Optimization, the interval is set to 2 seconds // when the number of trials is small, and the page is "trialList" or top page of preferential. - if (isTrialLeft) { + if (fetchedTrialsPartially) { // Too short time is frustrating because the page freezes until the rendering is done. interval = 3000 } else if ( diff --git a/optuna_dashboard/ts/state.ts b/optuna_dashboard/ts/state.ts index 7825311b..7b64d0d4 100644 --- a/optuna_dashboard/ts/state.ts +++ b/optuna_dashboard/ts/state.ts @@ -33,8 +33,8 @@ export const drawerOpenState = atom({ default: false, }) -export const isTrialLeftInCache = atom({ - key: "isTrialLeftInCache", +export const fetchedTrialsPartiallyState = atom({ + key: "fetchedTrialsPartially", default: false, }) From 967f6ceb553293bd5b19bbc1441c3b8de6c27c4b Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Mon, 25 Dec 2023 10:27:12 +0100 Subject: [PATCH 05/10] Address the umezawa's comment --- optuna_dashboard/ts/action.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index c2d3cc31..a54e09ea 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -248,16 +248,18 @@ export const actionCreator = () => { } getStudyDetailAPI(studyId, nLocalFixedTrials, nMaximumTrialsAtOnce) .then((study) => { + if (studyId in studyDetails && study.trials.length === 0) { + // Update trials only if necessary. + // NOTE: The first condition is for study with no trials. + return + } const currentFixedTrials = studyId in studyDetails ? studyDetails[studyId].trials.slice(0, nLocalFixedTrials) : [] - if (study.trials.length !== 0 || !(studyId in studyDetails)) { - // Update trials only if necessary. The second condition is for study with no trials. - study.trials = currentFixedTrials.concat(study.trials) - setStudyDetailState(studyId, study) - setFetchedTrialsPartially(study.fetched_trials_partially) - } + study.trials = currentFixedTrials.concat(study.trials) + setStudyDetailState(studyId, study) + setFetchedTrialsPartially(study.fetched_trials_partially) }) .catch((err) => { const reason = err.response?.data.reason From d04101fb769c171fb435789e1d0edaa96dc10063 Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Tue, 26 Dec 2023 09:12:16 +0100 Subject: [PATCH 06/10] Add some tests --- python_tests/test_api.py | 73 +++++++++++++++------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/python_tests/test_api.py b/python_tests/test_api.py index e7210710..ebe5a0ef 100644 --- a/python_tests/test_api.py +++ b/python_tests/test_api.py @@ -1,12 +1,14 @@ from __future__ import annotations import json +import pytest import sys from unittest import TestCase import optuna from optuna import get_all_study_summaries from optuna.study import StudyDirection +from optuna.trial import FrozenTrial from optuna_dashboard._app import create_app from optuna_dashboard._app import create_new_study from optuna_dashboard._note import note_str_key_prefix @@ -44,70 +46,51 @@ class APITestCase(TestCase): study_summaries = json.loads(body)["study_summaries"] self.assertEqual(len(study_summaries), 2) - def test_get_study_details_without_after_param(self) -> None: + def run_get_study_details( + self, queries: dict[str, str] | None = None, expected_status: int = 200, + ) -> tuple[int, list[FrozenTrial]]: study = optuna.create_study() study_id = study._study_id - study.optimize(objective, n_trials=2) + study.optimize(objective, n_trials=10) app = create_app(study._storage) status, _, body = send_request( app, f"/api/studies/{study_id}", "GET", + queries=queries, content_type="application/json", ) - self.assertEqual(status, 200) - all_trials = json.loads(body)["trials"] - self.assertEqual(len(all_trials), 2) + self.assertEqual(status, expected_status) + if expected_status == 400: + return [] + else: + return json.loads(body)["trials"] + + def test_get_study_details_without_after_param(self) -> None: + all_trials = self.run_get_study_details() + self.assertEqual(len(all_trials), 10) def test_get_study_details_with_after_param_partial(self) -> None: - study = optuna.create_study() - study_id = study._study_id - study.optimize(objective, n_trials=2) - app = create_app(study._storage) + all_trials = self.run_get_study_details({"after": "5"}) + self.assertEqual(len(all_trials), 5) - status, _, body = send_request( - app, - f"/api/studies/{study_id}", - "GET", - queries={"after": "1"}, - content_type="application/json", - ) - self.assertEqual(status, 200) - all_trials = json.loads(body)["trials"] - self.assertEqual(len(all_trials), 1) + def test_get_study_details_with_params(self) -> None: + for after in [0, 5, 9, 10]: + for limit in [1, 2, 5, 10]: + trials = self.run_get_study_details({"after": str(after), "limit": str(limit)}) + ans = list(range(after, min(10, after + limit))) + self.assertEqual([t["number"] for t in trials], ans) def test_get_study_details_with_after_param_full(self) -> None: - study = optuna.create_study() - study_id = study._study_id - study.optimize(objective, n_trials=2) - app = create_app(study._storage) - - status, _, body = send_request( - app, - f"/api/studies/{study_id}", - "GET", - queries={"after": "2"}, - content_type="application/json", - ) - self.assertEqual(status, 200) - all_trials = json.loads(body)["trials"] + all_trials = self.run_get_study_details({"after": "10"}) self.assertEqual(len(all_trials), 0) def test_get_study_details_with_after_param_illegal(self) -> None: - study = optuna.create_study() - study_id = study._study_id - study.optimize(objective, n_trials=2) - app = create_app(study._storage) + self.run_get_study_details({"after": "-1"}, expected_status=400) - status, _, body = send_request( - app, - f"/api/studies/{study_id}", - "GET", - queries={"after": "-1"}, - content_type="application/json", - ) - self.assertEqual(status, 400) + def test_get_study_details_with_limit_param_illegal(self) -> None: + self.run_get_study_details({"limit": "-1"}, expected_status=400) @pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support") def test_get_best_trials_of_preferential_study(self) -> None: From a2cf3ebd54d3dbe2b23cd2bb4fbfc554f9b3cd41 Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Tue, 26 Dec 2023 09:15:55 +0100 Subject: [PATCH 07/10] Apply formatter --- python_tests/test_api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python_tests/test_api.py b/python_tests/test_api.py index ebe5a0ef..cbf36e0c 100644 --- a/python_tests/test_api.py +++ b/python_tests/test_api.py @@ -1,14 +1,13 @@ from __future__ import annotations import json -import pytest import sys +from typing import Any from unittest import TestCase import optuna from optuna import get_all_study_summaries from optuna.study import StudyDirection -from optuna.trial import FrozenTrial from optuna_dashboard._app import create_app from optuna_dashboard._app import create_new_study from optuna_dashboard._note import note_str_key_prefix @@ -47,8 +46,10 @@ class APITestCase(TestCase): self.assertEqual(len(study_summaries), 2) def run_get_study_details( - self, queries: dict[str, str] | None = None, expected_status: int = 200, - ) -> tuple[int, list[FrozenTrial]]: + self, + queries: dict[str, str] | None = None, + expected_status: int = 200, + ) -> list[dict[str, Any]]: study = optuna.create_study() study_id = study._study_id study.optimize(objective, n_trials=10) From 78e1e118029c43281e7620bbeacb879c85aa8670 Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Fri, 19 Jan 2024 07:38:52 +0100 Subject: [PATCH 08/10] Add the force update for disabled live update --- optuna_dashboard/_app.py | 3 ++- optuna_dashboard/ts/action.ts | 4 ++-- optuna_dashboard/ts/components/AppDrawer.tsx | 7 ++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/optuna_dashboard/_app.py b/optuna_dashboard/_app.py index a0be6770..318135b0 100644 --- a/optuna_dashboard/_app.py +++ b/optuna_dashboard/_app.py @@ -192,7 +192,7 @@ def create_app( @json_api_view def get_study_detail(study_id: int) -> dict[str, Any]: # Use the following default values if not specified in request.params. - query_params = dict(after=0, limit=1000) + query_params = dict(after=0, limit=2000) for query_key in query_params: try: query_params[query_key] = int(request.params[query_key]) @@ -235,6 +235,7 @@ def create_app( plotly_graph_objects = get_plotly_graph_objects(system_attrs) skipped_trial_ids = get_skipped_trial_ids(system_attrs) skipped_trial_numbers = [t.number for t in trials if t._trial_id in skipped_trial_ids] + limit = len(trials) if limit == 0 else limit fetched_trials_partially = after + limit < len(trials) return serialize_study_detail( summary, diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index a54e09ea..159e22fe 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -235,9 +235,9 @@ export const actionCreator = () => { }) } - const updateStudyDetail = (studyId: number) => { + const updateStudyDetail = (studyId: number, forceFetchAllTrials: boolean = false) => { let nLocalFixedTrials = 0 - const nMaximumTrialsAtOnce = 2000 + const nMaximumTrialsAtOnce = forceFetchAllTrials ? 0 : 2000 if (studyId in studyDetails) { const currentTrials = studyDetails[studyId].trials const firstUpdatable = currentTrials.findIndex((trial) => diff --git a/optuna_dashboard/ts/components/AppDrawer.tsx b/optuna_dashboard/ts/components/AppDrawer.tsx index 31eeec69..0c17f338 100644 --- a/optuna_dashboard/ts/components/AppDrawer.tsx +++ b/optuna_dashboard/ts/components/AppDrawer.tsx @@ -310,7 +310,12 @@ export const AppDrawer: FC<{ { - action.saveReloadInterval(reloadInterval === -1 ? 10 : -1) + const newReloadInterval = reloadInterval === -1 ? 10 : -1 + action.saveReloadInterval(newReloadInterval) + if (newReloadInterval === -1) { + const forceFetchAllTrials = true + action.updateStudyDetail(studyId, forceFetchAllTrials) + } }} > From c10be8fcb8c49ab3f95ddc94d3bb1418cb8c620f Mon Sep 17 00:00:00 2001 From: nabenabe0928 Date: Fri, 19 Jan 2024 08:45:39 +0100 Subject: [PATCH 09/10] Apply formatter --- optuna_dashboard/ts/action.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index 159e22fe..4f7cb006 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -235,7 +235,10 @@ export const actionCreator = () => { }) } - const updateStudyDetail = (studyId: number, forceFetchAllTrials: boolean = false) => { + const updateStudyDetail = ( + studyId: number, + forceFetchAllTrials: boolean = false + ) => { let nLocalFixedTrials = 0 const nMaximumTrialsAtOnce = forceFetchAllTrials ? 0 : 2000 if (studyId in studyDetails) { From f838ef5f0ebb16b876ad94b283f3cb163445fbdb Mon Sep 17 00:00:00 2001 From: keisuke umezawa Date: Tue, 6 Feb 2024 21:44:00 +0900 Subject: [PATCH 10/10] Update action.ts --- optuna_dashboard/ts/action.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/optuna_dashboard/ts/action.ts b/optuna_dashboard/ts/action.ts index 48eb0a47..7c27a84c 100644 --- a/optuna_dashboard/ts/action.ts +++ b/optuna_dashboard/ts/action.ts @@ -51,6 +51,7 @@ export const actionCreator = () => { const setArtifactIsAvailable = useSetRecoilState(artifactIsAvailable) const setFetchedTrialsPartially = useSetRecoilState( fetchedTrialsPartiallyState + ) const setPlotlypyIsAvailable = useSetRecoilState( plotlypyIsAvailableState )