Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/experiment_manager #10

Merged
merged 23 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4e99290
feat: ExperimentManager added
ihsanKisi Apr 18, 2024
1233736
refactor: Updated the filter logic to reflect latest changes
ihsanKisi Apr 18, 2024
6a37753
docs: added the module explanation to experiment_manager
ihsanKisi Apr 25, 2024
58840cf
test: add tests for experiment_manager
ihsanKisi Apr 25, 2024
2b13ed9
refactor: git ignore file is updated to remove .pyc files in the commits
ihsanKisi Apr 25, 2024
90b05c0
refactor: minimum python version is set to 3.9 as before
ihsanKisi Apr 25, 2024
36e139d
add experiment filtering support with buttons, add enums for experime…
ihsanKisi May 2, 2024
22a561e
Merge branch 'develop' into feat-experiment-manager
aiakide May 7, 2024
272980d
fix: Remove __pycache__
aiakide May 7, 2024
ea889f2
refactor: generalize the state class
ihsanKisi May 16, 2024
dcd9931
refactor: resolve conflicts
ihsanKisi May 16, 2024
a2aa72b
rebase continuesrefacotor: add the rest of the conflicting files
ihsanKisi May 16, 2024
4274c65
rebasing the branchmerge conflicts are resolvedadd experiment filteri…
ihsanKisi May 2, 2024
c85d10a
conflicts resolvedrefactor: generalize the state class
ihsanKisi May 16, 2024
3cb75f4
fix: solve table items not loading and exclude lambda expression from…
ihsanKisi May 16, 2024
ba8cb1c
fix: Update dependencies (libsass installation error)
aiakide May 23, 2024
df9858f
Merge branch 'develop' into feat-experiment-manager
aiakide May 23, 2024
42e38d8
refactor: move the button component to buttons module for clarity (#18)
ihsanKisi May 28, 2024
6459f58
refactor: update file names according to the convention
ihsanKisi May 28, 2024
dc76823
Merge branch 'feat-experiment-management' into feat-experiment-manager
aiakide May 28, 2024
664e9d0
refactor: clean up the code, poetry update, and updating the file nam…
ihsanKisi May 28, 2024
98c8f7e
refactor: update docstrings
ihsanKisi May 28, 2024
bd1d8bf
refactor: update file name
ihsanKisi May 28, 2024
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: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ body:
description: By submitting this feature request, you agree to follow our [Code of Conduct](https://github.com/codecentric-oss/niceml-dashboard/blob/main/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow this project's Code of Conduct
required: true
required: true
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ Please provide any relevant links (e.g. documentation, external resources) that

If applicable, please include screenshots of the before and after effects of your changes.

Thank you for your contribution! 🎉
Thank you for your contribution! 🎉
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ Remember that this code of conduct applies to all project spaces, including GitH

Let's work together to build a welcoming and inclusive community where everyone can contribute and grow.

Note: This code of conduct was adapted from the Contributor Covenant (https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
Note: This code of conduct was adapted from the Contributor Covenant (https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# niceml-dashboard
- Welcome on board.

31 changes: 26 additions & 5 deletions nicemldashboard/State.py → nicemldashboard/State/State.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,29 @@
Also includes helper functions to initialize and get the instance of the Event Manager.
Enums for Dicts are defined for consistency.
"""
from enum import Enum
from abc import ABCMeta
from enum import EnumMeta
from nicegui import context
import logging
from nicegui.observables import ObservableDict

logger = logging.getLogger(__name__)

_EVENT_MNGR_ATTR_NAME = "_niceml"
_EVENT_MNGR_ATTR_NAME = "_nicemldashboard"


class StateKeys(ABCMeta, EnumMeta):
"""
Provides an abstract class for StateKey management
"""


class EventManager:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use a more appropriate class name. This is where our app data is stored. I qould suggest something like State, or AppState.

"""
Manages event dictionaries and provides methods to retrieve and manage them.
"""

_observable_dicts: dict[str, ObservableDict]
_observable_dicts: dict[StateKeys, ObservableDict]

def __init__(self):
"""
Expand Down Expand Up @@ -77,9 +84,23 @@ def init_event_manager(event_manager: EventManager):
logger.debug("Event Manager cannot be initialized in a background task")


class Dicts(Enum):
class StateEvent(ABCMeta, EnumMeta):
"""
Manages the keys for the observable dictionaries
"""


class ExperimentEvents(StateEvent):
"""
Manages the experimente events in the observable dictionaries
"""

ON_EXPERIMENT_PREFIX_CHANGE = "on_experiment_prefix_change"


class ExperimentStateKeys(StateKeys):
"""
Manages the observable dictionaries
"""

experiment_dict = "experiment_dict"
EXPERIMENT_DICT = "experiment_dict"
Empty file.
48 changes: 43 additions & 5 deletions nicemldashboard/basecomponents/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
from typing import Optional, List

from nicegui import ui
from nicegui.observables import ObservableDict


from nicemldashboard.State.State import (
_get_event_manager,
ExperimentStateKeys,
ExperimentEvents,
)
from nicemldashboard.basecomponents.buttons import SidebarToggleButton
from nicemldashboard.experiment.type import ExperimentType

Expand All @@ -36,14 +44,44 @@ def sidebar(experiment_types: Optional[List[ExperimentType]] = None):
side_bar_toggle = SidebarToggleButton(left_drawer=left_drawer)

for experiment_type in experiment_types:
button_callback = lambda e, et=experiment_type: (
on_stage_change(
_get_event_manager().get_dict(ExperimentStateKeys.EXPERIMENT_DICT),
get_enum(et),
)
)

with ui.button(
color="transparent",
icon=experiment_type.icon,
).props(
"flat"
).classes("exp-type-btn").bind_text_from(
color="transparent", icon=experiment_type.icon, on_click=button_callback
).props("flat").classes("exp-type-btn").bind_text_from(
experiment_type,
"prefix",
backward=lambda x: ("" if not side_bar_toggle.is_expanded() else x),
):
ui.tooltip(experiment_type.name)


def on_stage_change(observable_dict: ObservableDict, value: str):
"""
Updates the Events.on_experiment_change key with the value given.
:param observable_dict:
:param value:
:return:
"""
observable_dict[ExperimentEvents.ON_EXPERIMENT_PREFIX_CHANGE] = value


def get_enum(experiment_type: ExperimentType):
"""
Provides a way to easily compare the experiment type with the ExperimentType Enums
:param experiment_type:
:return:
"""
if experiment_type.prefix == "SEG":
return ExperimentType.SEM_SEG
elif experiment_type.prefix == "CLS":
return ExperimentType.CLS
elif experiment_type.prefix == "OBD":
return ExperimentType.OBJ_DET
else:
raise Exception("The event type is not available in the ExperimentType Enum")
1 change: 1 addition & 0 deletions nicemldashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from nicemldashboard.pages.home import home
from nicemldashboard.utils.settings import Settings


# TODO: Make file paths os-agnostic
app.add_static_files("/fonts", "nicemldashboard/assets/fonts")

Expand Down
52 changes: 52 additions & 0 deletions nicemldashboard/experiment/experiment_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
This module provides an experiment manager. Currently, experiment manager
supports filtering experiments by their properties.
"""
import logging
from typing import List

from nicemldashboard.experiment.experiment import Experiment


class ExperimentManager:
"""
Allows filtering experiments by making the filter_by method available
"""

def __init__(self, experiments: List[Experiment]):
"""
Initializes an ExperimentManager with the provided list of experiments.
"""
self.experiments = experiments

def filter_by(self, **filters) -> List[Experiment]:
"""
Filters the experiment list after filtering with the provided filters
:param filters:
:return:
"""
filtered_experiments = self.experiments.copy()
for key, value in filters.items():
try:
if isinstance(value, dict):
filtered_experiments = [
exp
for exp in filtered_experiments
if all(
item in getattr(exp, key, {}).items()
for item in value.items()
)
]
else:
filtered_experiments = [
exp
for exp in filtered_experiments
if getattr(exp, key, None) == value
]
except TypeError as e:
# Log the error message with details of which experiment and filter caused it.
logging.error(
f"Incomparable types between attribute '{key}' with value '{value}' "
f"and filter value '{value}': {e}"
)
return filtered_experiments
27 changes: 26 additions & 1 deletion nicemldashboard/pages/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,36 @@

"""


from nicemldashboard.State.State import EventManager, ExperimentStateKeys, ExperimentEvents, init_event_manager


from nicegui import ui
from nicegui.observables import ObservableDict


from nicemldashboard.State.State import EventManager, ExperimentStateKeys, ExperimentEvents, init_event_manager

from nicemldashboard.basecomponents.sidebar import sidebar
from nicemldashboard.basecomponents.table import experiment_runs_table
from nicemldashboard.experiment.utils import get_random_experiments
from nicemldashboard.experiment.experiment_manager import ExperimentManager


@ui.page("/")
def home():
"""
Define the layout of the home page.
"""

ui.add_scss("nicemldashboard/assets/style.scss")
_instance = EventManager()
init_event_manager(_instance)
exp_dict = _instance.get_dict(ExperimentStateKeys.EXPERIMENT_DICT)
exp_dict.on_change(_experiment_runs_table.refresh)

experiments = get_random_experiments(experiment_count=20)
experiment_manager = ExperimentManager(experiments)

sidebar()
with ui.grid().classes("content"):
Expand All @@ -33,4 +48,14 @@ def home():
with ui.row():
ui.input(label="Experiment run", placeholder="Search for run")
ui.separator()
experiment_runs_table(experiments=experiments)
_experiment_runs_table(experiment_manager, exp_dict)


@ui.refreshable
def _experiment_runs_table(
experiment_manager: ExperimentManager, exp_dic: ObservableDict
):
experiments = experiment_manager.filter_by(
experiment_type=exp_dic.get(ExperimentEvents.ON_EXPERIMENT_PREFIX_CHANGE)
)
experiment_runs_table(experiments=experiments)
Loading
Loading