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

Add recipe for using lists for state #2928

Closed

Conversation

liquidcarbon
Copy link
Contributor

📝 Summary

Example of using lists to hold initial state for triggering computation with a button

🔍 Description of Changes

Ideas from #2738 (comment)

📋 Checklist

  • I have read the contributor guidelines.
  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • I have added tests for the changes made.
  • I have run the code and verified that it works as expected.

Copy link

vercel bot commented Nov 22, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
marimo-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 22, 2024 1:33pm
marimo-storybook ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 22, 2024 1:33pm

@dmadisetti
Copy link
Collaborator

dmadisetti commented Nov 22, 2024

Hmm, read the thread- but I've always thought this was more of an antipattern. Thought on this?

value = "No joke"

mo.stop(not button.value)
value = text.value.upper()

text, button, value

@liquidcarbon
Copy link
Contributor Author

liquidcarbon commented Nov 22, 2024

That condition won't do anything, run_button's value is either True or False
If you meant not button.value you'd never see the output, because button's initial value is False

@dmadisetti
Copy link
Collaborator

Woops! Yes. Edited for correctness.

But this gets around carrying state outside of mo.State

There's an experimental "Strict Execution" mode, where this will intentionally fail

@mscolnick
Copy link
Contributor

mscolnick commented Nov 22, 2024

i agree with @dmadisetti, i think this is an anti-pattern because you are modifying state, which we are trying avoid mutations (similar to how React works)

@liquidcarbon
Copy link
Contributor Author

liquidcarbon commented Nov 22, 2024

Well... shall it be called out as un-encouraged hack?

This recipe

mo.stop(not button.value, "Click 'run' to generate a random number")

import random
random.randint(0, 1000)

is too simplistic - what if you need to the run button to modify a pre-existing variable or UI value?

My original question to @akshayka was how would you do this without state, his answer seemed very simple and practical. What would you suggest?

Do forms work via state?

@akshayka
Copy link
Contributor

I actually think stashing state in a non-reactive object (such as a Python list) can be simpler than using reactive state. I have noticed when people use reactive state, they have a difficult time reasoning about why cells are running and end up creating bugs that are hard to catch.

With non-reactive state, execution is still determined by the DAG. For this reason I personally prefer this pattern. I hadn't documented it because it does feel "advanced".

@akshayka
Copy link
Contributor

The ideal recipe would be something like @dmadisetti's suggestion, though I think it doesn't do quite what @liquidcarbon is trying to do.

@liquidcarbon
Copy link
Contributor Author

liquidcarbon commented Nov 22, 2024

value = "No joke" 

mo.stop(not button.value)
value = text.value.upper()

text, button, value  # this is in the next cell, or UI will never show up because initial button.value is False

In @dmadisetti 's example the form will always reset to this initial value; it's fine in some cases, but if you have a lot of parameters, they will all reset, on moving from field to field because the cell with mo.stop(not button.value) will reevaluate and you won't be able to populate the form at all.

I'd like to have a default, pre-populated UI with either 1) examples of how to use it, or 2) from query params;
and 3) that will stay intact until I click the button.

Like this:

MarimoChuckNorris.webm

@liquidcarbon
Copy link
Contributor Author

Appreciate the discussion, I'm learning something! :)

@akshayka
Copy link
Contributor

akshayka commented Nov 23, 2024

@liquidcarbon, after reflecting I think this is too advanced or niche to add to the recipes — marimo already introduces so many new concepts I'm worried our users will get confused. Sorry to lead you astray.

Here is a simpler recipe that I believe does what you need, using form() and without using any kind of state.

If it does do what you need, want to change the recipe to this?

https://marimo.app/l/cdiigo

import marimo

__generated_with = "0.9.21"
app = marimo.App(width="medium")


@app.cell
def __():
    import marimo as mo
    return (mo,)


@app.cell
def __(mo):
    form = mo.ui.text(label="Enter text").form(submit_button_label="capitalize", bordered=False)
    form
    return (form,)


@app.cell
def __(form):
    form.value.upper() if form.value is not None else "Here is my initial value"
    return


if __name__ == "__main__":
    app.run()

@liquidcarbon
Copy link
Contributor Author

liquidcarbon commented Nov 23, 2024

Sure, your call! The code is findable in this PR.

I prefer the run_button over the form because:

  1. form creates a large block that's harder to place and customize (maybe takes practice)
  2. you can bind a customizable hotkey
  3. mo.ui.code_editor UI improvements #2921

But for a recipe, how about:

examples = {"t1": "hello", "t2": "world"}
form = (
    mo.md('''
    ### Your form
    
    {t1}
    {t2}
''')
    .batch(
        t1=mo.ui.text(label="enter text", value=examples.get("t1")),
        t2=mo.ui.text(label="enter more text", value=examples.get("t2")),
    )
    .form(submit_button_label="go")  # <-- taking "value=examples" would be nice here
)
output = (
    " ".join(form.value.values()).upper()
    if form.value is not None
    else " ".join(examples.values()).upper()
)
form, output

@akshayka
Copy link
Contributor

@liquidcarbon, sorry I missed your edits. That recipe looks good to me, if you'd like to update the PR.

@liquidcarbon
Copy link
Contributor Author

I'll open a new one. This latest suggestion is a lot like gradio examples; the original idea was quite different.

@liquidcarbon liquidcarbon mentioned this pull request Nov 26, 2024
4 tasks
mscolnick pushed a commit that referenced this pull request Nov 26, 2024
## 📝 Summary

Provides recipes for pre-populating forms from examples or query
parameters

## 🔍 Description of Changes

[New form recipe](https://marimo.app/l/w21a3x?t1=query&t2=params)
Less hacky #2928 :)

## 📋 Checklist

- [x] I have read the [contributor
guidelines](https://github.com/marimo-team/marimo/blob/main/CONTRIBUTING.md).
- [x] For large changes, or changes that affect the public API: this
change was discussed or approved through an issue, on
[Discord](https://marimo.io/discord?ref=pr), or the community
[discussions](https://github.com/marimo-team/marimo/discussions) (Please
provide a link if applicable).
- [x] I have added tests for the changes made.
- [x] I have run the code and verified that it works as expected.
Light2Dark pushed a commit to Light2Dark/marimo that referenced this pull request Nov 27, 2024
## 📝 Summary

Provides recipes for pre-populating forms from examples or query
parameters

## 🔍 Description of Changes

[New form recipe](https://marimo.app/l/w21a3x?t1=query&t2=params)
Less hacky marimo-team#2928 :)

## 📋 Checklist

- [x] I have read the [contributor
guidelines](https://github.com/marimo-team/marimo/blob/main/CONTRIBUTING.md).
- [x] For large changes, or changes that affect the public API: this
change was discussed or approved through an issue, on
[Discord](https://marimo.io/discord?ref=pr), or the community
[discussions](https://github.com/marimo-team/marimo/discussions) (Please
provide a link if applicable).
- [x] I have added tests for the changes made.
- [x] I have run the code and verified that it works as expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants