Examples guide

The example apps in src/examples/ show ComposeUI’s features in complete apps. This guide says what each example shows, and how to run it. Each section has a screenshot of the example on each backend that shows it. The user guide explains each feature. The examples are not in the wheel: run them from a clone of the repository.

Contents

Run an example

Clone the repository, and install in it the extras of the backends that you want (see the README). Then run an example as a module:

uv run python -m examples.pipeform --backend qt

--backend takes qt, textual, or web. Without --backend, the COMPOSEUI_BACKEND environment variable picks the backend. Without both, each example starts its own default backend, which the overview gives. --help lists the other options, such as --language and -f FILE.

Overview

Example

Default backend

Shows

pipeform.py

web

Forms, validation, pages, a menu, a confirm dialog, Markdown help, a French translation

markdownviewer.py

web

A Markdown view, a file path input, an option of the app’s own, no File menu

studyinputs.py

web

A table of a study’s files: paths picked by each row’s kind, relative to the study’s folder; a summary saved after asking before replacing a file

taskview.py

web

Jobs in threads, metrics, a progress bar, a step chart, an expander, a button and a link in a table’s cells, a French translation

pipechart.py

qt

Line and scatter charts, a reference line, tabs, a table, check boxes and comboboxes in a table’s cells, colored, marked and disabled cells, cells spanning rows, a header group, row headers

pipecatalogue.py

web

A SQLite model, a sidebar, a list of views, a tree, resizable panes, a form dialog, a date input

pipesweep.py

web

A job writing to a SQLite model, a progress bar, a line chart and a table on tabs, a French translation

largetable.py

qt

A large table of a million rows in SQLite, read as they show, sorted by a click on a header, searched and filtered in its bar, exported as CSV

uberpickups.py

web

A CSV URL loaded into SQLite by a loading task, a bar chart, a street map filtered by a slider in a sidebar, a large table

uberpickupsframe.py

web

The Uber pickups app on a Polars frame instead of SQLite: a large table of a dataframe

batman.py

qt

Series colors, fills, and clicks on a chart

webhello.py

web only

A form on the web backend, built with WebApplication

textual_demo.py

textual

A small form in a terminal

The tests in tests/ also run these examples, as Testing your app shows. When you change an example, run its tests.

Where to start

Read the examples in this order. Each one adds a few features to the ones before it:

  1. Pipe form: forms and their checks, pages, menus, and a translation. It follows Building views of the user guide.

  2. Markdown viewer: a small app without studies, with a command-line option of its own.

  3. Task view: jobs in threads, with their progress.

  4. Pipe chart: charts, tabs, and the widgets in the cells of a table.

  5. Pipe catalogue: a SQLite model, with the views that follow it.

  6. Pipe sweep: a job that writes to a SQLite model.

The other examples each show one topic:

Pipe form

pipeform.py is a form that describes two pipes: a main pipe and an incident pipe.

uv run python -m examples.pipeform   # web; or --backend qt, or textual

On Qt:

The pipe form on Qt

On Textual:

The pipe form on Textual

On the web:

The pipe form on the web

It shows:

  • forms with labelled rows: text, float inputs, a checkbox, radio groups, a combobox, and a comment of several lines;

  • validation on a row, such as the name, and across rows, such as a main pipe that must fit the incident pipe;

  • three pages: Inputs, Results (a read-only table of the dimensions), and Help (a Markdown page);

  • a Pipe menu, whose Reset Dimensions asks for a confirmation first;

  • the File menu, which saves and loads the study as a .pipe file;

  • a French translation and a Language menu. To start in French, add --language fr.

Markdown viewer

markdownviewer.py shows a Markdown file.

uv run python -m examples.markdownviewer --markdown README.md --backend qt

On Qt:

The Markdown viewer on Qt

On Textual:

The Markdown viewer on Textual

On the web:

The Markdown viewer on the web

It shows:

  • a Markdown view;

  • an option of the app’s own: --markdown, beside the options of the backend;

  • a file path input at the top: the user types the path of a file, or picks the file with the “…” button. On the web, the browser uploads it. The reload button reads the file again, for example after the user edits it.

  • an app without studies: has_file_menu = False leaves out the File menu.

Study inputs

studyinputs.py lists the files and folders of a study, which the study reads or writes.

uv run python -m examples.studyinputs --study ~/studies/beam --backend qt

On Qt:

The study inputs on Qt

On Textual:

The study inputs on Textual

On the web:

The study inputs on the web

It shows:

  • a table with a combobox of each row’s kind: an input file, an input folder, an output file, or an output folder;

  • paths by the row’s kind: the “…” button of a row’s path picks a file, a folder, or a file to write, as its kind says. When the user changes the kind, the button follows. An output file may not exist yet, and picking one that exists asks first.

  • relative paths: the paths start from the study’s folder, --study, whatever folder the app started in. The line under the table shows where the selected row’s path leads (cell_widget(row, column).path(text)).

  • on the web, the “…” button lists the study’s folder: its server_roots.

  • “Save summary” writes the table’s rows to the text file of the save path input beside it. Over a file that exists, write_file asks first, unless the user already agreed in the field’s “…” picker.

Task view

taskview.py runs 25 tasks side by side in threads.

uv run python -m examples.taskview   # web; or --backend qt, or textual

On Qt:

The task view on Qt

On Textual:

The task view on Textual

On the web:

The task view on the web

It shows:

  • jobs: each task is a function that runs in a thread and never touches a view. Its job emits the status of the task on the main thread, where the views show it. A button cancels the jobs.

  • a configuration form with an integer input and a slider;

  • a progress bar of the tasks done;

  • metrics that count the tasks. Once a run is over, they show how each count changed since the last run.

  • a step chart of the tasks running over the time of the run;

  • an expander with the table of the tasks, which collapses to leave only the metrics and the chart;

  • widgets in cells: the Retry button of a task runs it again. The error of a failed task is a link that opens a dialog with its details.

  • a French translation and a Language menu.

Pipe chart

pipechart.py plots the pressure drop of a pipe against its flow rate.

uv run python -m examples.pipechart   # qt; or --backend textual, or web

On Qt:

The pipe chart on Qt

On Textual:

The pipe chart on Textual

On the web:

The pipe chart on the web

It shows:

  • a line chart: each click on Add Curve plots one curve for the diameter in the form, with its own flow rates;

  • a gap in a curve: between laminar and turbulent flow neither law holds, so the curve leaves a gap there (a NaN);

  • scatter series: Add Measurements plots, as dots over the curves, what a test rig measured on that pipe;

  • a reference line at the pressure of the pump;

  • tabs: the chart on one tab, and the measurements in a table of records on the Measurements tab, each against the computed drop;

  • how cells and headers look on the Measurements tab:

    • the pipe’s cell spans the rows of its measurements;

    • “Pressure Drop (kPa)” is a header over “Measured” and “Computed”;

    • a computed drop that the model can’t give (NaN, in transitional flow) is red;

    • a deviation over 10 % is orange, with a warning mark;

    • the Kept check box of a NaN row is disabled: that measurement can’t be compared with the model;

    • a summary under the table shows the measurements kept, with a header before each row;

  • widgets in cells: the Curves tab lists every curve. A check box shows or hides the curve, and the box in the header shows or hides them all. A combobox draws the curve as a line, in steps, or as dots.

Pipe catalogue

pipecatalogue.py is a catalogue of pipes, kept in a SQLite database.

uv run python -m examples.pipecatalogue   # web; or --backend qt, or textual

On Qt:

The pipe catalogue on Qt

On Textual:

The pipe catalogue on Textual

On the web:

The pipe catalogue on the web

It shows:

  • a SQLite model: the pipes are rows of the model’s database, not view state. The database checks every pipe added or changed: a name, positive dimensions, and a wall thinner than the radius. A SQL view computes the mass of each pipe from its material.

  • a sidebar with a form that adds a pipe;

  • a list of views: an expander per pipe, with its Edit and Delete buttons. A query filters the list by material, radius, and installation date.

  • a tree of the pipes by material, beside the list, in resizable panes. The materials are bold. A pipe has a done mark when its installation date is known, and a warning mark until then. When the user selects a pipe in the tree, its expander expands.

  • a form dialog that edits a pipe. Its Apply button saves the pipe, says so in the dialog, and leaves the dialog open. The dialog checks that no other pipe has the name, and shows why the database refuses a pipe;

  • a date input for the installation date of a pipe;

  • studies saved as a .pipes file with the views and the database. A study saved before pipes had an installation date gets the column, empty, when it opens, through a migration (PipeCatalogueModel.migrations).

Pipe sweep

pipesweep.py sweeps the outer radius of a pipe under pressure, and finds the hoop stress in its wall at each radius.

uv run python -m examples.pipesweep   # web; or --backend qt, or textual

On Qt:

The pipe sweep on Qt

On Textual:

The pipe sweep on Textual

On the web:

The pipe sweep on the web

It shows:

  • a job that works in a thread, one radius at a time, and writes each run to the model’s database when the run is done. The job never touches a view. The changed signal of each write is emitted on the main thread, where the views show the runs written so far. Cancel stops the sweep after the current run.

  • a form that checks the sweep before it starts, such as a wall thinner than the minimum radius;

  • a progress bar of the runs written, and two tabs: a line chart of the runs, and a table of them;

  • the File menu, which saves and opens the runs with the views as a .sweep file;

  • a French translation and a Language menu. To start in French, add --language fr.

Large table

largetable.py shows a million made-up sensor readings, kept in SQLite, in a large table.

uv run python -m examples.largetable   # qt; or --backend web, or textual
uv run python -m examples.largetable --rows 100000   # fewer readings, a faster start

On Qt:

A million readings on Qt

On Textual:

A million readings on Textual

On the web:

A million readings on the web

It shows:

  • a large table: a SourceTableView on a SqliteSource of the readings. SQLite sorts and filters them, indexed by the columns that sort; each backend draws the rows on screen alone, and reads them as the user scrolls. Python keeps the shown rows’ ids, never the readings.

  • a job writing the readings into the SQLite model, a batch at a time: the window shows at once, and the table fills once they are written.

  • a sort by a click on a header, and the table’s filter bar: a search in the text columns, and a filter on any column. On Qt and Textual, a job orders the rows, the window staying responsive. The label says how many rows pass and how long SQLite took to order them, once the table’s ordered emits.

  • a selection of several rows: the label under the table counts them, and shows the reading that a double click or Enter activates. Ctrl+C copies them, to paste in a spreadsheet.

  • an export of the rows shown to a CSV file: a job writes it on Qt and Textual, and the status bar says when it’s done; the web downloads it.

  • an option of the app’s own: --rows, the readings to make up (1,000,000 by default).

  • a study that saves the readings with the model, and the table’s settings with the views. Opened with -f, it shows its own readings: none are made up.

Uber pickups

uberpickups.py explores the Uber pickups of September 2014 in New York City, after Streamlit’s tutorial.

uv run python -m examples.uberpickups   # web; or --backend qt, or textual

These screenshots use made-up rows. The street map needs a network connection for its tiles. Textual shows no map.

On Qt:

Uber pickups on Qt

On Textual:

Uber pickups on Textual

On the web:

Uber pickups on the web

It shows:

  • a CSV URL imported into a typed SQLite table. The app downloads the CSV file when it first starts. A saved study keeps the rows, so the app does not download them again when the study opens.

  • a loading task that imports the rows in a job. Task.show_state shows its state in a status line: the count of rows read, or the error. It shows the chart and the map once the task has a result. The task’s finished callback gives them their data.

  • a bar chart of the pickups per hour, which counts all the rows. bar_chart, from composeui.core.dashboard, sets its kind and its hours.

  • a sidebar of filters: a check box, and a slider of the hour, 11 at the start. The slider is a form row with its label, straight in the sidebar, without a form around it.

  • a map of the pickups of the slider’s hour, on Qt and the web. The map shows at most 10,000 of them, sampled in the order of the rows. A move of the slider queries the saved rows again for the map only. The map fits the pickups, and keeps the viewport once the user pans or zooms.

  • a DashboardView: a wide main view without pages. This one keeps the File menu, so that a study saves the rows.

  • the raw data in a large table, with the rows of all the hours. CheckBoxMixin.shows shows it only while the sidebar’s check box is checked.

Uber pickups on a dataframe

uberpickupsframe.py is the Uber pickups app, with its rows in a Polars frame instead of SQLite.

uv run python -m examples.uberpickupsframe   # web; or --backend qt, or textual

It needs the dataframe extra and Polars. It reads the CSV file in a job each time that it starts. It has no File menu, because a study would keep no rows. The table shows the CSV’s own columns. Polars counts the pickups by hour, and samples the pickups of the slider’s hour for the map.

These screenshots use made-up rows. The street map needs a network connection for its tiles. Textual shows no map.

On Qt:

Uber pickups on a dataframe on Qt

On Textual:

Uber pickups on a dataframe on Textual

On the web:

Uber pickups on a dataframe on the web

It shows:

  • a large table on a DataFrameSource: Polars sorts, searches, and filters a million pickups;

  • a job that only reads the CSV file. Its result, a frame, becomes the table’s source on the main thread.

  • the status line, the chart, the map, and the sidebar of Uber pickups. The chart’s series comes from Series.bars, and the map’s points from the frame, with points_of.

Batman

batman.py draws the Batman logo on a chart.

uv run python -m examples.batman   # qt; or --backend web, or textual

On Qt:

The Batman logo on Qt

On Textual:

The Batman logo on Textual

On the web:

The Batman logo on the web

It shows:

  • series colors and fills: a yellow oval and the edges of the bat in black, each series in the color of the logo, whatever the theme;

  • clicks on a chart: clicked emits the point, and the view says whether it is on the bat. Textual draws the logo too, but a terminal has no pointer to click it with.

Web hello

webhello.py is a small form on the web backend only.

uv run python -m examples.webhello

The web hello form on the web

It serves http://127.0.0.1:8000. It shows:

  • an application built as a WebApplication subclass, without run;

  • a form with a text input, a float input, a radio group, and a combobox, with validation on the name and the age;

  • one keystroke that updates the status bar, the log of the row, and a summary label at once.

Textual demo

textual_demo.py is a small form in a terminal.

uv run python -m examples.textual_demo

On Qt:

The Textual demo on Qt

On Textual:

The Textual demo on Textual

On the web:

The Textual demo on the web

It shows a form with a text input, a float input, and a radio group. A change of shape shows a message in the status bar. It starts on Textual: run(..., default_backend=RendererType.TEXTUAL).