From 100ee613be35dbb38a366021bab23e2c36f4f0cd Mon Sep 17 00:00:00 2001 From: Nuno Bispo Date: Tue, 29 Sep 2026 09:45:05 +0200 Subject: [PATCH 1/4] Materials for NiceGUI article --- .../README.md | 40 +++++++++++++++++++ .../elements_and_actions.py | 11 +++++ .../hello_nicegui_browser.py | 5 +++ .../hello_nicegui_native.py | 5 +++ .../layout_and_styling.py | 12 ++++++ .../requirements.txt | 4 ++ 6 files changed, 77 insertions(+) create mode 100644 nicegui-a-browser-frontend-for-your-python-code/README.md create mode 100644 nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/requirements.txt diff --git a/nicegui-a-browser-frontend-for-your-python-code/README.md b/nicegui-a-browser-frontend-for-your-python-code/README.md new file mode 100644 index 0000000000..690edf83f8 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/README.md @@ -0,0 +1,40 @@ +# NiceGUI: A Browser Frontend for Your Python Code + +Sample scripts that build small user interfaces with [NiceGUI](https://nicegui.io/). Each file is a complete app. + +## Setup + +These examples need Python 3.10 or newer. Create a virtual environment and install the dependencies: + +```console +$ python -m venv venv +$ source venv/bin/activate +$ python -m pip install -r requirements.txt +``` + +On Windows, activate the environment with `venv\Scripts\activate`. + +`requirements.txt` installs NiceGUI 3.17.0 with the Plotly extra, along with pinned versions of Plotly, pandas, and [pywebview](https://pywebview.flowrl.com/). `hello_nicegui_native.py` uses pywebview to open a desktop window. On Linux, pywebview also needs a system WebKit or Qt backend. The [pywebview installation guide](https://pywebview.flowrl.com/guide/installation.html) lists the packages for each platform. + +## Examples + +| Script | What it shows | +| --- | --- | +| `hello_nicegui_browser.py` | A label and a button that shows a notification in the browser | +| `hello_nicegui_native.py` | The same interface in a native desktop window | +| `elements_and_actions.py` | Text and number inputs that update a label when you click Run | +| `layout_and_styling.py` | A row, a card, an icon, a badge, and Quasar utility classes | + +Run an example from this folder: + +```console +$ python hello_nicegui_browser.py +``` + +NiceGUI prints a local URL, usually `http://127.0.0.1:8080`. Open that address in a browser. Stop the app with Ctrl+C. + +The native example opens its own window: + +```console +$ python hello_nicegui_native.py +``` diff --git a/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py b/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py new file mode 100644 index 0000000000..9906ed7e0f --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py @@ -0,0 +1,11 @@ +from nicegui import ui + +name = ui.input("Name", value="Ada") +count = ui.number("Copies", value=2, min=1, max=10) +out = ui.label() + +def run() -> None: + out.set_text(f"Hello, {name.value}! ({int(count.value)} copies)") + +ui.button("Run", on_click=run) +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py new file mode 100644 index 0000000000..dd28c6dd10 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py @@ -0,0 +1,5 @@ +from nicegui import ui + +ui.label("Hello, NiceGUI!") +ui.button("Click me", on_click=lambda: ui.notify("It works!")) +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py new file mode 100644 index 0000000000..daa2c56fc8 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py @@ -0,0 +1,5 @@ +from nicegui import ui + +ui.label("Hello, NiceGUI!") +ui.button("Click me", on_click=lambda: ui.notify("It works!")) +ui.run(native=True) diff --git a/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py b/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py new file mode 100644 index 0000000000..85c181d357 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py @@ -0,0 +1,12 @@ +from nicegui import ui + +with ui.row().classes("w-full items-center gap-4 p-4"): + ui.icon("dashboard", size="md").props("color=primary") + ui.label("Ops Panel").classes("text-h6 text-weight-bold") + +with ui.card().classes("w-80"): + ui.label("Status").classes("text-subtitle2") + ui.badge("Ready").props("color=positive") + ui.button("Ping", on_click=lambda: ui.notify("Ready")) + +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/requirements.txt b/nicegui-a-browser-frontend-for-your-python-code/requirements.txt new file mode 100644 index 0000000000..3fc4963672 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/requirements.txt @@ -0,0 +1,4 @@ +nicegui[plotly]==3.17.0 +plotly==6.9.0 +pandas==3.0.5 +pywebview==6.2.1 From c4abef7ef8ee7bdd92627a40a1fc1543df557e40 Mon Sep 17 00:00:00 2001 From: Nuno Bispo Date: Tue, 29 Sep 2026 09:49:14 +0200 Subject: [PATCH 2/4] Add spacing for improved readability in elements_and_actions.py --- .../elements_and_actions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py b/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py index 9906ed7e0f..f6e5fdac38 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py +++ b/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py @@ -4,8 +4,10 @@ count = ui.number("Copies", value=2, min=1, max=10) out = ui.label() + def run() -> None: out.set_text(f"Hello, {name.value}! ({int(count.value)} copies)") + ui.button("Run", on_click=run) ui.run() From 577955e2aa8e6577ce9612455f36a3c2a5e71691 Mon Sep 17 00:00:00 2001 From: Nuno Bispo Date: Thu, 1 Oct 2026 12:41:51 +0200 Subject: [PATCH 3/4] Updates from TR#1 --- .../README.md | 28 +++++--- .../csv_to_markdown.py | 68 +++++++++++++++++++ .../csv_to_markdown_ui.py | 50 ++++++++++++++ .../element_catalog.py | 28 ++++++++ .../elements_and_actions.py | 13 ---- .../estimate_card.py | 28 ++++++++ .../hello_nicegui_browser.py | 5 -- .../hello_nicegui_native.py | 5 -- .../layout_and_styling.py | 12 ---- .../password_generator.py | 40 +++++++++++ .../password_generator_native.py | 40 +++++++++++ .../people.csv | 3 + .../plotly_chart.py | 24 +++++++ .../request_chart.py | 28 ++++++++ 14 files changed, 328 insertions(+), 44 deletions(-) create mode 100644 nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/element_catalog.py delete mode 100644 nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/estimate_card.py delete mode 100644 nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py delete mode 100644 nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py delete mode 100644 nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/password_generator.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/people.csv create mode 100644 nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py create mode 100644 nicegui-a-browser-frontend-for-your-python-code/request_chart.py diff --git a/nicegui-a-browser-frontend-for-your-python-code/README.md b/nicegui-a-browser-frontend-for-your-python-code/README.md index 690edf83f8..fef53992d7 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/README.md +++ b/nicegui-a-browser-frontend-for-your-python-code/README.md @@ -1,6 +1,6 @@ # NiceGUI: A Browser Frontend for Your Python Code -Sample scripts that build small user interfaces with [NiceGUI](https://nicegui.io/). Each file is a complete app. +Sample scripts that build small user interfaces with [NiceGUI](https://nicegui.io/). Each NiceGUI file is a complete app. `csv_to_markdown.py` is a plain CLI helper used by the UI example. ## Setup @@ -14,21 +14,25 @@ $ python -m pip install -r requirements.txt On Windows, activate the environment with `venv\Scripts\activate`. -`requirements.txt` installs NiceGUI 3.17.0 with the Plotly extra, along with pinned versions of Plotly, pandas, and [pywebview](https://pywebview.flowrl.com/). `hello_nicegui_native.py` uses pywebview to open a desktop window. On Linux, pywebview also needs a system WebKit or Qt backend. The [pywebview installation guide](https://pywebview.flowrl.com/guide/installation.html) lists the packages for each platform. +`requirements.txt` installs NiceGUI 3.17.0 with the Plotly extra, along with pinned versions of Plotly, pandas, and [pywebview](https://pywebview.flowrl.com/). `password_generator_native.py` uses pywebview to open a desktop window. On Linux, pywebview also needs a system WebKit or Qt backend. The [pywebview installation guide](https://pywebview.flowrl.com/guide/installation.html) lists the packages for each platform. ## Examples | Script | What it shows | | --- | --- | -| `hello_nicegui_browser.py` | A label and a button that shows a notification in the browser | -| `hello_nicegui_native.py` | The same interface in a native desktop window | -| `elements_and_actions.py` | Text and number inputs that update a label when you click Run | -| `layout_and_styling.py` | A row, a card, an icon, a badge, and Quasar utility classes | +| `element_catalog.py` | Common inputs (text, number, select, checkbox, radio, slider, switch) and a summary label | +| `estimate_card.py` | A card with quantity, unit price, optional tax, and a calculated total | +| `password_generator.py` | A password generator in the browser | +| `password_generator_native.py` | The same password generator in a native desktop window | +| `csv_to_markdown.py` | CLI that converts a CSV file to a Markdown table | +| `csv_to_markdown_ui.py` | Browser UI for the converter, with progress and `run.io_bound` | +| `request_chart.py` | An ECharts bar chart and a table of request counts | +| `plotly_chart.py` | A Plotly bar chart from a pandas DataFrame | -Run an example from this folder: +Run a NiceGUI example from this folder: ```console -$ python hello_nicegui_browser.py +$ python password_generator.py ``` NiceGUI prints a local URL, usually `http://127.0.0.1:8080`. Open that address in a browser. Stop the app with Ctrl+C. @@ -36,5 +40,11 @@ NiceGUI prints a local URL, usually `http://127.0.0.1:8080`. Open that address i The native example opens its own window: ```console -$ python hello_nicegui_native.py +$ python password_generator_native.py +``` + +The CLI converter works without starting a server: + +```console +$ python csv_to_markdown.py people.csv ``` diff --git a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py new file mode 100644 index 0000000000..9ba02e6a1d --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py @@ -0,0 +1,68 @@ +import argparse +import csv +from io import StringIO +from pathlib import Path + + +def csv_to_markdown( + text: str, + *, + delimiter: str = ",", + header: bool = True, +) -> str: + raw = text.strip() + if not raw: + raise ValueError("CSV text is empty") + + rows = list(csv.reader(StringIO(raw), delimiter=delimiter)) + if not rows: + raise ValueError("CSV text has no rows") + if any(len(row) != len(rows[0]) for row in rows): + raise ValueError("CSV rows do not all have the same number of columns") + + if header: + headings = [cell.strip() or " " for cell in rows[0]] + body = rows[1:] + else: + headings = [f"Col {index}" for index in range(1, len(rows[0]) + 1)] + body = rows + + lines = [ + "| " + " | ".join(headings) + " |", + "| " + " | ".join("---" for _ in headings) + " |", + ] + for row in body: + lines.append("| " + " | ".join(cell.strip() for cell in row) + " |") + return "\n".join(lines) + "\n" + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Convert a CSV file to a Markdown table." + ) + parser.add_argument("csv_file", type=Path, help="path to a CSV file") + parser.add_argument( + "-d", + "--delimiter", + default=",", + help="field delimiter (default: comma)", + ) + parser.add_argument( + "--no-header", + action="store_true", + help="treat the first row as data", + ) + args = parser.parse_args() + text = args.csv_file.read_text(encoding="utf-8") + print( + csv_to_markdown( + text, + delimiter=args.delimiter, + header=not args.no_header, + ), + end="", + ) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py new file mode 100644 index 0000000000..d89dbd4db3 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py @@ -0,0 +1,50 @@ +from nicegui import run, ui + +from csv_to_markdown import csv_to_markdown + +SAMPLE = "name,role\nAda,Engineer\nGrace,Scientist\n" + +source = ui.textarea("CSV", value=SAMPLE).classes("w-full").props("rows=8") +delimiter = ui.select( + {",": "Comma", ";": "Semicolon", "\t": "Tab"}, + value=",", + label="Delimiter", +) +header = ui.checkbox("First row is the header", value=True) +status = ui.label("Paste CSV, then click Convert.") +progress = ui.linear_progress(show_value=False, size="8px").props( + "indeterminate" +) +progress.set_visibility(False) +markdown = ui.textarea("Markdown").classes("w-full").props("rows=8") + + +async def convert() -> None: + raw = source.value or "" + convert_button.disable() + progress.set_visibility(True) + status.set_text("Converting") + try: + result = await run.io_bound( + csv_to_markdown, + raw, + delimiter=delimiter.value, + header=header.value, + ) + except ValueError as exc: + markdown.set_value("") + status.set_text(str(exc)) + ui.notify(str(exc), type="negative") + return + finally: + progress.set_visibility(False) + convert_button.enable() + + markdown.set_value(result) + status.set_text("Conversion complete.") + ui.notify("Markdown table ready", type="positive") + + +convert_button = ui.button("Convert", on_click=convert) + +ui.run() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py b/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py new file mode 100644 index 0000000000..b2b8122777 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py @@ -0,0 +1,28 @@ +from nicegui import ui + +name = ui.input("Project", value="notes") +notes = ui.textarea("Notes", value="Ship the export") +copies = ui.number("Copies", value=2, min=1, max=10) +kind = ui.select(["Draft", "Final"], value="Draft", label="Kind") +urgent = ui.checkbox("Urgent") +ui.label("Extension") +extension = ui.radio(["txt", "csv"], value="txt") +ui.label("Priority") +priority = ui.slider(min=0, max=10, value=3) +archive = ui.switch("Archive after") +summary = ui.label("No choices yet") + + +def show() -> None: + summary.set_text( + f"{name.value}: {kind.value}.{extension.value}, " + f"copies={copies.value}, urgent={urgent.value}, " + f"priority={priority.value}, archive={archive.value}" + ) + if notes.value: + ui.notify(notes.value) + + +ui.button("Show choices", on_click=show) + +ui.run() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py b/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py deleted file mode 100644 index f6e5fdac38..0000000000 --- a/nicegui-a-browser-frontend-for-your-python-code/elements_and_actions.py +++ /dev/null @@ -1,13 +0,0 @@ -from nicegui import ui - -name = ui.input("Name", value="Ada") -count = ui.number("Copies", value=2, min=1, max=10) -out = ui.label() - - -def run() -> None: - out.set_text(f"Hello, {name.value}! ({int(count.value)} copies)") - - -ui.button("Run", on_click=run) -ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py b/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py new file mode 100644 index 0000000000..ff16f4c93e --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py @@ -0,0 +1,28 @@ +from nicegui import ui + +with ui.row().classes("w-full items-center gap-4 p-4"): + ui.icon("request_quote", size="md").props("color=primary") + ui.label("Estimate").classes("text-h6 text-weight-bold") + +with ui.card().classes("w-80"): + quantity = ui.number("Quantity", value=2, min=1) + unit_price = ui.number("Unit price", value=40.0, min=0, format="%.2f") + taxed = ui.checkbox("Add 20% tax") + total = ui.label("Total: —").classes("text-subtitle1") + + def calculate() -> None: + qty = quantity.value + price = unit_price.value + if qty is None or price is None or qty < 1 or price < 0: + total.set_text("Total: —") + ui.notify("Enter a quantity and a unit price", type="warning") + return + + amount = float(qty) * float(price) + if taxed.value: + amount *= 1.2 + total.set_text(f"Total: {amount:.2f}") + + ui.button("Calculate", on_click=calculate).props("color=primary") + +ui.run() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py deleted file mode 100644 index dd28c6dd10..0000000000 --- a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_browser.py +++ /dev/null @@ -1,5 +0,0 @@ -from nicegui import ui - -ui.label("Hello, NiceGUI!") -ui.button("Click me", on_click=lambda: ui.notify("It works!")) -ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py b/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py deleted file mode 100644 index daa2c56fc8..0000000000 --- a/nicegui-a-browser-frontend-for-your-python-code/hello_nicegui_native.py +++ /dev/null @@ -1,5 +0,0 @@ -from nicegui import ui - -ui.label("Hello, NiceGUI!") -ui.button("Click me", on_click=lambda: ui.notify("It works!")) -ui.run(native=True) diff --git a/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py b/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py deleted file mode 100644 index 85c181d357..0000000000 --- a/nicegui-a-browser-frontend-for-your-python-code/layout_and_styling.py +++ /dev/null @@ -1,12 +0,0 @@ -from nicegui import ui - -with ui.row().classes("w-full items-center gap-4 p-4"): - ui.icon("dashboard", size="md").props("color=primary") - ui.label("Ops Panel").classes("text-h6 text-weight-bold") - -with ui.card().classes("w-80"): - ui.label("Status").classes("text-subtitle2") - ui.badge("Ready").props("color=positive") - ui.button("Ping", on_click=lambda: ui.notify("Ready")) - -ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/password_generator.py b/nicegui-a-browser-frontend-for-your-python-code/password_generator.py new file mode 100644 index 0000000000..ddae5d30e4 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/password_generator.py @@ -0,0 +1,40 @@ +import secrets +import string + +from nicegui import ui + +length = ui.number("Length", value=16, min=8, max=64) +digits = ui.checkbox("Include digits", value=True) +symbols = ui.checkbox("Include symbols") +password = ui.input("Password").props("readonly") +status = ui.label("Click Generate for a new password.") + + +def generate() -> None: + size = length.value + if ( + size is None + or size != int(size) + or size < 8 + or size > 64 + ): + password.set_value("") + status.set_text("Choose a whole length from 8 to 64.") + ui.notify("Length must be a whole number from 8 to 64", type="warning") + return + + alphabet = string.ascii_letters + if digits.value: + alphabet += string.digits + if symbols.value: + alphabet += "!@#$%^&*()-_=+" + + size = int(size) + result = "".join(secrets.choice(alphabet) for _ in range(size)) + password.set_value(result) + status.set_text(f"Generated a {size}-character password.") + + +ui.button("Generate", on_click=generate) + +ui.run() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py b/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py new file mode 100644 index 0000000000..3c99474622 --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py @@ -0,0 +1,40 @@ +import secrets +import string + +from nicegui import ui + +length = ui.number("Length", value=16, min=8, max=64) +digits = ui.checkbox("Include digits", value=True) +symbols = ui.checkbox("Include symbols") +password = ui.input("Password").props("readonly") +status = ui.label("Click Generate for a new password.") + + +def generate() -> None: + size = length.value + if ( + size is None + or size != int(size) + or size < 8 + or size > 64 + ): + password.set_value("") + status.set_text("Choose a whole length from 8 to 64.") + ui.notify("Length must be a whole number from 8 to 64", type="warning") + return + + alphabet = string.ascii_letters + if digits.value: + alphabet += string.digits + if symbols.value: + alphabet += "!@#$%^&*()-_=+" + + size = int(size) + result = "".join(secrets.choice(alphabet) for _ in range(size)) + password.set_value(result) + status.set_text(f"Generated a {size}-character password.") + + +ui.button("Generate", on_click=generate) + +ui.run(native=True) \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/people.csv b/nicegui-a-browser-frontend-for-your-python-code/people.csv new file mode 100644 index 0000000000..78ed284e8a --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/people.csv @@ -0,0 +1,3 @@ +name,role +Ada,Engineer +Grace,Scientist diff --git a/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py b/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py new file mode 100644 index 0000000000..e11e9d196d --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py @@ -0,0 +1,24 @@ +import pandas as pd +import plotly.express as px +from nicegui import ui + +traffic = pd.DataFrame({ + "Endpoint": [ + "/login", + "/api/items", + "/api/search", + "/checkout", + "/health", + "/admin", + ], + "Requests": [1280, 2540, 1875, 940, 4120, 210], +}) +fig = px.bar( + traffic, + x="Endpoint", + y="Requests", + title="Requests by Endpoint", +) +ui.plotly(fig).classes("w-full") + +ui.run() \ No newline at end of file diff --git a/nicegui-a-browser-frontend-for-your-python-code/request_chart.py b/nicegui-a-browser-frontend-for-your-python-code/request_chart.py new file mode 100644 index 0000000000..723c5b7bbb --- /dev/null +++ b/nicegui-a-browser-frontend-for-your-python-code/request_chart.py @@ -0,0 +1,28 @@ +from nicegui import ui + +traffic = [ + {"endpoint": "/login", "requests": 1280}, + {"endpoint": "/api/items", "requests": 2540}, + {"endpoint": "/api/search", "requests": 1875}, + {"endpoint": "/checkout", "requests": 940}, + {"endpoint": "/health", "requests": 4120}, + {"endpoint": "/admin", "requests": 210}, +] + +ui.echart( + { + "title": {"text": "Requests by Endpoint"}, + "xAxis": { + "type": "category", + "data": [row["endpoint"] for row in traffic], + }, + "yAxis": {"type": "value"}, + "series": [ + {"type": "bar", "data": [row["requests"] for row in traffic]} + ], + } +).classes("w-full") + +ui.table(rows=traffic) + +ui.run() \ No newline at end of file From 0be83ec24c27ee5f83514b4adc9947535640efd6 Mon Sep 17 00:00:00 2001 From: Nuno Bispo Date: Thu, 1 Oct 2026 12:45:55 +0200 Subject: [PATCH 4/4] Formatting --- .../csv_to_markdown.py | 2 +- .../csv_to_markdown_ui.py | 2 +- .../element_catalog.py | 2 +- .../estimate_card.py | 2 +- .../password_generator.py | 9 ++----- .../password_generator_native.py | 9 ++----- .../plotly_chart.py | 26 ++++++++++--------- .../request_chart.py | 2 +- 8 files changed, 23 insertions(+), 31 deletions(-) diff --git a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py index 9ba02e6a1d..12c5edaf56 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py +++ b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown.py @@ -65,4 +65,4 @@ def main() -> None: if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py index d89dbd4db3..0faeef366c 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py +++ b/nicegui-a-browser-frontend-for-your-python-code/csv_to_markdown_ui.py @@ -47,4 +47,4 @@ async def convert() -> None: convert_button = ui.button("Convert", on_click=convert) -ui.run() \ No newline at end of file +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py b/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py index b2b8122777..e6d83709f1 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py +++ b/nicegui-a-browser-frontend-for-your-python-code/element_catalog.py @@ -25,4 +25,4 @@ def show() -> None: ui.button("Show choices", on_click=show) -ui.run() \ No newline at end of file +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py b/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py index ff16f4c93e..b2ea707e12 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py +++ b/nicegui-a-browser-frontend-for-your-python-code/estimate_card.py @@ -25,4 +25,4 @@ def calculate() -> None: ui.button("Calculate", on_click=calculate).props("color=primary") -ui.run() \ No newline at end of file +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/password_generator.py b/nicegui-a-browser-frontend-for-your-python-code/password_generator.py index ddae5d30e4..789a67d685 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/password_generator.py +++ b/nicegui-a-browser-frontend-for-your-python-code/password_generator.py @@ -12,12 +12,7 @@ def generate() -> None: size = length.value - if ( - size is None - or size != int(size) - or size < 8 - or size > 64 - ): + if size is None or size != int(size) or size < 8 or size > 64: password.set_value("") status.set_text("Choose a whole length from 8 to 64.") ui.notify("Length must be a whole number from 8 to 64", type="warning") @@ -37,4 +32,4 @@ def generate() -> None: ui.button("Generate", on_click=generate) -ui.run() \ No newline at end of file +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py b/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py index 3c99474622..bef186958f 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py +++ b/nicegui-a-browser-frontend-for-your-python-code/password_generator_native.py @@ -12,12 +12,7 @@ def generate() -> None: size = length.value - if ( - size is None - or size != int(size) - or size < 8 - or size > 64 - ): + if size is None or size != int(size) or size < 8 or size > 64: password.set_value("") status.set_text("Choose a whole length from 8 to 64.") ui.notify("Length must be a whole number from 8 to 64", type="warning") @@ -37,4 +32,4 @@ def generate() -> None: ui.button("Generate", on_click=generate) -ui.run(native=True) \ No newline at end of file +ui.run(native=True) diff --git a/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py b/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py index e11e9d196d..b904160b83 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py +++ b/nicegui-a-browser-frontend-for-your-python-code/plotly_chart.py @@ -2,17 +2,19 @@ import plotly.express as px from nicegui import ui -traffic = pd.DataFrame({ - "Endpoint": [ - "/login", - "/api/items", - "/api/search", - "/checkout", - "/health", - "/admin", - ], - "Requests": [1280, 2540, 1875, 940, 4120, 210], -}) +traffic = pd.DataFrame( + { + "Endpoint": [ + "/login", + "/api/items", + "/api/search", + "/checkout", + "/health", + "/admin", + ], + "Requests": [1280, 2540, 1875, 940, 4120, 210], + } +) fig = px.bar( traffic, x="Endpoint", @@ -21,4 +23,4 @@ ) ui.plotly(fig).classes("w-full") -ui.run() \ No newline at end of file +ui.run() diff --git a/nicegui-a-browser-frontend-for-your-python-code/request_chart.py b/nicegui-a-browser-frontend-for-your-python-code/request_chart.py index 723c5b7bbb..7f4327ebc4 100644 --- a/nicegui-a-browser-frontend-for-your-python-code/request_chart.py +++ b/nicegui-a-browser-frontend-for-your-python-code/request_chart.py @@ -25,4 +25,4 @@ ui.table(rows=traffic) -ui.run() \ No newline at end of file +ui.run()