Fix broken "Cell Output Must Be at the Top Level" example in notebook patterns
The previous "FIXED" example still had mo.md() called as a side effect inside if/else blocks (never rendered) while mixing it with a DataFrame in the same cell. Replace with the correct pattern: split into separate cells where each displays exactly one thing at the top level.
This commit is contained in:
@@ -83,7 +83,7 @@ def fetch_details(client, DATAINDEX, results):
|
||||
|
||||
Marimo only renders the **last expression at the top level** of a cell as rich output. An expression buried inside an `if`/`else`, `for`, `try`, or any other block is **not** displayed — it's silently discarded.
|
||||
|
||||
**BROKEN** — `_df` inside the `if` branch is never rendered:
|
||||
**BROKEN** — `_df` inside the `if` branch is never rendered, and `mo.md()` inside `if`/`else` is also discarded:
|
||||
|
||||
```python
|
||||
@app.cell
|
||||
@@ -93,26 +93,35 @@ def show_results(results, mo):
|
||||
mo.md(f"**Found {len(results)} results**")
|
||||
_df # Inside an if block — marimo does NOT display this
|
||||
else:
|
||||
mo.md("**No results found**")
|
||||
mo.md("**No results found**") # Also inside a block — NOT displayed
|
||||
return
|
||||
```
|
||||
|
||||
**FIXED** — assign inside the branches, display at the top level:
|
||||
**FIXED** — split into separate cells. Each cell displays exactly **one thing** at the top level:
|
||||
|
||||
```python
|
||||
# Cell 1: build the data, return it
|
||||
@app.cell
|
||||
def show_results(results, mo):
|
||||
_output = None
|
||||
if results:
|
||||
_output = pl.DataFrame(results)
|
||||
mo.md(f"**Found {len(results)} results**")
|
||||
else:
|
||||
mo.md("**No results found**")
|
||||
_output # Top-level last expression — marimo renders this
|
||||
return
|
||||
def build_results(results, pl):
|
||||
results_df = pl.DataFrame(results) if results else None
|
||||
return (results_df,)
|
||||
|
||||
# Cell 2: heading — mo.md() is the top-level expression (use ternary for conditional text)
|
||||
@app.cell
|
||||
def show_results_heading(results_df, mo):
|
||||
mo.md(f"**Found {len(results_df)} results**" if results_df is not None else "**No results found**")
|
||||
|
||||
# Cell 3: table — DataFrame is the top-level expression
|
||||
@app.cell
|
||||
def show_results_table(results_df):
|
||||
results_df # Top-level expression — marimo renders this as interactive table
|
||||
```
|
||||
|
||||
**Rule of thumb:** initialize a `_output = None` variable before any conditional, assign the displayable value inside the branches, then put `_output` as the last top-level expression. When it's `None` (e.g., the `else` path), marimo shows nothing — which is fine since the `mo.md()` already provides feedback.
|
||||
**Rules:**
|
||||
- Each cell should display **one thing** — either `mo.md()` OR a DataFrame, never both
|
||||
- `mo.md()` must be a **top-level expression**, not inside `if`/`else`/`for`/`try` blocks
|
||||
- Build conditional text using variables or ternary expressions, then call `mo.md(_text)` at the top level
|
||||
- For DataFrames, use a standalone display cell: `def show_table(df): df`
|
||||
|
||||
### Async Cells
|
||||
|
||||
|
||||
Reference in New Issue
Block a user