From 9bfcf6ce3172b03ffed68e431366c3200bc36054 Mon Sep 17 00:00:00 2001 From: Jochem Smit Date: Tue, 29 Oct 2024 19:32:59 +0100 Subject: [PATCH] generate selectors from object --- dont_fret/web/bursts/components.py | 33 ++++------------------ dont_fret/web/new_models.py | 10 ++++++- dont_fret/web/state.py | 4 ++- dont_fret/web/trace/page.py | 44 +++++++++++------------------- dont_fret/web/utils.py | 40 +++++++++++++++++++++++++-- 5 files changed, 72 insertions(+), 59 deletions(-) diff --git a/dont_fret/web/bursts/components.py b/dont_fret/web/bursts/components.py index f4484b0..93e6e78 100644 --- a/dont_fret/web/bursts/components.py +++ b/dont_fret/web/bursts/components.py @@ -27,6 +27,7 @@ from dont_fret.web.new_models import FRETNode, FRETStore, ListStore from dont_fret.web.reactive import ReactiveFRETNodes from dont_fret.web.utils import ( + NestedSelectors, find_index, find_object, get_bursts, @@ -236,35 +237,13 @@ def filter_from_selection(): with solara.ColumnsResponsive([8, 4]): with solara.Card("Histogram"): labels = ["Measurement", "Bursts"] # TODO move elsewhere - + selectors = NestedSelectors( + nodes=selector_nodes, selection=burst_node_choice, labels=labels + ) # TODO make a class which yields setters/values for each selector with solara.Row(): - stack = selector_nodes - i = 0 - while stack: - records = [node.record for node in stack] - if not records: - break - - on_value = wrap_callback(burst_node_choice.set_item, "item", idx=i) - - val_stored = burst_node_choice.get_item(i, None) - if val_stored in {v["value"] for v in records}: - value = val_stored - else: - value = records[0]["value"] - on_value(value) - - solara.Select( - label=labels[i], - value=value, - values=records, - on_value=on_value, - ) - - selected_node = find_object(stack, value=value) - stack = selected_node.children - i += 1 + for level in selectors: + solara.Select(**level) with solara.Row(style={"align-items": "center"}): diff --git a/dont_fret/web/new_models.py b/dont_fret/web/new_models.py index 7ca1944..b87a941 100644 --- a/dont_fret/web/new_models.py +++ b/dont_fret/web/new_models.py @@ -10,7 +10,15 @@ from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass, field from pathlib import Path -from typing import TYPE_CHECKING, Callable, Generic, Optional, ParamSpec, Type, TypeVar +from typing import ( + TYPE_CHECKING, + Callable, + Generic, + Optional, + ParamSpec, + Type, + TypeVar, +) import numpy as np import polars as pl diff --git a/dont_fret/web/state.py b/dont_fret/web/state.py index 38ea7a1..a301657 100644 --- a/dont_fret/web/state.py +++ b/dont_fret/web/state.py @@ -31,8 +31,10 @@ # then we dont have to have burst search method for headless and web seperately +from dont_fret.web.tmp_load import TEST_NODES + # TODO refactor fret_store -fret_nodes = FRETStore([]) +fret_nodes = FRETStore(TEST_NODES) burst_figure_selection = [ BurstFigureSelection(fret_nodes), diff --git a/dont_fret/web/trace/page.py b/dont_fret/web/trace/page.py index 681ac76..5b5dae9 100644 --- a/dont_fret/web/trace/page.py +++ b/dont_fret/web/trace/page.py @@ -14,10 +14,21 @@ from dont_fret import BinnedPhotonData, PhotonData from dont_fret.formatting import TRACE_COLORS, TRACE_SIGNS from dont_fret.web.methods import generate_traces -from dont_fret.web.models import BurstNode, PhotonNode, TCSPCSettings, TraceSettings +from dont_fret.web.models import ( + BurstNode, + PhotonNode, + TCSPCSettings, + TraceSettings, +) from dont_fret.web.new_models import FRETNode, FRETStore, ListStore from dont_fret.web.trace.methods import create_tcspc_histogram -from dont_fret.web.utils import find_object, get_photons, make_selector_nodes, wrap_callback +from dont_fret.web.utils import ( + NestedSelectors, + find_object, + get_photons, + make_selector_nodes, + wrap_callback, +) # TODO move fret node / photon file reactives to module level TCSPC_SETTINGS = solara.Reactive(TCSPCSettings()) @@ -144,33 +155,10 @@ def TracePage(): labels = ["Measurement", "Photons"] # TODO move elsewhere TRACE_SETTINGS: solara.Reactive[TraceSettings] = solara.use_reactive(TraceSettings()) - stack = selector_nodes + selectors = NestedSelectors(nodes=selector_nodes, selection=choice, labels=labels) with solara.Sidebar(): - i = 0 - while stack: - records = [node.record for node in stack] - if not records: - break - - on_value = wrap_callback(choice.set_item, "item", idx=i) - - val_stored = choice.get_item(i, None) - if val_stored in {v["value"] for v in records}: - value = val_stored - else: - value = records[0]["value"] - on_value(value) - - solara.Select( - label=labels[i], - value=value, - on_value=on_value, - values=records, - ) - - selected_node = find_object(stack, value=value) - stack = selected_node.children - i += 1 + for level in selectors: + solara.Select(**level) photon_node = get_photons(state.fret_nodes.items, choice.items) TraceFigure(photon_node, TRACE_SETTINGS.value) diff --git a/dont_fret/web/utils.py b/dont_fret/web/utils.py index 5e36fc1..1a8cd4d 100644 --- a/dont_fret/web/utils.py +++ b/dont_fret/web/utils.py @@ -1,10 +1,11 @@ import time import uuid +from dataclasses import dataclass from functools import partial -from typing import Any, Callable, Literal, Optional, TypeVar +from typing import Any, Callable, Dict, Iterator, List, Literal, Optional, TypeVar from dont_fret.web.models import BurstNode, PhotonNode -from dont_fret.web.new_models import FRETNode, SelectorNode +from dont_fret.web.new_models import FRETNode, ListStore, SelectorNode T = TypeVar("T") V = TypeVar("V") @@ -101,3 +102,38 @@ def get_bursts(fret_nodes: list[FRETNode], choice: list[str]) -> BurstNode: fret_node = find_object(fret_nodes, id=uuid.UUID(choice[0])) burst_node = find_object(fret_node.bursts.items, id=uuid.UUID(choice[1])) return burst_node + + +@dataclass +class NestedSelectors: + nodes: List[SelectorNode] + selection: ListStore[str] + labels: Optional[List[str]] + + def __iter__(self) -> Iterator[Dict[str, Any]]: + stack = self.nodes + i = 0 + while stack: + records = [node.record for node in stack] + if not records: + break + + on_value = wrap_callback(self.selection.set_item, "item", idx=i) + + val_stored = self.selection.get_item(i, None) + if val_stored in {v["value"] for v in records}: + value = val_stored + else: + value = records[0]["value"] + on_value(value) + + if self.labels: + label = self.labels[i] + else: + label = f"Level {i}" + + yield {"label": label, "value": value, "values": records, "on_value": on_value} + + selected_node = find_object(stack, value=value) + stack = selected_node.children if selected_node else [] + i += 1