diff --git a/.github/workflows/export-notebooks.yml b/.github/workflows/export-notebooks.yml index 64126a2..f9f1b76 100644 --- a/.github/workflows/export-notebooks.yml +++ b/.github/workflows/export-notebooks.yml @@ -5,9 +5,12 @@ on: repository_dispatch: types: [marimo-release] - # Trigger on push to main + # Trigger on push to main, but ignore if in generated files push: branches: [main] + paths-ignore: + - 'generated/**' + - 'public/**' # Trigger nightly schedule: @@ -17,7 +20,10 @@ on: workflow_dispatch: {} permissions: + pull-requests: write contents: write + pages: write + id-token: write env: UV_SYSTEM_PYTHON: 1 @@ -40,6 +46,7 @@ jobs: - name: ๐Ÿ“ฆ Install marimo run: | uv pip install marimo + uv pip install nbformat polars altair vega_datasets matplotlib pandas - name: ๐Ÿ“‚ Clone marimo examples run: | @@ -71,4 +78,31 @@ jobs: automated assignees: | mscolnick - add-paths: 'generated/*' + add-paths: | + generated/* + public/* + + deploy: + needs: export-notebooks + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: ๐Ÿ“ฅ Download artifact + uses: actions/download-artifact@v4 + with: + name: github-pages + + - name: ๐Ÿ“ฆ Setup Pages + uses: actions/configure-pages@v4 + + - name: ๐Ÿš€ Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: public + + - name: ๐ŸŒ Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 496589c..ed95c00 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ Automated CI pipeline for validating and exporting [marimo](https://github.com/m - Automatically exports whitelisted marimo notebooks: - to markdown - - (soon) to HTML - - (soon) to ipynb - - (soon) to script + - to HTML + - to ipynb + - to script - Triggers on: - (todo) New marimo releases - Pushes to main from this repo diff --git a/generated/examples/ui/arrays_and_dicts.py.ipynb b/generated/examples/ui/arrays_and_dicts.py.ipynb new file mode 100644 index 0000000..5bbca05 --- /dev/null +++ b/generated/examples/ui/arrays_and_dicts.py.ipynb @@ -0,0 +1,178 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Arrays and Dictionaries" + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "Use `mo.ui.array` and `mo.ui.dictionary` to create UI elements that wrap\n", + "other elements.\n", + "\n", + "Because UI elements must be assigned to global variables,\n", + "these functions are required when the set of elements to create is not\n", + "known until runtime." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "create = mo.ui.button(label=\"Create new collections\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "create.center()" + ] + }, + { + "cell_type": "markdown", + "id": "lEQa", + "metadata": {}, + "source": [ + "UI Elements ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "create\n", + "\n", + "array = mo.ui.array(\n", + " [mo.ui.text()]\n", + " + [mo.ui.slider(1, 10) for _ in range(0, random.randint(2, 5))],\n", + ")\n", + "dictionary = mo.ui.dictionary(\n", + " {str(i): mo.ui.slider(1, 10) for i in range(0, random.randint(2, 5))}\n", + ")\n", + "\n", + "mo.hstack([array, dictionary], justify=\"space-around\")" + ] + }, + { + "cell_type": "markdown", + "id": "Xref", + "metadata": {}, + "source": [ + "... and their values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack([array.value, dictionary.value], justify=\"space-around\")" + ] + }, + { + "cell_type": "markdown", + "id": "BYtC", + "metadata": {}, + "source": [ + "Key difference between marimo dict and standard python dict:\n", + "\n", + "The main reason to use `mo.ui.dictionary` is for reactive execution โ€” when you interact with an element in a `mo.ui.dictionary`, all cells that reference the `mo.ui.dictionary` run automatically, just like all other ui elements. When you use a regular dictionary, you don't get this reactivity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "RGSE", + "metadata": {}, + "outputs": [], + "source": [ + "create\n", + "\n", + "slider = mo.ui.slider(1, 10, show_value=True)\n", + "text = mo.ui.text()\n", + "date = mo.ui.date()\n", + "\n", + "mo_d = mo.ui.dictionary(\n", + " {\n", + " \"slider\": slider,\n", + " \"text\": text,\n", + " \"date\": date,\n", + " }\n", + ")\n", + "\n", + "py_d = {\n", + " \"slider\": slider,\n", + " \"text\": text,\n", + " \"date\": date,\n", + "}\n", + "\n", + "mo.hstack(\n", + " [\n", + " mo.vstack([\"marimo dict\", mo_d]),\n", + " mo.vstack([\"original elements\", mo.vstack([slider, text, date])]),\n", + " mo.vstack([\"python dict\", py_d]),\n", + " ],\n", + " justify=\"space-around\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Kclp", + "metadata": {}, + "outputs": [], + "source": [ + "mo_d_ref = {k: mo_d[k].value for k in mo_d.value.keys()}\n", + "py_d_ref = {k: py_d[k].value for k in py_d.keys()}\n", + "mo.hstack(\n", + " [\n", + " mo.vstack([\"reference of marimo dict\", mo_d_ref]),\n", + " mo.vstack([\"reference of python dict\", py_d_ref]),\n", + " ],\n", + " justify=\"space-around\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "emfo", + "metadata": {}, + "source": [ + "Notice that when you interact with the UI elements in the marimo dict, the reference of marimo dict updates automatically. However, when you interact with the elements in the python dict, you need to manually re-run the cell to see the updated values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Hstk", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo\n", + "import random" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/arrays_and_dicts.script.py b/generated/examples/ui/arrays_and_dicts.script.py new file mode 100644 index 0000000..8522cbf --- /dev/null +++ b/generated/examples/ui/arrays_and_dicts.script.py @@ -0,0 +1,102 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo +import random + +# %% +mo.md( + """ + Use `mo.ui.array` and `mo.ui.dictionary` to create UI elements that wrap + other elements. + + Because UI elements must be assigned to global variables, + these functions are required when the set of elements to create is not + known until runtime. + """ +) + +# %% +mo.md( + r""" + Key difference between marimo dict and standard python dict: + + The main reason to use `mo.ui.dictionary` is for reactive execution โ€” when you interact with an element in a `mo.ui.dictionary`, all cells that reference the `mo.ui.dictionary` run automatically, just like all other ui elements. When you use a regular dictionary, you don't get this reactivity. + """ +) + +# %% +create = mo.ui.button(label="Create new collections") + +# %% +mo.md("""UI Elements ...""") + +# %% +mo.md(r"""Notice that when you interact with the UI elements in the marimo dict, the reference of marimo dict updates automatically. However, when you interact with the elements in the python dict, you need to manually re-run the cell to see the updated values.""") + +# %% +mo.md("""... and their values""") + +# %% +mo.md("""# Arrays and Dictionaries""") + +# %% +create.center() + +# %% +create + +slider = mo.ui.slider(1, 10, show_value=True) +text = mo.ui.text() +date = mo.ui.date() + +mo_d = mo.ui.dictionary( + { + "slider": slider, + "text": text, + "date": date, + } +) + +py_d = { + "slider": slider, + "text": text, + "date": date, +} + +mo.hstack( + [ + mo.vstack(["marimo dict", mo_d]), + mo.vstack(["original elements", mo.vstack([slider, text, date])]), + mo.vstack(["python dict", py_d]), + ], + justify="space-around", +) + +# %% +create + +array = mo.ui.array( + [mo.ui.text()] + + [mo.ui.slider(1, 10) for _ in range(0, random.randint(2, 5))], +) +dictionary = mo.ui.dictionary( + {str(i): mo.ui.slider(1, 10) for i in range(0, random.randint(2, 5))} +) + +mo.hstack([array, dictionary], justify="space-around") + +# %% +mo_d_ref = {k: mo_d[k].value for k in mo_d.value.keys()} +py_d_ref = {k: py_d[k].value for k in py_d.keys()} +mo.hstack( + [ + mo.vstack(["reference of marimo dict", mo_d_ref]), + mo.vstack(["reference of python dict", py_d_ref]), + ], + justify="space-around", +) + +# %% +mo.hstack([array.value, dictionary.value], justify="space-around") \ No newline at end of file diff --git a/generated/examples/ui/batch_and_form.py.ipynb b/generated/examples/ui/batch_and_form.py.ipynb new file mode 100644 index 0000000..855f5fb --- /dev/null +++ b/generated/examples/ui/batch_and_form.py.ipynb @@ -0,0 +1,112 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Batch and Form" + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "Make custom UI elements using `batch()`, and turn any UI element\n", + "into a form with `form()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "reset\n", + "\n", + "variables = (\n", + " mo.md(\n", + " \"\"\"\n", + " Choose your variable values\n", + "\n", + " {x}\n", + "\n", + " {y}\n", + " \"\"\"\n", + " )\n", + " .batch(\n", + " x=mo.ui.slider(start=1, stop=10, step=1, label=\"$x =$\"),\n", + " y=mo.ui.slider(start=1, stop=10, step=1, label=\"$y =$\"),\n", + " )\n", + " .form(show_clear_button=True, bordered=False)\n", + ")\n", + "\n", + "variables" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "if variables.value is not None:\n", + " submitted_values[\"x\"].add(variables.value[\"x\"])\n", + " submitted_values[\"y\"].add(variables.value[\"y\"])\n", + "\n", + "x = variables.value[\"x\"] if variables.value else \"\\ldots\"\n", + "y = variables.value[\"y\"] if variables.value else \"\\ldots\"\n", + "\n", + "\n", + "mo.md(\n", + " f\"\"\"\n", + " At the moment,\n", + " $x = {x}$ and $y = {y}$\n", + "\n", + " All values ever assumed by $x$ and $y$ are\n", + "\n", + " {mo.hstack([mo.tree(submitted_values), reset], align=\"center\", gap=4)}\n", + " \"\"\"\n", + ").callout()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "reset\n", + "\n", + "submitted_values = {\"x\": set(), \"y\": set()}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "reset = mo.ui.button(label=\"reset history\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/batch_and_form.script.py b/generated/examples/ui/batch_and_form.script.py new file mode 100644 index 0000000..008d5a2 --- /dev/null +++ b/generated/examples/ui/batch_and_form.script.py @@ -0,0 +1,66 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +mo.md( + """ + Make custom UI elements using `batch()`, and turn any UI element + into a form with `form()`. + """ +) + +# %% +reset = mo.ui.button(label="reset history") + +# %% +mo.md("""# Batch and Form""") + +# %% +reset + +submitted_values = {"x": set(), "y": set()} + +# %% +reset + +variables = ( + mo.md( + """ + Choose your variable values + + {x} + + {y} + """ + ) + .batch( + x=mo.ui.slider(start=1, stop=10, step=1, label="$x =$"), + y=mo.ui.slider(start=1, stop=10, step=1, label="$y =$"), + ) + .form(show_clear_button=True, bordered=False) +) + +variables + +# %% +if variables.value is not None: + submitted_values["x"].add(variables.value["x"]) + submitted_values["y"].add(variables.value["y"]) + +x = variables.value["x"] if variables.value else "\ldots" +y = variables.value["y"] if variables.value else "\ldots" + + +mo.md( + f""" + At the moment, + $x = {x}$ and $y = {y}$ + + All values ever assumed by $x$ and $y$ are + + {mo.hstack([mo.tree(submitted_values), reset], align="center", gap=4)} + """ +).callout() \ No newline at end of file diff --git a/generated/examples/ui/data_explorer.py.ipynb b/generated/examples/ui/data_explorer.py.ipynb new file mode 100644 index 0000000..69ba1d5 --- /dev/null +++ b/generated/examples/ui/data_explorer.py.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Data Explorer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "sample = \"https://github.com/vega/vega/blob/main/docs/data/stocks.csv\"\n", + "\n", + "mo.md(\n", + " f\"\"\"\n", + " This notebook lets you upload a CSV and plot its columns.\n", + "\n", + " You can download a sample CSV if you'd like.\n", + " \"\"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "mo.md(\n", + " f\"\"\"\n", + " {mo.hstack([mo.md(\"**Upload a CSV.**\")], justify=\"center\")}\n", + "\n", + " {uploaded_file}\n", + " \"\"\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mo.stop(not uploaded_file.name())\n", + "df = pd.read_csv(io.StringIO(uploaded_file.contents().decode()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "mo.ui.table(df, page_size=5, selection=None)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "plot_type = mo.ui.dropdown(\n", + " [\"line\", \"hist\"], value=\"line\", label=\"Choose a plot type: \"\n", + ")\n", + "\n", + "x_column = mo.ui.dropdown(df.columns, label=\"Choose x-axis: \")\n", + "y_column = mo.ui.dropdown(df.columns, label=\"Choose y-axis: \")\n", + "color_column = mo.ui.dropdown(df.columns, label=\"Choose color-axis: \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack(\n", + " [x_column, y_column, color_column, plot_type], justify=\"space-around\"\n", + ").callout(kind=\"warn\" if not x_column.value else \"neutral\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "mo.stop(not x_column.value)\n", + "\n", + "\n", + "def plot(x_column, y_column, color_column):\n", + " y_column = y_column or \"count()\"\n", + " title = f\"{y_column} by {x_column}\"\n", + " encoding = {\"x\": x_column, \"y\": y_column}\n", + " if color_column:\n", + " encoding[\"color\"] = color_column\n", + " if plot_type.value == \"line\":\n", + " chart = alt.Chart(df).mark_line()\n", + " else:\n", + " chart = alt.Chart(df).mark_bar().encode(x=alt.X(x_column, bin=True))\n", + " return chart.encode(**encoding).properties(title=title, width=\"container\")\n", + "\n", + "\n", + "plot(x_column.value, y_column.value, color_column.value)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "BYtC", + "metadata": {}, + "outputs": [], + "source": [ + "uploaded_file = mo.ui.file(filetypes=[\".csv\"], kind=\"area\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "RGSE", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo\n", + "import altair as alt\n", + "\n", + "\n", + "import io\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/data_explorer.script.py b/generated/examples/ui/data_explorer.script.py new file mode 100644 index 0000000..1bb108d --- /dev/null +++ b/generated/examples/ui/data_explorer.script.py @@ -0,0 +1,77 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo +import altair as alt + + +import io +import matplotlib.pyplot as plt +import pandas as pd + +# %% +mo.md("""# Data Explorer""") + +# %% +sample = "https://github.com/vega/vega/blob/main/docs/data/stocks.csv" + +mo.md( + f""" + This notebook lets you upload a CSV and plot its columns. + + You can download a sample CSV if you'd like. + """ +) + +# %% +uploaded_file = mo.ui.file(filetypes=[".csv"], kind="area") + +# %% +mo.stop(not uploaded_file.name()) +df = pd.read_csv(io.StringIO(uploaded_file.contents().decode())) + +# %% +mo.md( + f""" + {mo.hstack([mo.md("**Upload a CSV.**")], justify="center")} + + {uploaded_file} + """ +) + +# %% +mo.ui.table(df, page_size=5, selection=None) + +# %% +plot_type = mo.ui.dropdown( + ["line", "hist"], value="line", label="Choose a plot type: " +) + +x_column = mo.ui.dropdown(df.columns, label="Choose x-axis: ") +y_column = mo.ui.dropdown(df.columns, label="Choose y-axis: ") +color_column = mo.ui.dropdown(df.columns, label="Choose color-axis: ") + +# %% +mo.hstack( + [x_column, y_column, color_column, plot_type], justify="space-around" +).callout(kind="warn" if not x_column.value else "neutral") + +# %% +mo.stop(not x_column.value) + + +def plot(x_column, y_column, color_column): + y_column = y_column or "count()" + title = f"{y_column} by {x_column}" + encoding = {"x": x_column, "y": y_column} + if color_column: + encoding["color"] = color_column + if plot_type.value == "line": + chart = alt.Chart(df).mark_line() + else: + chart = alt.Chart(df).mark_bar().encode(x=alt.X(x_column, bin=True)) + return chart.encode(**encoding).properties(title=title, width="container") + + +plot(x_column.value, y_column.value, color_column.value) \ No newline at end of file diff --git a/generated/examples/ui/filterable_table.py.ipynb b/generated/examples/ui/filterable_table.py.ipynb new file mode 100644 index 0000000..b013b0f --- /dev/null +++ b/generated/examples/ui/filterable_table.py.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Filterable DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "# Read the csv\n", + "df = pd.read_json(data_url(\"cars.json\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "# Create options for select widgets\n", + "manufacturer_options = df[\"Name\"].str.split().str[0].unique()\n", + "manufacturer_options.sort()\n", + "cylinder_options = df[\"Cylinders\"].unique().astype(str)\n", + "cylinder_options.sort()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "# Create the filters\n", + "manufacturer = mo.ui.dropdown(manufacturer_options, label=\"Manufacturer\")\n", + "cylinders = mo.ui.dropdown(cylinder_options, label=\"Cylinders\")\n", + "\n", + "horse_power = mo.ui.range_slider.from_series(\n", + " df[\"Horsepower\"],\n", + " show_value=True,\n", + ")\n", + "\n", + "mo.hstack([manufacturer, horse_power, cylinders], gap=3).left()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "filter_df(df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "def filter_df(df):\n", + " filtered_df = df\n", + " if manufacturer.value:\n", + " filtered_df = filtered_df[\n", + " filtered_df[\"Name\"].str.contains(manufacturer.value, case=False)\n", + " ]\n", + " if cylinders.value:\n", + " filtered_df = filtered_df[filtered_df[\"Cylinders\"] == cylinders.value]\n", + " if horse_power.value:\n", + " left, right = horse_power.value\n", + " filtered_df = filtered_df[\n", + " (filtered_df[\"Horsepower\"] >= left)\n", + " & (filtered_df[\"Horsepower\"] <= right)\n", + " ]\n", + " return filtered_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "def data_url(file):\n", + " return f\"https://cdn.jsdelivr.net/npm/vega-datasets@v1.29.0/data/{file}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo\n", + "import pandas as pd" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/filterable_table.script.py b/generated/examples/ui/filterable_table.script.py new file mode 100644 index 0000000..91f46c2 --- /dev/null +++ b/generated/examples/ui/filterable_table.script.py @@ -0,0 +1,56 @@ + +__generated_with = "0.9.30" + +# %% +def data_url(file): + return f"https://cdn.jsdelivr.net/npm/vega-datasets@v1.29.0/data/{file}" + +# %% +import marimo as mo +import pandas as pd + +# %% +# Read the csv +df = pd.read_json(data_url("cars.json")) + +# %% +mo.md(r"""# Filterable DataFrame""") + +# %% +# Create options for select widgets +manufacturer_options = df["Name"].str.split().str[0].unique() +manufacturer_options.sort() +cylinder_options = df["Cylinders"].unique().astype(str) +cylinder_options.sort() + +# %% +# Create the filters +manufacturer = mo.ui.dropdown(manufacturer_options, label="Manufacturer") +cylinders = mo.ui.dropdown(cylinder_options, label="Cylinders") + +horse_power = mo.ui.range_slider.from_series( + df["Horsepower"], + show_value=True, +) + +mo.hstack([manufacturer, horse_power, cylinders], gap=3).left() + +# %% +def filter_df(df): + filtered_df = df + if manufacturer.value: + filtered_df = filtered_df[ + filtered_df["Name"].str.contains(manufacturer.value, case=False) + ] + if cylinders.value: + filtered_df = filtered_df[filtered_df["Cylinders"] == cylinders.value] + if horse_power.value: + left, right = horse_power.value + filtered_df = filtered_df[ + (filtered_df["Horsepower"] >= left) + & (filtered_df["Horsepower"] <= right) + ] + return filtered_df + +# %% +filter_df(df) \ No newline at end of file diff --git a/generated/examples/ui/inputs.py.ipynb b/generated/examples/ui/inputs.py.ipynb new file mode 100644 index 0000000..113331a --- /dev/null +++ b/generated/examples/ui/inputs.py.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Inputs\n", + "\n", + "There are many way that a user can input with your notebook, such as text boxes, sliders, dates, and more." + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "## Text boxes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack(\n", + " [\n", + " username := mo.ui.text(label=\"Username\"),\n", + " email := mo.ui.text(label=\"Email\", kind=\"email\"),\n", + " mo.ui.text(label=\"Password\", kind=\"password\"),\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mo.stop(not username.value, mo.md(\"What is your name?\"))\n", + "\n", + "mo.md(f\"๐Ÿ‘‹ Hello {username.value}, nice to meet you!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "mo.ui.text_area(\n", + " label=\"A space for your thoughts\", full_width=True, max_length=1000\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "mo.ui.number(label=\"What is your favorite number?\", start=0, stop=10)" + ] + }, + { + "cell_type": "markdown", + "id": "Xref", + "metadata": {}, + "source": [ + "## Sliders" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "slider = mo.ui.slider(0, 100, value=50, label=\"Basic slider\", show_value=True)\n", + "range_slider = mo.ui.range_slider(\n", + " 0, 100, value=(30, 70), label=\"Range slider\", show_value=True\n", + ")\n", + "custom_steps = mo.ui.slider(\n", + " steps=[1, 10, 100, 1000], value=10, label=\"Custom steps\", show_value=True\n", + ")\n", + "vertical = mo.ui.slider(\n", + " 0, 100, value=50, label=\"Vertical slider\", orientation=\"vertical\"\n", + ")\n", + "mo.vstack([slider, range_slider, custom_steps, vertical]).center()" + ] + }, + { + "cell_type": "markdown", + "id": "BYtC", + "metadata": {}, + "source": [ + "## Checkboxes and Radios" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "RGSE", + "metadata": {}, + "outputs": [], + "source": [ + "COLORS = [\"red\", \"green\", \"blue\"]\n", + "colors = mo.ui.array(\n", + " [mo.ui.checkbox(label=color) for color in COLORS],\n", + ")\n", + "\n", + "shape = mo.ui.radio(\n", + " [\"circle\", \"square\", \"triangle\"], inline=True, value=\"square\"\n", + ")\n", + "mo.md(f\"\"\"\n", + "Let's build something:\n", + "\n", + "**Pick a shape:**\n", + "\n", + "{shape}\n", + "\n", + "**Pick a color:**\n", + "\n", + "{colors.hstack().left()}\n", + "\"\"\").center()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Kclp", + "metadata": {}, + "outputs": [], + "source": [ + "selected_colors = [color for i, color in enumerate(COLORS) if colors.value[i]]\n", + "\n", + "\n", + "def draw_shape(shape, colors):\n", + " if not colors:\n", + " return \"\"\n", + "\n", + " gradient = \"\"\n", + " if isinstance(colors, list) and len(colors) > 1:\n", + " gradient_id = f\"grad{hash(tuple(colors)) % 1000}\"\n", + " stops = \"\".join(\n", + " [\n", + " f''\n", + " for i, color in enumerate(colors)\n", + " ]\n", + " )\n", + " gradient = f'{stops}'\n", + " fill_color = f\"url(#{gradient_id})\"\n", + " else:\n", + " fill_color = colors if isinstance(colors, str) else colors[0]\n", + "\n", + " if shape == \"circle\":\n", + " html = f'{gradient}'\n", + " elif shape == \"square\":\n", + " html = f'{gradient}'\n", + " elif shape == \"triangle\":\n", + " html = f'{gradient}'\n", + " else:\n", + " html = \"Shape not recognized\"\n", + " return mo.Html(html)\n", + "\n", + "\n", + "mo.md(f\"\"\"\n", + "A {\"/\".join(selected_colors)} {shape.value}:\n", + "{draw_shape(shape.value, selected_colors)}\n", + "\"\"\").center()" + ] + }, + { + "cell_type": "markdown", + "id": "emfo", + "metadata": {}, + "source": [ + "## Dates" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Hstk", + "metadata": {}, + "outputs": [], + "source": [ + "import datetime\n", + "\n", + "start_date = mo.ui.date(\n", + " label=\"Start date\",\n", + " start=datetime.date(2020, 1, 1),\n", + " stop=datetime.date(2020, 12, 31),\n", + ")\n", + "end_date = mo.ui.date(\n", + " label=\"End date\",\n", + " start=datetime.date(2020, 1, 1),\n", + " stop=datetime.date(2020, 12, 31),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "nWHF", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack(\n", + " [\n", + " mo.hstack([start_date, \"โžก๏ธ\", end_date]).left(),\n", + " mo.md(f\"From {start_date.value} to {end_date.value}\"),\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "iLit", + "metadata": {}, + "source": [ + "## Dropdowns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ZHCJ", + "metadata": {}, + "outputs": [], + "source": [ + "single = mo.ui.dropdown(\n", + " [\"Option 1\", \"Option 2\", \"Option 3\", \"Option 4\", \"Option 5\"],\n", + " label=\"Single select\",\n", + ")\n", + "multi = mo.ui.multiselect(\n", + " [\"Option 1\", \"Option 2\", \"Option 3\", \"Option 4\", \"Option 5\"],\n", + " label=\"Multi select\",\n", + " value=[\"Option 1\", \"Option 2\"],\n", + ")\n", + "mo.hstack([single, multi])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ROlb", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/inputs.script.py b/generated/examples/ui/inputs.script.py new file mode 100644 index 0000000..6b33d7b --- /dev/null +++ b/generated/examples/ui/inputs.script.py @@ -0,0 +1,157 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +mo.md(r"""## Checkboxes and Radios""") + +# %% +mo.md("""## Dates""") + +# %% +mo.md( + r""" + # Inputs + + There are many way that a user can input with your notebook, such as text boxes, sliders, dates, and more. + """ +) + +# %% +mo.ui.number(label="What is your favorite number?", start=0, stop=10) + +# %% +slider = mo.ui.slider(0, 100, value=50, label="Basic slider", show_value=True) +range_slider = mo.ui.range_slider( + 0, 100, value=(30, 70), label="Range slider", show_value=True +) +custom_steps = mo.ui.slider( + steps=[1, 10, 100, 1000], value=10, label="Custom steps", show_value=True +) +vertical = mo.ui.slider( + 0, 100, value=50, label="Vertical slider", orientation="vertical" +) +mo.vstack([slider, range_slider, custom_steps, vertical]).center() + +# %% +mo.md(r"""## Sliders""") + +# %% +mo.ui.text_area( + label="A space for your thoughts", full_width=True, max_length=1000 +) + +# %% +single = mo.ui.dropdown( + ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"], + label="Single select", +) +multi = mo.ui.multiselect( + ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"], + label="Multi select", + value=["Option 1", "Option 2"], +) +mo.hstack([single, multi]) + +# %% +COLORS = ["red", "green", "blue"] +colors = mo.ui.array( + [mo.ui.checkbox(label=color) for color in COLORS], +) + +shape = mo.ui.radio( + ["circle", "square", "triangle"], inline=True, value="square" +) +mo.md(f""" +Let's build something: + +**Pick a shape:** + +{shape} + +**Pick a color:** + +{colors.hstack().left()} +""").center() + +# %% +import datetime + +start_date = mo.ui.date( + label="Start date", + start=datetime.date(2020, 1, 1), + stop=datetime.date(2020, 12, 31), +) +end_date = mo.ui.date( + label="End date", + start=datetime.date(2020, 1, 1), + stop=datetime.date(2020, 12, 31), +) + +# %% +mo.md(r"""## Text boxes""") + +# %% +mo.md("""## Dropdowns""") + +# %% +mo.hstack( + [ + username := mo.ui.text(label="Username"), + email := mo.ui.text(label="Email", kind="email"), + mo.ui.text(label="Password", kind="password"), + ] +) + +# %% +selected_colors = [color for i, color in enumerate(COLORS) if colors.value[i]] + + +def draw_shape(shape, colors): + if not colors: + return "" + + gradient = "" + if isinstance(colors, list) and len(colors) > 1: + gradient_id = f"grad{hash(tuple(colors)) % 1000}" + stops = "".join( + [ + f'' + for i, color in enumerate(colors) + ] + ) + gradient = f'{stops}' + fill_color = f"url(#{gradient_id})" + else: + fill_color = colors if isinstance(colors, str) else colors[0] + + if shape == "circle": + html = f'{gradient}' + elif shape == "square": + html = f'{gradient}' + elif shape == "triangle": + html = f'{gradient}' + else: + html = "Shape not recognized" + return mo.Html(html) + + +mo.md(f""" +A {"/".join(selected_colors)} {shape.value}: +{draw_shape(shape.value, selected_colors)} +""").center() + +# %% +mo.hstack( + [ + mo.hstack([start_date, "โžก๏ธ", end_date]).left(), + mo.md(f"From {start_date.value} to {end_date.value}"), + ] +) + +# %% +mo.stop(not username.value, mo.md("What is your name?")) + +mo.md(f"๐Ÿ‘‹ Hello {username.value}, nice to meet you!") \ No newline at end of file diff --git a/generated/examples/ui/layout.py.ipynb b/generated/examples/ui/layout.py.ipynb new file mode 100644 index 0000000..a89cbd3 --- /dev/null +++ b/generated/examples/ui/layout.py.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Stacks" + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "Use `mo.hstack` and `mo.vstack` to layout outputs in rows and columns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "align = mo.ui.dropdown(\n", + " label=\"Align\", options=[\"start\", \"end\", \"center\", \"stretch\"]\n", + ")\n", + "justify = mo.ui.dropdown(\n", + " label=\"Justify\",\n", + " options=[\"start\", \"center\", \"end\", \"space-between\", \"space-around\"],\n", + ")\n", + "gap = mo.ui.number(label=\"Gap\", start=0, stop=100, value=1)\n", + "size = mo.ui.slider(label=\"Size\", start=60, stop=500)\n", + "wrap = mo.ui.checkbox(label=\"Wrap\")\n", + "\n", + "mo.md(\n", + " f\"\"\"\n", + " **Stack parameters**\n", + "\n", + " {mo.hstack([align, justify, gap, wrap], gap=0.25)}\n", + "\n", + " **Boxes {size}**\n", + " \"\"\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bkHC", + "metadata": {}, + "source": [ + "## Horizontal Stack: `hstack`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack(\n", + " boxes,\n", + " align=align.value,\n", + " justify=justify.value,\n", + " gap=gap.value,\n", + " wrap=wrap.value,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "PKri", + "metadata": {}, + "source": [ + "## Vertical Stack: `vstack`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "mo.vstack(\n", + " boxes,\n", + " align=align.value,\n", + " gap=gap.value,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "def create_box(num):\n", + " box_size = size.value + num * 10\n", + " return mo.Html(\n", + " f\"
{str(num)}
\"\n", + " )\n", + "\n", + "\n", + "boxes = [create_box(i) for i in range(1, 5)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "BYtC", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/layout.script.py b/generated/examples/ui/layout.script.py new file mode 100644 index 0000000..4425cfe --- /dev/null +++ b/generated/examples/ui/layout.script.py @@ -0,0 +1,65 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +mo.md("""## Vertical Stack: `vstack`""") + +# %% +mo.md("""# Stacks""") + +# %% +mo.md("""## Horizontal Stack: `hstack`""") + +# %% +align = mo.ui.dropdown( + label="Align", options=["start", "end", "center", "stretch"] +) +justify = mo.ui.dropdown( + label="Justify", + options=["start", "center", "end", "space-between", "space-around"], +) +gap = mo.ui.number(label="Gap", start=0, stop=100, value=1) +size = mo.ui.slider(label="Size", start=60, stop=500) +wrap = mo.ui.checkbox(label="Wrap") + +mo.md( + f""" + **Stack parameters** + + {mo.hstack([align, justify, gap, wrap], gap=0.25)} + + **Boxes {size}** + """ +) + +# %% +mo.md("""Use `mo.hstack` and `mo.vstack` to layout outputs in rows and columns.""") + +# %% +def create_box(num): + box_size = size.value + num * 10 + return mo.Html( + f"
{str(num)}
" + ) + + +boxes = [create_box(i) for i in range(1, 5)] + +# %% +mo.hstack( + boxes, + align=align.value, + justify=justify.value, + gap=gap.value, + wrap=wrap.value, +) + +# %% +mo.vstack( + boxes, + align=align.value, + gap=gap.value, +) \ No newline at end of file diff --git a/generated/examples/ui/mermaid.py.ipynb b/generated/examples/ui/mermaid.py.ipynb new file mode 100644 index 0000000..227752e --- /dev/null +++ b/generated/examples/ui/mermaid.py.ipynb @@ -0,0 +1,74 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "Hbol", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "mo.mermaid(\n", + " \"\"\"\n", + "graph TD\n", + " A[Enter Chart Definition] --> B(Preview)\n", + " B --> C{decide}\n", + " C --> D[Keep]\n", + " C --> E[Edit Definition]\n", + " E --> B\n", + " D --> F[Save Image and Code]\n", + " F --> B\n", + "\"\"\"\n", + ").center()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "graph = mo.ui.code_editor(\n", + " value=\"\"\"sequenceDiagram\n", + " Alice->>John: Hello John, how are you?\n", + " John-->>Alice: Great!\n", + " Alice-)John: See you later!\"\"\",\n", + " language=\"mermaid\",\n", + " label=\"Mermaid editor\",\n", + ")\n", + "graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mo.md(\n", + " f\"\"\"\n", + " You can render mermaid directly inside `mo.md`. Using\n", + "\n", + " `mo.mermaid()`\n", + "\n", + " {mo.mermaid(graph.value)}\n", + " \"\"\"\n", + ")" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/mermaid.script.py b/generated/examples/ui/mermaid.script.py new file mode 100644 index 0000000..13af23e --- /dev/null +++ b/generated/examples/ui/mermaid.script.py @@ -0,0 +1,41 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +mo.mermaid( + """ +graph TD + A[Enter Chart Definition] --> B(Preview) + B --> C{decide} + C --> D[Keep] + C --> E[Edit Definition] + E --> B + D --> F[Save Image and Code] + F --> B +""" +).center() + +# %% +graph = mo.ui.code_editor( + value="""sequenceDiagram + Alice->>John: Hello John, how are you? + John-->>Alice: Great! + Alice-)John: See you later!""", + language="mermaid", + label="Mermaid editor", +) +graph + +# %% +mo.md( + f""" + You can render mermaid directly inside `mo.md`. Using + + `mo.mermaid()` + + {mo.mermaid(graph.value)} + """ +) \ No newline at end of file diff --git a/generated/examples/ui/reactive_plots.py.ipynb b/generated/examples/ui/reactive_plots.py.ipynb new file mode 100644 index 0000000..24b8ad0 --- /dev/null +++ b/generated/examples/ui/reactive_plots.py.ipynb @@ -0,0 +1,105 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Welcome to marimo!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "chart = mo.ui.altair_chart(scatter & bars)\n", + "chart" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "(filtered_data := mo.ui.table(chart.value))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mo.stop(not len(filtered_data.value))\n", + "mpg_hist = mo.ui.altair_chart(\n", + " alt.Chart(filtered_data.value)\n", + " .mark_bar()\n", + " .encode(alt.X(\"Miles_per_Gallon:Q\", bin=True), y=\"count()\")\n", + ")\n", + "horsepower_hist = mo.ui.altair_chart(\n", + " alt.Chart(filtered_data.value)\n", + " .mark_bar()\n", + " .encode(alt.X(\"Horsepower:Q\", bin=True), y=\"count()\")\n", + ")\n", + "mo.hstack([mpg_hist, horsepower_hist], justify=\"space-around\", widths=\"equal\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "cars = data.cars()\n", + "brush = alt.selection_interval()\n", + "scatter = (\n", + " alt.Chart(cars)\n", + " .mark_point()\n", + " .encode(\n", + " x=\"Horsepower\",\n", + " y=\"Miles_per_Gallon\",\n", + " color=\"Origin\",\n", + " )\n", + " .add_params(brush)\n", + ")\n", + "bars = (\n", + " alt.Chart(cars)\n", + " .mark_bar()\n", + " .encode(y=\"Origin:N\", color=\"Origin:N\", x=\"count(Origin):Q\")\n", + " .transform_filter(brush)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "import altair as alt\n", + "from vega_datasets import data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/reactive_plots.script.py b/generated/examples/ui/reactive_plots.script.py new file mode 100644 index 0000000..3a2e73e --- /dev/null +++ b/generated/examples/ui/reactive_plots.script.py @@ -0,0 +1,53 @@ + +__generated_with = "0.9.30" + +# %% +import altair as alt +from vega_datasets import data + +# %% +import marimo as mo + +# %% +cars = data.cars() +brush = alt.selection_interval() +scatter = ( + alt.Chart(cars) + .mark_point() + .encode( + x="Horsepower", + y="Miles_per_Gallon", + color="Origin", + ) + .add_params(brush) +) +bars = ( + alt.Chart(cars) + .mark_bar() + .encode(y="Origin:N", color="Origin:N", x="count(Origin):Q") + .transform_filter(brush) +) + +# %% +mo.md("""# Welcome to marimo!""") + +# %% +chart = mo.ui.altair_chart(scatter & bars) +chart + +# %% +(filtered_data := mo.ui.table(chart.value)) + +# %% +mo.stop(not len(filtered_data.value)) +mpg_hist = mo.ui.altair_chart( + alt.Chart(filtered_data.value) + .mark_bar() + .encode(alt.X("Miles_per_Gallon:Q", bin=True), y="count()") +) +horsepower_hist = mo.ui.altair_chart( + alt.Chart(filtered_data.value) + .mark_bar() + .encode(alt.X("Horsepower:Q", bin=True), y="count()") +) +mo.hstack([mpg_hist, horsepower_hist], justify="space-around", widths="equal") \ No newline at end of file diff --git a/generated/examples/ui/refresh.py.ipynb b/generated/examples/ui/refresh.py.ipynb new file mode 100644 index 0000000..ac45951 --- /dev/null +++ b/generated/examples/ui/refresh.py.ipynb @@ -0,0 +1,139 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "Hbol", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack([\n", + " mo.vstack([\n", + " mo.md(\"## Settings | [`marimo.ui.slider`](https://docs.marimo.io/api/inputs/slider.html), [`marimo.ui.refresh`](https://docs.marimo.io/recipes.html#run-a-cell-on-a-timer)\\n---\"),\n", + " refresh_interval_slider,\n", + " n_points_slider,\n", + " refresher,\n", + " mo.md(\"## ISS Positions | [`marimo.ui.altair_chart`](https://docs.marimo.io/api/plotting.html#marimo.ui.altair_chart)\\n---\"),\n", + " mo.as_html(chart).style({\"width\": \"700px\"})\n", + " ], align=\"center\"),\n", + " mo.vstack([\n", + " mo.md(\"## Data | [`marimo.as_html`](https://docs.marimo.io/api/html.html)`(pd.DataFrame)`\\n---\"),\n", + " mo.as_html(iss_df)\n", + " ])\n", + "], justify=\"center\", wrap=True, gap=3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "hover=alt.selection_point(on=\"mouseover\", clear=\"mouseout\")\n", + "\n", + "# iss positions\n", + "iss_df = get_iss_positions()\n", + "iss = alt.Chart(iss_df[['longitude','latitude','timestamp']]).mark_circle(\n", + " stroke='black', size=100,\n", + ").encode(\n", + " longitude=alt.Longitude('longitude:Q'),\n", + " latitude='latitude:Q',\n", + " fill=alt.Fill('timestamp:Q', scale=alt.Scale(scheme='purples'), legend=None),\n", + " strokeWidth=alt.condition(hover, alt.value(3, empty=False), alt.value(0)),\n", + " tooltip=[\n", + " alt.Tooltip('longitude:Q', title='Longitude', format='.4f'),\n", + " alt.Tooltip('latitude:Q', title='Latitude', format='.4f'),\n", + " alt.Tooltip('timestamp:T', title='Timestamp', format='%Y-%m-%d %H:%M:%S')\n", + " ]\n", + ").add_params(hover)\n", + "\n", + "chart = alt.layer(sphere, world, iss).project(type=\"naturalEarth1\").properties(width=640, title=\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "# load geo data from Vega Datasets\n", + "countries = alt.topo_feature(data.world_110m.url, 'countries')\n", + "\n", + "# world base\n", + "sphere = alt.Chart(alt.sphere()).mark_geoshape(\n", + " fill=\"aliceblue\", stroke=\"black\", strokeWidth=1.5\n", + ")\n", + "\n", + "# world map\n", + "world = alt.Chart(countries).mark_geoshape(\n", + " fill=\"mintcream\", stroke=\"black\", strokeWidth=0.35\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "def get_iss_positions(refresher=refresher):\n", + " refresher\n", + " timepoints = [int(time())]\n", + " while len(timepoints) <= n_points_slider.value:\n", + " timepoints.append(timepoints[-1] - refresh_interval_slider.value)\n", + " else:\n", + " timepoints.pop(0)\n", + " timepoints_str = str(timepoints)[1:-1].replace(\" \", \"\")\n", + " iss_url = f\"https://api.wheretheiss.at/v1/satellites/25544/positions?timestamps={timepoints_str}\"\n", + " response = requests.get(iss_url)\n", + " df = pd.DataFrame(response.json())\n", + " df['timestamp'] = pd.to_datetime(df.timestamp, unit='s')\n", + " return df[['timestamp','latitude','longitude','altitude','velocity','visibility']]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "refresher = mo.ui.refresh(default_interval=f\"{refresh_interval_slider.value}s\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "refresh_interval_slider = mo.ui.slider(start=5, stop=60, step=1, value=10, label=\"refresh interval (default = 10 sec)\")\n", + "n_points_slider = mo.ui.slider(start=5, stop=30, step=1, value=15, label=\"number of points (default = 15)\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "import altair as alt\n", + "import marimo as mo\n", + "import pandas as pd\n", + "import requests\n", + "from time import time\n", + "from vega_datasets import data\n", + "\n", + "pd.options.display.max_rows = 30" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/refresh.script.py b/generated/examples/ui/refresh.script.py new file mode 100644 index 0000000..55e3444 --- /dev/null +++ b/generated/examples/ui/refresh.script.py @@ -0,0 +1,85 @@ + +__generated_with = "0.9.30" + +# %% +import altair as alt +import marimo as mo +import pandas as pd +import requests +from time import time +from vega_datasets import data + +pd.options.display.max_rows = 30 + +# %% +# load geo data from Vega Datasets +countries = alt.topo_feature(data.world_110m.url, 'countries') + +# world base +sphere = alt.Chart(alt.sphere()).mark_geoshape( + fill="aliceblue", stroke="black", strokeWidth=1.5 +) + +# world map +world = alt.Chart(countries).mark_geoshape( + fill="mintcream", stroke="black", strokeWidth=0.35 +) + +# %% +refresh_interval_slider = mo.ui.slider(start=5, stop=60, step=1, value=10, label="refresh interval (default = 10 sec)") +n_points_slider = mo.ui.slider(start=5, stop=30, step=1, value=15, label="number of points (default = 15)") + +# %% +refresher = mo.ui.refresh(default_interval=f"{refresh_interval_slider.value}s") + +# %% +def get_iss_positions(refresher=refresher): + refresher + timepoints = [int(time())] + while len(timepoints) <= n_points_slider.value: + timepoints.append(timepoints[-1] - refresh_interval_slider.value) + else: + timepoints.pop(0) + timepoints_str = str(timepoints)[1:-1].replace(" ", "") + iss_url = f"https://api.wheretheiss.at/v1/satellites/25544/positions?timestamps={timepoints_str}" + response = requests.get(iss_url) + df = pd.DataFrame(response.json()) + df['timestamp'] = pd.to_datetime(df.timestamp, unit='s') + return df[['timestamp','latitude','longitude','altitude','velocity','visibility']] + +# %% +hover=alt.selection_point(on="mouseover", clear="mouseout") + +# iss positions +iss_df = get_iss_positions() +iss = alt.Chart(iss_df[['longitude','latitude','timestamp']]).mark_circle( + stroke='black', size=100, +).encode( + longitude=alt.Longitude('longitude:Q'), + latitude='latitude:Q', + fill=alt.Fill('timestamp:Q', scale=alt.Scale(scheme='purples'), legend=None), + strokeWidth=alt.condition(hover, alt.value(3, empty=False), alt.value(0)), + tooltip=[ + alt.Tooltip('longitude:Q', title='Longitude', format='.4f'), + alt.Tooltip('latitude:Q', title='Latitude', format='.4f'), + alt.Tooltip('timestamp:T', title='Timestamp', format='%Y-%m-%d %H:%M:%S') + ] +).add_params(hover) + +chart = alt.layer(sphere, world, iss).project(type="naturalEarth1").properties(width=640, title="") + +# %% +mo.hstack([ + mo.vstack([ + mo.md("## Settings | [`marimo.ui.slider`](https://docs.marimo.io/api/inputs/slider.html), [`marimo.ui.refresh`](https://docs.marimo.io/recipes.html#run-a-cell-on-a-timer)\n---"), + refresh_interval_slider, + n_points_slider, + refresher, + mo.md("## ISS Positions | [`marimo.ui.altair_chart`](https://docs.marimo.io/api/plotting.html#marimo.ui.altair_chart)\n---"), + mo.as_html(chart).style({"width": "700px"}) + ], align="center"), + mo.vstack([ + mo.md("## Data | [`marimo.as_html`](https://docs.marimo.io/api/html.html)`(pd.DataFrame)`\n---"), + mo.as_html(iss_df) + ]) +], justify="center", wrap=True, gap=3) \ No newline at end of file diff --git a/generated/examples/ui/table.py.ipynb b/generated/examples/ui/table.py.ipynb new file mode 100644 index 0000000..f013e18 --- /dev/null +++ b/generated/examples/ui/table.py.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Tables\n", + "\n", + "> โ€œSometimes Iโ€™ll start a sentence and I donโ€™t even know where itโ€™s going. I just hope I find it along the way.โ€\n", + "โ€” Michael Scott" + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "_Create rich tables with selectable rows using_ `mo.ui.table`." + ] + }, + { + "cell_type": "markdown", + "id": "vblA", + "metadata": {}, + "source": [ + "**Single selection.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "single_select_table = mo.ui.table(\n", + " office_characters,\n", + " selection=\"single\",\n", + " pagination=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "mo.ui.tabs({\"table\": single_select_table, \"selection\": single_select_table.value})" + ] + }, + { + "cell_type": "markdown", + "id": "PKri", + "metadata": {}, + "source": [ + "**Multi-selection.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "multi_select_table = mo.ui.table(\n", + " office_characters,\n", + " selection=\"multi\",\n", + " pagination=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "mo.ui.tabs({\"table\": multi_select_table, \"selection\": multi_select_table.value})" + ] + }, + { + "cell_type": "markdown", + "id": "BYtC", + "metadata": {}, + "source": [ + "**No selection.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "RGSE", + "metadata": {}, + "outputs": [], + "source": [ + "table = mo.ui.table(\n", + " office_characters,\n", + " label=\"Employees\",\n", + " selection=None,\n", + ")\n", + "\n", + "table" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Kclp", + "metadata": {}, + "outputs": [], + "source": [ + "office_characters = [\n", + " {\n", + " \"first_name\": \"Michael\",\n", + " \"last_name\": \"Scott\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\", rounded=True),\n", + " },\n", + " {\n", + " \"first_name\": \"Jim\",\n", + " \"last_name\": \"Halpert\",\n", + " \"skill\": mo.ui.slider(1, 10, value=7),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Pam\",\n", + " \"last_name\": \"Beesly\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Dwight\",\n", + " \"last_name\": \"Schrute\",\n", + " \"skill\": mo.ui.slider(1, 10, value=7),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Angela\",\n", + " \"last_name\": \"Martin\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Kevin\",\n", + " \"last_name\": \"Malone\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Oscar\",\n", + " \"last_name\": \"Martinez\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Stanley\",\n", + " \"last_name\": \"Hudson\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Phyllis\",\n", + " \"last_name\": \"Vance\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Meredith\",\n", + " \"last_name\": \"Palmer\",\n", + " \"skill\": mo.ui.slider(1, 10, value=7),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Creed\",\n", + " \"last_name\": \"Bratton\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Ryan\",\n", + " \"last_name\": \"Howard\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Kelly\",\n", + " \"last_name\": \"Kapoor\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Toby\",\n", + " \"last_name\": \"Flenderson\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Darryl\",\n", + " \"last_name\": \"Philbin\",\n", + " \"skill\": mo.ui.slider(1, 10, value=7),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Erin\",\n", + " \"last_name\": \"Hannon\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Andy\",\n", + " \"last_name\": \"Bernard\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Jan\",\n", + " \"last_name\": \"Levinson\",\n", + " \"skill\": mo.ui.slider(1, 10, value=5),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"David\",\n", + " \"last_name\": \"Wallace\",\n", + " \"skill\": mo.ui.slider(1, 10, value=3),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + " {\n", + " \"first_name\": \"Holly\",\n", + " \"last_name\": \"Flax\",\n", + " \"skill\": mo.ui.slider(1, 10, value=7),\n", + " \"favorite place\": mo.image(src=\"https://picsum.photos/100\"),\n", + " },\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "emfo", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/table.script.py b/generated/examples/ui/table.script.py new file mode 100644 index 0000000..0fc37d0 --- /dev/null +++ b/generated/examples/ui/table.script.py @@ -0,0 +1,180 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +office_characters = [ + { + "first_name": "Michael", + "last_name": "Scott", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100", rounded=True), + }, + { + "first_name": "Jim", + "last_name": "Halpert", + "skill": mo.ui.slider(1, 10, value=7), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Pam", + "last_name": "Beesly", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Dwight", + "last_name": "Schrute", + "skill": mo.ui.slider(1, 10, value=7), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Angela", + "last_name": "Martin", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Kevin", + "last_name": "Malone", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Oscar", + "last_name": "Martinez", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Stanley", + "last_name": "Hudson", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Phyllis", + "last_name": "Vance", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Meredith", + "last_name": "Palmer", + "skill": mo.ui.slider(1, 10, value=7), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Creed", + "last_name": "Bratton", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Ryan", + "last_name": "Howard", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Kelly", + "last_name": "Kapoor", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Toby", + "last_name": "Flenderson", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Darryl", + "last_name": "Philbin", + "skill": mo.ui.slider(1, 10, value=7), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Erin", + "last_name": "Hannon", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Andy", + "last_name": "Bernard", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Jan", + "last_name": "Levinson", + "skill": mo.ui.slider(1, 10, value=5), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "David", + "last_name": "Wallace", + "skill": mo.ui.slider(1, 10, value=3), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, + { + "first_name": "Holly", + "last_name": "Flax", + "skill": mo.ui.slider(1, 10, value=7), + "favorite place": mo.image(src="https://picsum.photos/100"), + }, +] + +# %% +mo.md("""**Multi-selection.**""") + +# %% +mo.md("""_Create rich tables with selectable rows using_ `mo.ui.table`.""") + +# %% +mo.md( + """ + # Tables + + > โ€œSometimes Iโ€™ll start a sentence and I donโ€™t even know where itโ€™s going. I just hope I find it along the way.โ€ + โ€” Michael Scott + """ +) + +# %% +mo.md("""**Single selection.**""") + +# %% +mo.md("""**No selection.**""") + +# %% +single_select_table = mo.ui.table( + office_characters, + selection="single", + pagination=True, +) + +# %% +table = mo.ui.table( + office_characters, + label="Employees", + selection=None, +) + +table + +# %% +multi_select_table = mo.ui.table( + office_characters, + selection="multi", + pagination=True, +) + +# %% +mo.ui.tabs({"table": single_select_table, "selection": single_select_table.value}) + +# %% +mo.ui.tabs({"table": multi_select_table, "selection": multi_select_table.value}) \ No newline at end of file diff --git a/generated/examples/ui/tabs.py.ipynb b/generated/examples/ui/tabs.py.ipynb new file mode 100644 index 0000000..7e1a4d7 --- /dev/null +++ b/generated/examples/ui/tabs.py.ipynb @@ -0,0 +1,83 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "Hbol", + "metadata": {}, + "source": [ + "# Tabs" + ] + }, + { + "cell_type": "markdown", + "id": "MJUe", + "metadata": {}, + "source": [ + "Use `mo.ui.tabs` to organize outputs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "settings = mo.vstack(\n", + " [\n", + " mo.md(\"Edit User\"),\n", + " first := mo.ui.text(label=\"First Name\"),\n", + " last := mo.ui.text(label=\"Last Name\"),\n", + " ]\n", + ")\n", + "\n", + "organization = mo.vstack(\n", + " [\n", + " mo.md(\"Edit Organization\"),\n", + " org := mo.ui.text(label=\"Organization Name\", value=\"...\"),\n", + " employees := mo.ui.number(\n", + " label=\"Number of Employees\", start=0, stop=1000\n", + " ),\n", + " ]\n", + ")\n", + "\n", + "mo.ui.tabs(\n", + " {\n", + " \"๐Ÿง™โ€โ™€ User\": settings,\n", + " \"๐Ÿข Organization\": organization,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mo.md(\n", + " f\"\"\"\n", + " Welcome **{first.value} {last.value}** to **{org.value}**! You are \n", + " employee no. **{employees.value + 1}**.\n", + "\n", + " #{\"๐ŸŽ‰\" * (min(employees.value + 1, 1000))} \n", + " \"\"\"\n", + ") if all([first.value, last.value, org.value]) else None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/tabs.script.py b/generated/examples/ui/tabs.script.py new file mode 100644 index 0000000..fc39698 --- /dev/null +++ b/generated/examples/ui/tabs.script.py @@ -0,0 +1,47 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +mo.md("""# Tabs""") + +# %% +mo.md("""Use `mo.ui.tabs` to organize outputs.""") + +# %% +settings = mo.vstack( + [ + mo.md("Edit User"), + first := mo.ui.text(label="First Name"), + last := mo.ui.text(label="Last Name"), + ] +) + +organization = mo.vstack( + [ + mo.md("Edit Organization"), + org := mo.ui.text(label="Organization Name", value="..."), + employees := mo.ui.number( + label="Number of Employees", start=0, stop=1000 + ), + ] +) + +mo.ui.tabs( + { + "๐Ÿง™โ€โ™€ User": settings, + "๐Ÿข Organization": organization, + } +) + +# %% +mo.md( + f""" + Welcome **{first.value} {last.value}** to **{org.value}**! You are + employee no. **{employees.value + 1}**. + + #{"๐ŸŽ‰" * (min(employees.value + 1, 1000))} + """ +) if all([first.value, last.value, org.value]) else None \ No newline at end of file diff --git a/generated/examples/ui/task_list.py.ipynb b/generated/examples/ui/task_list.py.ipynb new file mode 100644 index 0000000..81af93d --- /dev/null +++ b/generated/examples/ui/task_list.py.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "Hbol", + "metadata": {}, + "outputs": [], + "source": [ + "mo.md(\"# Task List\").left()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "MJUe", + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass\n", + "class Task:\n", + " name: str\n", + " done: bool = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "vblA", + "metadata": {}, + "outputs": [], + "source": [ + "get_tasks, set_tasks = mo.state([])\n", + "mutation_signal, set_mutation_signal = mo.state(False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bkHC", + "metadata": {}, + "outputs": [], + "source": [ + "mutation_signal\n", + "\n", + "task_entry_box = mo.ui.text(placeholder=\"a task ...\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "lEQa", + "metadata": {}, + "outputs": [], + "source": [ + "def add_task():\n", + " if task_entry_box.value:\n", + " set_tasks(lambda v: v + [Task(task_entry_box.value)])\n", + " set_mutation_signal(True)\n", + "\n", + "\n", + "add_task_button = mo.ui.button(\n", + " label=\"add task\",\n", + " on_change=lambda _: add_task(),\n", + ")\n", + "\n", + "clear_tasks_button = mo.ui.button(\n", + " label=\"clear completed tasks\",\n", + " on_change=lambda _: set_tasks(\n", + " lambda v: [task for task in v if not task.done]\n", + " ),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "PKri", + "metadata": {}, + "outputs": [], + "source": [ + "mo.hstack(\n", + " [task_entry_box, add_task_button, clear_tasks_button], justify=\"start\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "Xref", + "metadata": {}, + "outputs": [], + "source": [ + "task_list = mo.ui.array(\n", + " [mo.ui.checkbox(value=task.done, label=task.name) for task in get_tasks()],\n", + " label=\"tasks\",\n", + " on_change=lambda v: set_tasks(\n", + " [Task(task.name, done=v[i]) for i, task in enumerate(get_tasks())]\n", + " ),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "SFPL", + "metadata": {}, + "outputs": [], + "source": [ + "mo.as_html(task_list) if task_list.value else mo.md(\"No tasks! ๐ŸŽ‰\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "BYtC", + "metadata": {}, + "outputs": [], + "source": [ + "import marimo as mo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "RGSE", + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/generated/examples/ui/task_list.script.py b/generated/examples/ui/task_list.script.py new file mode 100644 index 0000000..36556dd --- /dev/null +++ b/generated/examples/ui/task_list.script.py @@ -0,0 +1,62 @@ + +__generated_with = "0.9.30" + +# %% +import marimo as mo + +# %% +from dataclasses import dataclass + +# %% +mo.md("# Task List").left() + +# %% +get_tasks, set_tasks = mo.state([]) +mutation_signal, set_mutation_signal = mo.state(False) + +# %% +@dataclass +class Task: + name: str + done: bool = False + +# %% +mutation_signal + +task_entry_box = mo.ui.text(placeholder="a task ...") + +# %% +task_list = mo.ui.array( + [mo.ui.checkbox(value=task.done, label=task.name) for task in get_tasks()], + label="tasks", + on_change=lambda v: set_tasks( + [Task(task.name, done=v[i]) for i, task in enumerate(get_tasks())] + ), +) + +# %% +def add_task(): + if task_entry_box.value: + set_tasks(lambda v: v + [Task(task_entry_box.value)]) + set_mutation_signal(True) + + +add_task_button = mo.ui.button( + label="add task", + on_change=lambda _: add_task(), +) + +clear_tasks_button = mo.ui.button( + label="clear completed tasks", + on_change=lambda _: set_tasks( + lambda v: [task for task in v if not task.done] + ), +) + +# %% +mo.as_html(task_list) if task_list.value else mo.md("No tasks! ๐ŸŽ‰") + +# %% +mo.hstack( + [task_entry_box, add_task_button, clear_tasks_button], justify="start" +) \ No newline at end of file diff --git a/public/examples/ui/arrays_and_dicts.py.html b/public/examples/ui/arrays_and_dicts.py.html new file mode 100644 index 0000000..2b8da34 --- /dev/null +++ b/public/examples/ui/arrays_and_dicts.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + arrays and dicts + + + + + + +
+ + + + + + diff --git a/public/examples/ui/batch_and_form.py.html b/public/examples/ui/batch_and_form.py.html new file mode 100644 index 0000000..0fd2705 --- /dev/null +++ b/public/examples/ui/batch_and_form.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + batch and form + + + + + + +
+ + + + + + diff --git a/public/examples/ui/data_explorer.py.html b/public/examples/ui/data_explorer.py.html new file mode 100644 index 0000000..3174b46 --- /dev/null +++ b/public/examples/ui/data_explorer.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + data explorer + + + + + + +
+ + + + + + diff --git a/public/examples/ui/filterable_table.py.html b/public/examples/ui/filterable_table.py.html new file mode 100644 index 0000000..5d254fc --- /dev/null +++ b/public/examples/ui/filterable_table.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + filterable table + + + + + + +
+ + + + + + diff --git a/public/examples/ui/inputs.py.html b/public/examples/ui/inputs.py.html new file mode 100644 index 0000000..7494620 --- /dev/null +++ b/public/examples/ui/inputs.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inputs + + + + + + +
+ + + + + + diff --git a/public/examples/ui/layout.py.html b/public/examples/ui/layout.py.html new file mode 100644 index 0000000..e5bb9dc --- /dev/null +++ b/public/examples/ui/layout.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + layout + + + + + + +
+ + + + + + diff --git a/public/examples/ui/mermaid.py.html b/public/examples/ui/mermaid.py.html new file mode 100644 index 0000000..55f8b49 --- /dev/null +++ b/public/examples/ui/mermaid.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mermaid + + + + + + +
+ + + + + + diff --git a/public/examples/ui/reactive_plots.py.html b/public/examples/ui/reactive_plots.py.html new file mode 100644 index 0000000..03b32a7 --- /dev/null +++ b/public/examples/ui/reactive_plots.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + reactive plots + + + + + + +
+ + + + + + diff --git a/public/examples/ui/refresh.py.html b/public/examples/ui/refresh.py.html new file mode 100644 index 0000000..3d4e182 --- /dev/null +++ b/public/examples/ui/refresh.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + refresh + + + + + + +
+ + + + + + diff --git a/public/examples/ui/table.py.html b/public/examples/ui/table.py.html new file mode 100644 index 0000000..17a71f8 --- /dev/null +++ b/public/examples/ui/table.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + + + + + + +
+ + + + + + diff --git a/public/examples/ui/tabs.py.html b/public/examples/ui/tabs.py.html new file mode 100644 index 0000000..66ff00e --- /dev/null +++ b/public/examples/ui/tabs.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tabs + + + + + + +
+ + + + + + diff --git a/public/examples/ui/task_list.py.html b/public/examples/ui/task_list.py.html new file mode 100644 index 0000000..2ce7bbf --- /dev/null +++ b/public/examples/ui/task_list.py.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + task list + + + + + + +
+ + + + + + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..5f7aa1e --- /dev/null +++ b/public/index.html @@ -0,0 +1,50 @@ + + + + + + Marimo Examples + + + +

Marimo Examples

+ + + \ No newline at end of file diff --git a/scripts/export_notebooks.py b/scripts/export_notebooks.py index c2a9a2c..75650f4 100755 --- a/scripts/export_notebooks.py +++ b/scripts/export_notebooks.py @@ -21,12 +21,12 @@ ] def export_markdown(notebook_path: str) -> None: - """Export a single marimo notebook to markdown.""" + """Export a single marimo notebook to markdown format.""" output_path = f"{notebook_path}.md" print(f"Exporting {notebook_path} to {output_path}") result = subprocess.run( - ["marimo", "export", "md", notebook_path, "-o", "generated/" + output_path], + ["marimo", "export", "md", notebook_path, "-o", f"generated/{output_path}"], capture_output=True, text=True, ) @@ -36,8 +36,82 @@ def export_markdown(notebook_path: str) -> None: print(result.stderr) raise RuntimeError(f"Failed to export {notebook_path}") +def export_html(notebook_path: str) -> None: + """Export a single marimo notebook to HTML format.""" + ext = "html" + output_path = f"{notebook_path}.{ext}" + print(f"Exporting {notebook_path} to {output_path}") + result = subprocess.run( + ["marimo", "export", "html", notebook_path, "-o", f"public/{output_path}"], + capture_output=True, + text=True, + ) + + if result.returncode != 0: + print(f"Error exporting {notebook_path}:") + print(result.stderr) + raise RuntimeError(f"Failed to export {notebook_path}") + +def export_ipynb(notebook_path: str) -> None: + """Export a single marimo notebook to ipynb format.""" + output_path = f"{notebook_path}.ipynb" + print(f"Exporting {notebook_path} to {output_path}") + + result = subprocess.run( + ["marimo", "export", "ipynb", notebook_path, "-o", f"generated/{output_path}", "--sort", "top-down"], + capture_output=True, + text=True, + ) + + if result.returncode != 0: + print(f"Error exporting {notebook_path}:") + print(result.stderr) + raise RuntimeError(f"Failed to export {notebook_path}") + +def export_script(notebook_path: str) -> None: + """Export a single marimo notebook to a python script.""" + output_path = f"{notebook_path.replace('.py', '.script.py')}" + print(f"Exporting {notebook_path} to {output_path}") + + result = subprocess.run( + ["marimo", "export", "script", notebook_path, "-o", f"generated/{output_path}"], + capture_output=True, + text=True, + ) + + if result.returncode != 0: + print(f"Error exporting {notebook_path}:") + print(result.stderr) + raise RuntimeError(f"Failed to export {notebook_path}") + +def generate_index(dir: str) -> None: + """Generate the index.html file.""" + print("Generating index.html") + + with open("public/index.html", "w") as f: + f.write(""" + + + + + Marimo Examples + + + +

Marimo Examples

+
+""") + for notebook in WHITELISTED_NOTEBOOKS: + notebook_name = notebook.split('/')[-1].replace('.py', '') + f.write(f' \n') + f.write(f'

{notebook_name.replace("_", " ").title()}

\n') + f.write('
\n') + f.write("""
+ +""") + def main(): - parser = argparse.ArgumentParser(description="Export marimo notebooks to markdown") + parser = argparse.ArgumentParser(description="Export marimo notebooks") parser.add_argument( "--examples-dir", type=str, @@ -50,11 +124,16 @@ def main(): if not os.path.exists(args.examples_dir): raise FileNotFoundError(f"Examples directory not found: {args.examples_dir}") + generate_index(args.examples_dir) + # Process each whitelisted notebook for notebook in WHITELISTED_NOTEBOOKS: notebook_path = os.path.join(args.examples_dir, notebook) if os.path.exists(notebook_path): export_markdown(notebook_path) + # export_html(notebook_path) + export_ipynb(notebook_path) + export_script(notebook_path) else: print(f"Warning: Notebook not found: {notebook_path}")