| | import marimo as mo |
| | import json |
| |
|
| |
|
| | def create_widgets(widget_type, values, widget_dict=None, stack=None): |
| | """ |
| | Create marimo widgets for a list of values. |
| | |
| | Args: |
| | widget_type: Default marimo widget type (e.g., mo.ui.text_area) |
| | values: List of values to create widgets for |
| | widget_dict: Optional dict mapping specific values to widget types |
| | stack: 'horizontal' for hstack, 'vertical' for vstack, None for dict return |
| | """ |
| | widgets = {} |
| |
|
| | for value in values: |
| | |
| | current_widget_type = ( |
| | widget_dict.get(value, widget_type) if widget_dict else widget_type |
| | ) |
| | widgets[value] = current_widget_type(label=f"**{str(value)}**") |
| |
|
| | if stack == "horizontal": |
| | return mo.hstack(list(widgets.values()), gap=1) |
| | elif stack == "vertical": |
| | return mo.vstack(list(widgets.values()), gap=1) |
| | else: |
| | return widgets |
| |
|
| |
|
| | def json_to_marimo_ui( |
| | data, |
| | replicate_values=False, |
| | label="", |
| | label_containers=False, |
| | label_nested_leaves=False, |
| | ): |
| | """ |
| | Convert a JSON structure to marimo UI elements. |
| | |
| | Args: |
| | data: JSON-like dict/list, or mo.ui.file element containing JSON |
| | replicate_values: If True, populate widgets with existing values; if False, leave empty |
| | label: Optional label for the root element |
| | label_containers: If True, apply labels to nested dicts/arrays (causes double nesting display); |
| | if False (default), only label leaf input widgets |
| | label_nested_leaves: If True, label leaf widgets with their key names; |
| | if False (default), only root label is applied, nested leaves have no labels |
| | |
| | Returns: |
| | mo.ui.dictionary for dicts, mo.ui.array for lists |
| | """ |
| | |
| | |
| |
|
| | |
| | if hasattr(data, "contents") and callable(data.contents): |
| | file_contents = data.contents() |
| | if file_contents is None: |
| | return mo.ui.dictionary({}, label=label) |
| | if isinstance(file_contents, bytes): |
| | file_contents = file_contents.decode("utf-8") |
| | data = json.loads(file_contents) |
| |
|
| | def _convert(obj, replicate, lbl="", is_root=False): |
| | if isinstance(obj, dict): |
| | elements = { |
| | str(key): _convert( |
| | value, |
| | replicate, |
| | lbl=str(key) if label_nested_leaves else "", |
| | ) |
| | for key, value in obj.items() |
| | } |
| | container_label = lbl if (is_root or label_containers) else "" |
| | return mo.ui.dictionary(elements, label=container_label) |
| |
|
| | elif isinstance(obj, list): |
| | if not obj: |
| | container_label = lbl if (is_root or label_containers) else "" |
| | return mo.ui.array([], label=container_label) |
| | elements = [ |
| | _convert(item, replicate, lbl="" if not label_nested_leaves else "") |
| | for item in obj |
| | ] |
| | container_label = lbl if (is_root or label_containers) else "" |
| | return mo.ui.array(elements, label=container_label) |
| |
|
| | elif isinstance(obj, bool): |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | return mo.ui.checkbox( |
| | value=obj if replicate else False, |
| | label=leaf_label, |
| | ) |
| |
|
| | elif isinstance(obj, int): |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | return mo.ui.number( |
| | value=obj if replicate else None, |
| | label=leaf_label, |
| | full_width=True, |
| | ) |
| |
|
| | elif isinstance(obj, float): |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | return mo.ui.number( |
| | value=obj if replicate else None, |
| | step=0.01, |
| | label=leaf_label, |
| | full_width=True, |
| | ) |
| |
|
| | elif isinstance(obj, str): |
| | val = obj if replicate else "" |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | if len(obj) > 40: |
| | return mo.ui.text_area(value=val, label=leaf_label, full_width=True) |
| | return mo.ui.text(value=val, label=leaf_label, full_width=True) |
| |
|
| | elif obj is None: |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | return mo.ui.text(value="", label=leaf_label, full_width=True) |
| |
|
| | else: |
| | leaf_label = lbl if (is_root or label_nested_leaves) else "" |
| | return mo.ui.text( |
| | value=str(obj) if replicate else "", |
| | label=leaf_label, |
| | full_width=True, |
| | ) |
| |
|
| | return _convert(data, replicate_values, label, is_root=True) |
| |
|
| |
|
| | def create_download_button( |
| | widget_value, filename_prefix="download", add_uuid_suffix=True |
| | ): |
| | """Create a marimo download button appropriate for the widget value type. |
| | |
| | Automatically detects data type and creates download button with correct format and MIME type. |
| | |
| | Args: |
| | widget_value: Data to download (dict/list as JSON, DataFrames as CSV, |
| | str as text, bytes as binary, others converted to string) |
| | filename_prefix (str): Filename prefix. Defaults to "download". |
| | add_uuid_suffix (bool): Add 4-char UUID suffix to filename. Defaults to True. |
| | |
| | Returns: |
| | mo.download: Configured marimo download button widget. |
| | |
| | Examples: |
| | >>> data = {"key": "value", "numbers": [1, 2, 3]} |
| | >>> button = create_download_button(data, "my_data") |
| | |
| | >>> df = pd.DataFrame({"A": [1, 2], "B": [3, 4]}) |
| | >>> button = create_download_button(df, "dataframe") |
| | |
| | Note: |
| | Requires marimo (mo) and uuid modules. JSON formatted with 2-space indent. |
| | CSV exports exclude index for pandas DataFrames. |
| | """ |
| | import marimo as mo |
| | import json |
| | import uuid |
| |
|
| | if isinstance(widget_value, dict) or isinstance(widget_value, list): |
| | |
| | data = json.dumps(widget_value, indent=2) |
| | filename = f"{filename_prefix}.json" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.json" |
| | return mo.download( |
| | data=data.encode(), filename=filename, mimetype="application/json" |
| | ) |
| |
|
| | elif hasattr(widget_value, "to_csv"): |
| | |
| | data = widget_value.to_csv(index=False) |
| | filename = f"{filename_prefix}.csv" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.csv" |
| | return mo.download(data=data.encode(), filename=filename, mimetype="text/csv") |
| |
|
| | elif hasattr(widget_value, "write_csv"): |
| | |
| | data = widget_value.write_csv() |
| | filename = f"{filename_prefix}.csv" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.csv" |
| | return mo.download(data=data.encode(), filename=filename, mimetype="text/csv") |
| |
|
| | elif isinstance(widget_value, str): |
| | |
| | filename = f"{filename_prefix}.txt" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.txt" |
| | return mo.download( |
| | data=widget_value.encode(), |
| | filename=filename, |
| | mimetype="text/plain", |
| | ) |
| |
|
| | elif isinstance(widget_value, bytes): |
| | |
| | filename = f"{filename_prefix}.bin" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.bin" |
| | return mo.download( |
| | data=widget_value, |
| | filename=filename, |
| | mimetype="application/octet-stream", |
| | ) |
| |
|
| | else: |
| | |
| | data = str(widget_value) |
| | filename = f"{filename_prefix}.txt" |
| | if add_uuid_suffix: |
| | uuid_suffix = str(uuid.uuid4())[:4] |
| | filename = f"{filename_prefix}_{uuid_suffix}.txt" |
| | return mo.download(data=data.encode(), filename=filename, mimetype="text/plain") |
| |
|
| |
|
| | if __name__ == "__main__": |
| | print("Only Importable in Marimo Notebooks") |
| |
|