Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
29cfc47
Add streamlit helper
cross32768 Jun 23, 2023
53d4ae7
update comment
cross32768 Jun 23, 2023
e3821d3
Add render_user_attr_form_widgets
cross32768 Jun 23, 2023
29a0246
Merge branch 'main' into add_streamlit_helper
cross32768 Jun 30, 2023
17bcdf9
Fix some linter problems
cross32768 Jun 30, 2023
c737141
Add streamlit helper to __init__.py
cross32768 Jun 30, 2023
4cdfcf1
Update requirements.txt
cross32768 Jun 30, 2023
603d1fc
update pyproject.toml
cross32768 Jun 30, 2023
86ff6e4
apply some fix for mypy
cross32768 Jun 30, 2023
3d1c9dc
Apply black
cross32768 Jun 30, 2023
1cbf27f
fix some mypy error
cross32768 Jun 30, 2023
1f15777
update type annotation
cross32768 Jun 30, 2023
4e7d0bf
remove type annotation
cross32768 Jun 30, 2023
fb87b23
add type:ignore
cross32768 Jun 30, 2023
2430ff6
update
cross32768 Jun 30, 2023
9eeffba
add type: ignore
cross32768 Jun 30, 2023
5645ca5
fix some mypy error
cross32768 Jun 30, 2023
68ab4eb
roll back __init__.py
cross32768 Jun 30, 2023
09231c5
misc
cross32768 Jun 30, 2023
ceb7546
fix 1 mypy error
cross32768 Jun 30, 2023
a0ed9cc
Add type: ignore
cross32768 Jun 30, 2023
01433d2
move type: ignore
cross32768 Jun 30, 2023
56c6d72
Add type annotation
cross32768 Jun 30, 2023
2f8403a
trial for mypy error
cross32768 Jun 30, 2023
6395929
Change dir structure
cross32768 Jun 30, 2023
da3423c
change file name
cross32768 Jun 30, 2023
85bf158
Fix import path
cross32768 Jun 30, 2023
5faf59c
Merge branch 'main' into add_streamlit_helper
cross32768 Jul 7, 2023
87be6de
update some code structure
cross32768 Jul 7, 2023
fffe3df
Remove unused space
cross32768 Jul 7, 2023
96ee424
Add some space for readability
cross32768 Jul 7, 2023
836382c
Add unit tests
cross32768 Jul 7, 2023
e8cc246
Apply isort
cross32768 Jul 7, 2023
842f65b
Add streamlit for test
cross32768 Jul 7, 2023
4d728e4
Update test for combination
cross32768 Jul 7, 2023
8535927
Add callback function when feedback submission is completed by success
cross32768 Jul 7, 2023
1e37671
Change error handling
cross32768 Jul 7, 2023
294c065
Add default value for on_success_callback
cross32768 Jul 7, 2023
244f1c8
Change type annotation style
cross32768 Jul 7, 2023
e9fb869
Add streamlit to CI
cross32768 Jul 7, 2023
fad5c79
Add key
cross32768 Jul 7, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions optuna_dashboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from ._named_objectives import set_objective_names # noqa
from ._note import get_note # noqa
from ._note import save_note # noqa
from ._streamlit_helper import render_trial_note # noqa
from ._streamlit_helper import render_user_attr_form_widgets # noqa
Copy link
Copy Markdown
Member

@c-bata c-bata Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add the optuna.streamlit package and put these functions in it? Then we can make streamlit as an optional dependency.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Does you mean I create directory "optuna-dashboard/streamlit" and put my code in this dir instead of "optuna-dashboard/optuna-dashboard/_streamlit_helper.py"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly 👍



__version__ = "0.10.3"
89 changes: 89 additions & 0 deletions optuna_dashboard/_streamlit_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from __future__ import annotations

import optuna
from optuna.trial import FrozenTrial
import streamlit as st

from ._form_widget import get_form_widgets_json
from ._note import get_note_from_system_attrs


def render_trial_note(study: optuna.Study, trial: FrozenTrial) -> None:
"""Write a trial note to UI with streamlit as a markdown format.

Args:
study: The optuna study object.
trial: The optuna trial object to get note.
"""
note = get_note_from_system_attrs(study.system_attrs, trial._trial_id)
st.markdown(note["body"], unsafe_allow_html=True)


def render_user_attr_form_widgets(study: optuna.Study, trial: FrozenTrial) -> None:
"""Render user input widgets to UI with streamlit.

Submitted values to the forms are registered as each trial's user_attrs.

Args:
study: The optuna study object to get widget specification.
trial: The optuna trial object to tell user feedbacks.

Raises:
ValueError: If No form widgets registered.
ValueError: If 'output_type' of form widgets is not 'user_attr'.
ValueError: If any widget["type"] is not in ["choice", "slider", "text"].
"""

form_widgets_dict = get_form_widgets_json(study.system_attrs)
if form_widgets_dict is None:
raise ValueError("No form widgets registered.")

if (
"output_type" not in form_widgets_dict.keys()
or form_widgets_dict["output_type"] != "user_attr"
):
raise ValueError("'output_type' should be 'user_attr'.")

widgets = form_widgets_dict["widgets"]
values = []
with st.form("user_input", clear_on_submit=False):
for widget in widgets:
if widget["description"] is None: # type: ignore
description = ""
else:
description = widget["description"] # type: ignore
if widget["type"] == "choice":
value = st.radio(
description,
widget["values"],
format_func=lambda choice, widget=widget: widget["choices"][ # type: ignore
widget["values"].index(choice)
],
horizontal=True,
)
values.append(value)
elif widget["type"] == "slider":
# NOTE: It is difficult to reflect "labels".
value = st.slider(
description,
min_value=widget["min"],
max_value=widget["max"],
step=widget["step"],
)
values.append(value)
elif widget["type"] == "text":
# TODO (kaitos): Resolve that current implementation ignores "optional"
# (always optional on streamlit)
values.append(st.text_input(description)) # type: ignore
else:
raise ValueError("Widget type should be 'choice', 'slider', or 'text'.")
submitted = st.form_submit_button("Submit")

if submitted:
for widget, value in zip(widgets, values):
if widget["user_attr_key"] is not None: # type: ignore
study._storage.set_trial_user_attr(
trial._trial_id, key=widget["user_attr_key"], value=value # type: ignore
)

st.success("Submitted!")
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies = [
"optuna>=2.4.0",
"packaging",
"scikit-learn",
"streamlit",
]
dynamic = ["version"]

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
optuna>=2.4
bottle
scikit-learn
streamlit
typing-extensions;python_version<"3.8"

# lint
Expand Down