Skip to content

state

Main application state variables

State = StateData() module-attribute #

Specific StateData instance used for app

StateData #

Holds app-wide state variables

Attributes:

Name Type Description
mapping Reactive[DataFrame]

bitmappings dataframe, used for targeting filters.

datamodel Reactive[DataFrame]

column glossary dataframe

df Reactive[DataFrame]

loaded dataframe file, defaults to nothing but app will instantiate with one loaded.

columns Reactive[dict[str, list[str]]]

column lookup, used for guardrailing.

release str

release type

datatype str

datatype of file

Source code in src/sdss_explorer/dashboard/dataclass/state.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
class StateData:
    """Holds app-wide state variables

    Attributes:
        mapping (solara.Reactive[vx.DataFrame]): bitmappings dataframe, used for targeting filters.
        datamodel (solara.Reactive[pd.DataFrame]): column glossary dataframe

        df (solara.Reactive[vx.DataFrame]): loaded dataframe file, defaults to nothing but app will instantiate with one loaded.
        columns (solara.Reactive[dict[str,list[str]]]): column lookup, used for guardrailing.

        release (str): release type
        datatype (str): datatype of file
    """

    def __init__(self):
        # app settings, underscored to hide prop
        self._release = sl.reactive(cast(str, None))  # TODO: dr19
        self._datatype = sl.reactive(cast(str, None))

        # globally shared, read only files
        self.mapping = sl.reactive(
            open_file("mappings.parquet"))  # mappings for bitmasks
        self.datamodel = sl.reactive(load_datamodel(self.release))  # datamodel spec

        # adaptively rerendered on changes; set on startup in app root
        self.df = sl.reactive(cast(vx.DataFrame, None))  # main datafile
        self.columns = sl.reactive(cast(
            dict, None))  # column glossary for guardrailing

        # user-binded instances
        # NOTE: this approach allows UUID + subsetstore to be read-only
        self._uuid = sl.reactive(sl.get_session_id())
        self._kernel_id = sl.reactive(sl.get_kernel_id())
        self._subset_store = sl.reactive(SubsetStore())

    def load_dataset(self,
                     release: Optional[str] = None,
                     datatype: Optional[str] = None) -> bool:
        """ load the HDF5 dataset for the dashboard """
        # use attributes if not manually overridden
        if not release:
            release = self.release
        if not datatype:
            datatype = self.datatype

        # start with standard open operation
        # TODO: redux version via envvar?
        df = open_file(
            f"{release}/explorerAll{datatype.capitalize()}-{VASTRA}.hdf5")
        columns = load_column_json(release, datatype)

        if (df is None) and (columns is None):
            logger.critical(
                "Part of dataset load failed! ensure everything is setup (files, envvars)"
            )
            return False

        # set reactives
        self.df.set(df)
        self.columns.set(columns)

        return True

    @property
    def release(self) -> str:
        """Current release of app (dr19, etc)"""
        return str(self._release.value)

    @property
    def datatype(self) -> str:
        """Current datatype of app (star or visit)"""
        return str(self._datatype.value)

    def get_default_dataset(self) -> str:
        """Method version to get the default dataset of app (star or visit). Used for defaulting the Subset dataclass"""
        datatype = self._datatype.value
        return "mwmlite" if datatype == "star" else "thepayne"

    @property
    def uuid(self) -> str:
        """User ID; Solara Session ID"""
        return str(self._uuid.value)

    @property
    def kernel_id(self) -> str:
        """Virtual kernel ID"""
        return str(self._kernel_id.value)

    @property
    def subset_store(self):
        """Internal subset backend"""
        return self._subset_store.value

    def __repr__(self) -> str:
        """Show relevant properties of class as string."""
        return "\n".join(
            f"{k:15}: {v}" for k, v in {
                "uuid": self.uuid,
                "kernel_id": self.kernel_id,
                "df": hex(id(self.df.value)),  # dataframe mem address
                "subset_backend": hex(id(self.subset_store)),
                "release": self.release,
                "datatype": self.datatype,
            }.items())

datatype property #

Current datatype of app (star or visit)

kernel_id property #

Virtual kernel ID

release property #

Current release of app (dr19, etc)

subset_store property #

Internal subset backend

uuid property #

User ID; Solara Session ID

__repr__() #

Show relevant properties of class as string.

Source code in src/sdss_explorer/dashboard/dataclass/state.py
214
215
216
217
218
219
220
221
222
223
224
def __repr__(self) -> str:
    """Show relevant properties of class as string."""
    return "\n".join(
        f"{k:15}: {v}" for k, v in {
            "uuid": self.uuid,
            "kernel_id": self.kernel_id,
            "df": hex(id(self.df.value)),  # dataframe mem address
            "subset_backend": hex(id(self.subset_store)),
            "release": self.release,
            "datatype": self.datatype,
        }.items())

get_default_dataset() #

Method version to get the default dataset of app (star or visit). Used for defaulting the Subset dataclass

Source code in src/sdss_explorer/dashboard/dataclass/state.py
194
195
196
197
def get_default_dataset(self) -> str:
    """Method version to get the default dataset of app (star or visit). Used for defaulting the Subset dataclass"""
    datatype = self._datatype.value
    return "mwmlite" if datatype == "star" else "thepayne"

load_dataset(release=None, datatype=None) #

load the HDF5 dataset for the dashboard

Source code in src/sdss_explorer/dashboard/dataclass/state.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def load_dataset(self,
                 release: Optional[str] = None,
                 datatype: Optional[str] = None) -> bool:
    """ load the HDF5 dataset for the dashboard """
    # use attributes if not manually overridden
    if not release:
        release = self.release
    if not datatype:
        datatype = self.datatype

    # start with standard open operation
    # TODO: redux version via envvar?
    df = open_file(
        f"{release}/explorerAll{datatype.capitalize()}-{VASTRA}.hdf5")
    columns = load_column_json(release, datatype)

    if (df is None) and (columns is None):
        logger.critical(
            "Part of dataset load failed! ensure everything is setup (files, envvars)"
        )
        return False

    # set reactives
    self.df.set(df)
    self.columns.set(columns)

    return True

load_column_json(release, datatype) #

Load the pre-compiled column JSON for a given dataset.

Parameters:

Name Type Description Default
release str

data release directory to for

required
datatype str

specific datatype of file to load. ('star', 'visit')

required
Source code in src/sdss_explorer/dashboard/dataclass/state.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def load_column_json(release: str, datatype: str) -> dict | None:
    """Load the pre-compiled column JSON for a given dataset.

    Args:
        release: data release directory to for
        datatype: specific datatype of file to load. (`'star', 'visit'`)

    """
    # get dataset name
    datapath = settings.datapath

    # fail case for no envvar
    if datapath is None:
        return None

    file = f"{release}/columnsAll{datatype.capitalize()}-{VASTRA}.json"
    path = pathlib.Path(f"{datapath}/{file}")
    if not path.exists():
        logger.critical(
            "Expected to find %s for column lookup, didn't find it.", file)
        return None

    with open(path, 'r', encoding="utf-8") as f:
        data = json.load(f)
        return data

load_datamodel(release=None) #

Loads a given compiled datamodel, used in conjunction with the column glossary

Source code in src/sdss_explorer/dashboard/dataclass/state.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def load_datamodel(release: str = None) -> pd.DataFrame | None:
    """Loads a given compiled datamodel, used in conjunction with the column glossary"""
    datapath = settings.datapath
    # no datapath
    if datapath is None:
        return None

    # no fail found
    # TODO: replace with a real datamodel from the real things
    # TODO: this is globally set on app start; these needs to be set dynamically by the app
    #file = "ipl3_partial.json"
    release = None if release == "None" else release
    release = release or 'dr19'
    file = f"{release.lower()}_dminfo.json"


    path = pathlib.Path(f"{settings.datapath}/{file}")
    if not path.exists():
        logger.critical(
            "Expected to find %s for column glossary datamodel, didn't find it.", path
        )
        return None

    try:
        with open(f"{settings.datapath}/{file}", "r", encoding='utf-8') as f:
            data = json.load(f).values()
    except Exception as e:
        logger.debug("caught exception on datamodel loader: %s", e)
        return None
    else:
        logger.info('successfully loaded datamodel')
        return pd.DataFrame(data)  # TODO: back to vaex

open_file(filename) #

Vaex open wrapper for datafiles to ensure authorization/file finding.

Parameters:

Name Type Description Default
filename str

filename to open

required
Source code in src/sdss_explorer/dashboard/dataclass/state.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def open_file(filename):
    """Vaex open wrapper for datafiles to ensure authorization/file finding.

    Args:
        filename (str): filename to open

    """
    # get dataset name
    datapath = settings.datapath

    # fail case for no envvar
    if datapath is None:
        return None

    # TODO: verify auth status when attempting to load a working group dataset
    try:
        dataset = vx.open(f"{datapath}/{filename}")
        dataset = dataset.shuffle(
            random_state=42
        )  # shuffle to ensure skyplot looks nice, constant seed for reproducibility
        return dataset
    except FileNotFoundError:
        logger.critical(
            "Expected to find %s for dataframe, didn't find it.", filename)
        return None
    except Exception as e:
        logger.debug("caught exception on dataframe load: %s", e)
        return None